<?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=Xaneu</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=Xaneu"/>
	<link rel="alternate" type="text/html" href="http://wiki.fhem.de/wiki/Spezial:Beitr%C3%A4ge/Xaneu"/>
	<updated>2026-04-11T02:17:51Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Hue&amp;diff=39389</id>
		<title>Hue</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Hue&amp;diff=39389"/>
		<updated>2024-07-30T19:23:16Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* HUE-Device */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;float:right&amp;quot;&amp;gt;{{Infobox Modul&lt;br /&gt;
|Name=HUEBridge&lt;br /&gt;
|ModPurpose=Anbindung Bridge des Philips Hue Lighting System&lt;br /&gt;
|ModType=d&lt;br /&gt;
&amp;lt;!-- |ModCategory= (noch?) nicht verwendet --&amp;gt;&lt;br /&gt;
|ModCmdRef=HUEBridge&lt;br /&gt;
|ModForumArea=Zigbee&lt;br /&gt;
|ModTechName=30_HUEBridge.pm&lt;br /&gt;
|ModOwner=Andre ([http://forum.fhem.de/index.php?action=profile;u=430 Forum] / [[Benutzer Diskussion:justme|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|Name=HUEDevice&lt;br /&gt;
|ModPurpose=Ansteuerung Geräte des Philips Hue Lighting System über HUEBridge&lt;br /&gt;
|ModType=d&lt;br /&gt;
&amp;lt;!-- |ModCategory= (noch?) nicht verwendet --&amp;gt;&lt;br /&gt;
|ModCmdRef=HUEDevice&lt;br /&gt;
|ModForumArea=Zigbee&lt;br /&gt;
|ModTechName=31_HUEDevice.pm&lt;br /&gt;
|ModOwner=Andre ([http://forum.fhem.de/index.php?action=profile;u=430 Forum] / [[Benutzer Diskussion:justme|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== HUE-Bridge ==&lt;br /&gt;
=== Einrichtung in FHEM ===&lt;br /&gt;
Die Einrichtung ist wirklich einfach. Mit&lt;br /&gt;
:&amp;lt;code&amp;gt;define Wiesollesheißen HUEBridge 192.168.0.123&amp;lt;/code&amp;gt;&lt;br /&gt;
wird die Bridge eingebunden. (Die IP-Adresse gegen die der HUE Bridge ersetzen oder den DNS Namen.) Dann einfach auf den runden Knopf in der Mitte der Bridge drücken und sie wird von FHEM erkannt. Die drei Lampen des Starterkits werden automatisch erkannt und sind ansteuerbar -&amp;gt; fertig!&lt;br /&gt;
&lt;br /&gt;
WICHTIG: danach in FHEM einmal die Konfiguration speichern damit der Pairing-Key gesichert wird. Sonst muss beim nächsten FHEM-Neustart das Pairing erneut durchgeführt werden.&lt;br /&gt;
&lt;br /&gt;
Falls die Hue Bridge resetet wurde bleibt der Status auf &amp;quot;paired&amp;quot; und geht nicht mehr auf connected. Um das pairing erneut durchzuführen, muss das Attribut &amp;quot;key&amp;quot; gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
=== Nonblocking ===&lt;br /&gt;
Wenn man möchte, dass die Versuche, die HUEBridge zu kontaktieren, FHEM nicht blockieren, sollte man &lt;br /&gt;
:&amp;lt;code&amp;gt;attr &amp;lt;HUEBridge_Name&amp;gt; httpUtils 1&amp;lt;/code&amp;gt;&lt;br /&gt;
setzen.&lt;br /&gt;
&lt;br /&gt;
== HUE-Device ==&lt;br /&gt;
Als Gerät können alle Hue und LightLink kompatiblen Modelle verwendet werden, die sich an der Bridge anlernen lassen. Dies sind unter anderem:&lt;br /&gt;
*HueBulbs (E27, GU10, Lux, White, ...)&lt;br /&gt;
*Hue Beyond und Phoenix&lt;br /&gt;
*Friends of Hue LightStrips und LivingColors Bloom&lt;br /&gt;
*LivingColors ab gen2&lt;br /&gt;
*LivingColors Bloom, Iris und Aura&lt;br /&gt;
*LivingWhites Energiesparlampen&lt;br /&gt;
*LivingWhites Leuchtenadapter&lt;br /&gt;
*LivingWhites Bulbs&lt;br /&gt;
*[[HUE_Dimmer_Switch|Hue Tap und Hue Dimmer]] (mit Einschränkungen)&lt;br /&gt;
*dresden elektronik Vorschaltgeräte&lt;br /&gt;
*OSRAM LIGHTIFY Lampen (an der Hue Bridge angelernt)&lt;br /&gt;
*Müller Licht tint&lt;br /&gt;
*Paulmann Plug &amp;amp; Shine  (an der Hue Bridge angelernt)&lt;br /&gt;
*...&lt;br /&gt;
&lt;br /&gt;
Diese sind jeweils über eine Bridge (HueBridge) steuerbar. Die LivingColors und LivingWhites Geräte sind vorher mit Hilfe einer LivingColors oder LivingWhites Fernbedienung an der Bridge anzulernen.&lt;br /&gt;
&lt;br /&gt;
Es werden auch alle HUE Sensoren (Taster, Bewegungsmelder) unterstützt. Diese werden aber nicht per [[autocreate]] angelegt, sondern müssen manuell definiert werden. Hier ist auf ein passendes Polling-Intervall zu achten (siehe: [[HUE_Dimmer_Switch|HUE Dimmer Switch]]). &lt;br /&gt;
&lt;br /&gt;
Sensoren (und Aktoren) lassen sich Konfigurieren (parameter Einstellen) und eigene Set- und Get- Kommandos im definieren.&lt;br /&gt;
&lt;br /&gt;
=== Mögliche andere Gateways ===&lt;br /&gt;
HUEDevice Client-Devices können (mit leicht unterschiedlichem Funktionsumfang) auch mit den folgenden Gateways anderer Hersteller und dem zugehörigen Bridge-Device verwendet werden:&lt;br /&gt;
*[[Hue#RaspBee_.26_ConBee|RaspBee &amp;amp; ConBee mit deCONZ]] von Dresden Elektronik&lt;br /&gt;
** inklusive Push-API Erweiterung und Szenen &lt;br /&gt;
*[[TRÅDFRI| TRÅDFRI bzw. IKEA Home smart]] &lt;br /&gt;
** inklusive Rollos&lt;br /&gt;
*[https://github.com/bwssytems/ha-bridge HA-Bridge]&lt;br /&gt;
** inklusive aller [https://github.com/dresden-elektronik/deconz-rest-plugin/wiki/Supported-Devices unterstützten Geräte] (Lampen, Sensoren, Thermostate, Rollos, ...)&lt;br /&gt;
** inklusive Update des HA-Bridge internen Gerätestatus per &amp;lt;code&amp;gt;habridgeupdate&amp;lt;/code&amp;gt; Kommando&lt;br /&gt;
*[[ZigBee#Lightify_von_Osram|OSRAM LIGHTIFY Gateway]]&lt;br /&gt;
&lt;br /&gt;
Das HUEBridge Modul erkennt, wenn ein Leuchtmittel zwischen einer Hue und einer deCONZ Bridge (oder umgekehrt) wechselt und verschiebt das zugehörige HUEDevice in FHEM jeweils zum richtigen Bridge-Device. D.h. wenn z.B. zum Firmwareupdate die Bridge gewechselt wird, ist auf FHEM Seite nichts weiter zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Grundlagen - Farbmodelle ===&lt;br /&gt;
Ein HueDevice kann per set-Befehl über unterschiedliche Farbmodelle gesteuert werden. In der folgenden Tabelle ist dargestellt, welche Werte-Kombinationen sinnvoll sind:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Farbmodell !! Bestandteile !! Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| xyY || x- und y-Koordinate im Farbraum, Y ist die Helligkeit || &amp;lt;code&amp;gt; set bulb1 xy 0.4595,0.4105 : bri 220 &amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| hue,sat,bri || Farbwert, Sättigung und Helligkeit || &amp;lt;code&amp;gt; set bulb1 hue 14922 : sat 144 : bri 220 &amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| ct || Farbwert über Farbtemperatur || &amp;lt;code&amp;gt; set bulb1 color 2600 &amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| rgb || Farbbestandteile rot, grün und blau || &amp;lt;code&amp;gt; set bulb1 rgb FFC698 &amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Zur Regelung der Helligkeit sind die Befehle &#039;&#039;bri&#039;&#039; und &#039;&#039;pct&#039;&#039; gleichwertig. &#039;&#039;bri&#039;&#039; hat den Bereich 0..254, &#039;&#039;pct&#039;&#039; 0..100 .&lt;br /&gt;
&lt;br /&gt;
Das Modul lässt die Mischung von Angaben aus unterschiedlichen Farbmodellen technisch zu, jedoch sind diese nicht immer sinnvoll.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;HA-Bridge:&#039;&#039;&#039; In der HA-Bridge können virtuelle Devices definiert werden, welche in FHEM als &#039;&#039;Dimmable light&#039;&#039; eingebunden und verwendet werden können.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zu den bereits beschriebenen set-Befehlen kann der Zustand der HA-Bridge-Devices mit Hilfe von &#039;&#039;habridgeupdate&#039;&#039; in Kombination mit &#039;&#039;on&#039;&#039;, &#039;&#039;off&#039;&#039;, &#039;&#039;pct&#039;&#039; und &#039;&#039;bri&#039;&#039; aktualisiert werden, ohne dass die HA-Bridge einen Schaltbefehl versendet. Beispiel: &amp;lt;code&amp;gt;set bulb1 habridgeupdate : on : pct 50&amp;lt;/code&amp;gt; Details siehe: [https://github.com/bwssytems/ha-bridge#update-bridge-internal-light-state].&lt;br /&gt;
&lt;br /&gt;
=== Darstellung im Webfrontend ===&lt;br /&gt;
Wenn man die SVG Icons verwendet, ist es sinnvoll, das Attribut color-icons zu setzen. Mit &lt;br /&gt;
:&amp;lt;code&amp;gt;attr HUEDevice1 color-icons 2&amp;lt;/code&amp;gt; &lt;br /&gt;
werden z.B. die Farben und der Dimmzustand der Lampe als Icon dargestellt. Damit das ganze funktioniert, muss noch &lt;br /&gt;
:&amp;lt;code&amp;gt;attr WEB iconPath fhemSVG:openautomation:default&amp;lt;/code&amp;gt; &lt;br /&gt;
gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== Spezielle Konfigurationsmöglichkeiten ===&lt;br /&gt;
Zur Syntax der nachfolgenden Attribute (für widgets) siehe {{Link2Forum|Topic=119298|LinkText=&lt;br /&gt;
Patchvorschlag im Forum}}&lt;br /&gt;
==== setList ==== &lt;br /&gt;
Ermöglicht einen indirekten Zugriff auf den Befehl &#039;&#039;setsensor&#039;&#039; der HUEBridge.&lt;br /&gt;
&lt;br /&gt;
Beispiele &lt;br /&gt;
* {{Link2Forum|Topic=118788|LinkText=	&lt;br /&gt;
Eurotonics Spirit bzw. MOES Thermostat}} &lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,11020.msg1192888.html#msg1192888 HueLabs Scene aus FHEM über die HUEBridge ein- und ausschalten] &lt;br /&gt;
&lt;br /&gt;
==== configList ====&lt;br /&gt;
Ermöglicht einen indirekten Zugriff auf den Befehl &#039;&#039;configsensor&#039;&#039; der HUEBridge.&lt;br /&gt;
&lt;br /&gt;
Beispiele &lt;br /&gt;
* {{Link2Forum|Topic=115102|Message=1093876|LinkText=Aqara motion sensor - duration}} &lt;br /&gt;
* {{Link2Forum|Topic=111887|Message=1064164|LinkText=Aqara vibration sensor - sensitivity}}&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130869.msg1250786.html#msg1250786 Hue Bewegungsmelder - aktivieren, empfindlichkeit und mehr]&lt;br /&gt;
&lt;br /&gt;
==== weiter Konfigurationsmöglichkeiten ====&lt;br /&gt;
Device spezifische Kommandos hinzufügen - [https://forum.fhem.de/index.php/topic,11020.msg1193583.html#msg1193583 effect] , [https://forum.fhem.de/index.php/topic,125676.msg1208041.html#msg1208041 startup] &lt;br /&gt;
&lt;br /&gt;
== RaspBee &amp;amp; ConBee ==&lt;br /&gt;
Das HUEBridge Modul unterstützt auch die ZigBee Gateway Module RaspBee und ConBee von Dresden Elektronik über die zugehörige deCONZ Software und die Wireless Light Control WebApp und die Phoscon WebApp (kommt zusammen mit deConz). Die hierzu erhältlichen Funk-Vorschaltgeräte sind noch nicht getestet, sollten aber auch funktionieren.&lt;br /&gt;
&lt;br /&gt;
Im diesem {{Link2Forum|Topic=80985|LinkText=Forenbeitrag}} wird über Details der HUE Module diskutiert, die das deCONZ PushAPI über Websockets unterstützen (die entsprechenden Modulversionen sind mittlerweile regulär verfügbar). Sensoren müssen hier nicht mehr gepollt werden.&lt;br /&gt;
&lt;br /&gt;
Mittlerweile funktioniert die Einbindung der RaspBee und ConBee Module auf einem sehr einfachen Weg. Dieser ist in diesem {{Link2Forum|Topic=95288|LinkText=Forenbeitrag}} zusammengefasst. Zusätzliche Plugins sind nicht mehr nötig.&lt;br /&gt;
&lt;br /&gt;
=== Installation von deCONZ in einer Proxmox-VM ===&lt;br /&gt;
Folgende Schritte sind notwendig, um unter Proxmox zu installieren:&lt;br /&gt;
&lt;br /&gt;
* Installation einer Ubuntu oder Debian VM:&lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /var/lib/vz/template/iso/&lt;br /&gt;
wget http://releases.ubuntu.com/18.04/ubuntu-18.04.2-desktop-amd64.iso&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
:oder&lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /var/lib/vz/template/iso/&lt;br /&gt;
wget https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-9.8.0-amd64-xfce-CD-1.iso&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Weiterreichen des USB Devices in die VM:&lt;br /&gt;
: Auflistung der verfügbaren USB Geräte:&lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
root@node1:~# lsusb&lt;br /&gt;
Bus 002 Device 004: ID 0403:6015 Future Technology Devices International, Ltd Bridge(I2C/SPI/UART/FIFO)&lt;br /&gt;
Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub&lt;br /&gt;
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub&lt;br /&gt;
Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub&lt;br /&gt;
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
:Der Conbee meldet sich als &amp;quot;Future Technology Devices International, Ltd Bridge(I2C/SPI/UART/FIFO)&amp;quot;, hier ist die ID wichtig (0403:6015).&lt;br /&gt;
:Anschließend kann das USB Gerät an die VM weitergeleitet werden. Der Wert 804 ist durch die ID der VM zu ersetzen. &lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
qm set 804 -usb0 host=0403:6015&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Installation von deCONZ: &lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt-get update &amp;amp;&amp;amp; apt-get upgrade -y&lt;br /&gt;
wget http://www.dresden-elektronik.de/deconz/ubuntu/beta/deconz-2.05.60-qt5.deb&lt;br /&gt;
sudo dpkg -i deconz-2.05.60-qt5.deb &lt;br /&gt;
sudo apt install -f&lt;br /&gt;
sudo systemctl enable deconz&lt;br /&gt;
reboot now&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installation von deCONZ in einem Proxmox LXC-Container ===&lt;br /&gt;
&lt;br /&gt;
[[Conbee/deCONZ im Proxmox LXC-Container (Tutorial)]]&lt;br /&gt;
&lt;br /&gt;
=== Installation von deCONZ unter Docker ===&lt;br /&gt;
https://hub.docker.com/r/marthoc/deconz/&lt;br /&gt;
&lt;br /&gt;
=== Installation von deCONZ auf einem RaspberryPI ===&lt;br /&gt;
Für den ConBee2 [https://phoscon.de/en/conbee2/install#raspbian kann der guten Installation von Phoscon gefolgt werden]. Entweder ihr installiert deCONZ direkt (wie hier beschrieben) oder über einen Docker Container. Der Docker Container hat ein paar Einschränkungen bzgl. Firmware Updates.&lt;br /&gt;
&lt;br /&gt;
Der ausführende Benutzer muss dialout Rechte haben um auf /dev/tty* zugreifen zu dürfen:&lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo gpasswd -a pi dialout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Im Standard wird deCONZ mit dem pi-Benutzer (user id 1000) ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Das deCONZ Repository bei APT hinzufügen (Vorteil davon ist dass später ganz normal mit sudo apt update/upgrade deCONZ aktualisieren könnt):&lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
wget -O - http://phoscon.de/apt/deconz.pub.key | \&lt;br /&gt;
           sudo apt-key add -;&lt;br /&gt;
sudo sh -c &amp;quot;echo &#039;deb http://phoscon.de/apt/deconz \&lt;br /&gt;
            $(lsb_release -cs) main&#039; &amp;gt; \&lt;br /&gt;
            /etc/apt/sources.list.d/deconz.list&amp;quot;;&lt;br /&gt;
sudo apt update&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit der Einführung des Raspberry Pi 3 sind noch weitere Einstellungen notwendig. Diese sind hier: [[Raspberry Pi 3: GPIO-Port Module und Bluetooth|Raspberry Pi 3: GPIO-Port Module und Bluetooth – FHEMWiki]] ausführlich beschrieben.&lt;br /&gt;
&lt;br /&gt;
deCONZ installieren:&lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt install deconz&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wenn ihr euren RaspberryPI mit UI betreibt, kann deCONZ über &#039;&#039;Menu &amp;gt; Programming &amp;gt; deCONZ&#039;&#039; aufgerufen werden. Es gibt aber auch den Service-Modus, der ohne X11 funktionert. Hierfür die Datei &#039;&#039;/lib/systemd/system/deconz.service&#039;&#039; anpassen (ich habe z.B. den Port des Webservers geändert) und den Service wie folgt aktivieren:&lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl enable deconz.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== HUE auf der Fritzbox ==&lt;br /&gt;
Da auf der FB standardmäßig kein JSON installiert ist, muss dies nachinstalliert werden:  Man lädt das JSON-Paket http://search.cpan.org/CPAN/authors/id/M/MA/MAKAMAKA/JSON-2.53.tar.gz, packt es aus und kopiert den Inhalt vom &amp;lt;b&amp;gt;lib-Verzeichnis&amp;lt;/b&amp;gt; nach \fhem\lib\perl5\site_perl\5.12.2&lt;br /&gt;
&lt;br /&gt;
== HUE auf der Synology Diskstation ==&lt;br /&gt;
Da auf der DS standardmäßig kein JSON installiert ist, muss dies nachinstalliert werden, die Anleitung dazu {{Link2Forum|Topic=19093|Message=224641|LinkText=in diesem Forenbeitrag}}.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:ZigBee]]&lt;br /&gt;
[[Kategorie:Lichteffektgeräte]]&lt;br /&gt;
[[Kategorie:IP Components]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Hue&amp;diff=39388</id>
		<title>Hue</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Hue&amp;diff=39388"/>
		<updated>2024-07-30T19:21:40Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* HUE-Device Paulmann Plug &amp;amp; Shine ergänzt */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;float:right&amp;quot;&amp;gt;{{Infobox Modul&lt;br /&gt;
|Name=HUEBridge&lt;br /&gt;
|ModPurpose=Anbindung Bridge des Philips Hue Lighting System&lt;br /&gt;
|ModType=d&lt;br /&gt;
&amp;lt;!-- |ModCategory= (noch?) nicht verwendet --&amp;gt;&lt;br /&gt;
|ModCmdRef=HUEBridge&lt;br /&gt;
|ModForumArea=Zigbee&lt;br /&gt;
|ModTechName=30_HUEBridge.pm&lt;br /&gt;
|ModOwner=Andre ([http://forum.fhem.de/index.php?action=profile;u=430 Forum] / [[Benutzer Diskussion:justme|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
{{Infobox Modul&lt;br /&gt;
|Name=HUEDevice&lt;br /&gt;
|ModPurpose=Ansteuerung Geräte des Philips Hue Lighting System über HUEBridge&lt;br /&gt;
|ModType=d&lt;br /&gt;
&amp;lt;!-- |ModCategory= (noch?) nicht verwendet --&amp;gt;&lt;br /&gt;
|ModCmdRef=HUEDevice&lt;br /&gt;
|ModForumArea=Zigbee&lt;br /&gt;
|ModTechName=31_HUEDevice.pm&lt;br /&gt;
|ModOwner=Andre ([http://forum.fhem.de/index.php?action=profile;u=430 Forum] / [[Benutzer Diskussion:justme|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== HUE-Bridge ==&lt;br /&gt;
=== Einrichtung in FHEM ===&lt;br /&gt;
Die Einrichtung ist wirklich einfach. Mit&lt;br /&gt;
:&amp;lt;code&amp;gt;define Wiesollesheißen HUEBridge 192.168.0.123&amp;lt;/code&amp;gt;&lt;br /&gt;
wird die Bridge eingebunden. (Die IP-Adresse gegen die der HUE Bridge ersetzen oder den DNS Namen.) Dann einfach auf den runden Knopf in der Mitte der Bridge drücken und sie wird von FHEM erkannt. Die drei Lampen des Starterkits werden automatisch erkannt und sind ansteuerbar -&amp;gt; fertig!&lt;br /&gt;
&lt;br /&gt;
WICHTIG: danach in FHEM einmal die Konfiguration speichern damit der Pairing-Key gesichert wird. Sonst muss beim nächsten FHEM-Neustart das Pairing erneut durchgeführt werden.&lt;br /&gt;
&lt;br /&gt;
Falls die Hue Bridge resetet wurde bleibt der Status auf &amp;quot;paired&amp;quot; und geht nicht mehr auf connected. Um das pairing erneut durchzuführen, muss das Attribut &amp;quot;key&amp;quot; gelöscht werden.&lt;br /&gt;
&lt;br /&gt;
=== Nonblocking ===&lt;br /&gt;
Wenn man möchte, dass die Versuche, die HUEBridge zu kontaktieren, FHEM nicht blockieren, sollte man &lt;br /&gt;
:&amp;lt;code&amp;gt;attr &amp;lt;HUEBridge_Name&amp;gt; httpUtils 1&amp;lt;/code&amp;gt;&lt;br /&gt;
setzen.&lt;br /&gt;
&lt;br /&gt;
== HUE-Device ==&lt;br /&gt;
Als Gerät können alle Hue und LightLink kompatiblen Modelle verwendet werden, die sich an der Bridge anlernen lassen. Dies sind unter anderem:&lt;br /&gt;
*HueBulbs (E27, GU10, Lux, White, ...)&lt;br /&gt;
*Hue Beyond und Phoenix&lt;br /&gt;
*Friends of Hue LightStrips und LivingColors Bloom&lt;br /&gt;
*LivingColors ab gen2&lt;br /&gt;
*LivingColors Bloom, Iris und Aura&lt;br /&gt;
*LivingWhites Energiesparlampen&lt;br /&gt;
*LivingWhites Leuchtenadapter&lt;br /&gt;
*LivingWhites Bulbs&lt;br /&gt;
*[[HUE_Dimmer_Switch|Hue Tap und Hue Dimmer]] (mit Einschränkungen)&lt;br /&gt;
*dresden elektronik Vorschaltgeräte&lt;br /&gt;
*OSRAM LIGHTIFY Lampen (an der Hue Bridge angelernt)&lt;br /&gt;
*Müller Licht tint&lt;br /&gt;
*Paulmann Plug &amp;amp; Shine&lt;br /&gt;
*...&lt;br /&gt;
&lt;br /&gt;
Diese sind jeweils über eine Bridge (HueBridge) steuerbar. Die LivingColors und LivingWhites Geräte sind vorher mit Hilfe einer LivingColors oder LivingWhites Fernbedienung an der Bridge anzulernen.&lt;br /&gt;
&lt;br /&gt;
Es werden auch alle HUE Sensoren (Taster, Bewegungsmelder) unterstützt. Diese werden aber nicht per [[autocreate]] angelegt, sondern müssen manuell definiert werden. Hier ist auf ein passendes Polling-Intervall zu achten (siehe: [[HUE_Dimmer_Switch|HUE Dimmer Switch]]). &lt;br /&gt;
&lt;br /&gt;
Sensoren (und Aktoren) lassen sich Konfigurieren (parameter Einstellen) und eigene Set- und Get- Kommandos im definieren.&lt;br /&gt;
&lt;br /&gt;
=== Mögliche andere Gateways ===&lt;br /&gt;
HUEDevice Client-Devices können (mit leicht unterschiedlichem Funktionsumfang) auch mit den folgenden Gateways anderer Hersteller und dem zugehörigen Bridge-Device verwendet werden:&lt;br /&gt;
*[[Hue#RaspBee_.26_ConBee|RaspBee &amp;amp; ConBee mit deCONZ]] von Dresden Elektronik&lt;br /&gt;
** inklusive Push-API Erweiterung und Szenen &lt;br /&gt;
*[[TRÅDFRI| TRÅDFRI bzw. IKEA Home smart]] &lt;br /&gt;
** inklusive Rollos&lt;br /&gt;
*[https://github.com/bwssytems/ha-bridge HA-Bridge]&lt;br /&gt;
** inklusive aller [https://github.com/dresden-elektronik/deconz-rest-plugin/wiki/Supported-Devices unterstützten Geräte] (Lampen, Sensoren, Thermostate, Rollos, ...)&lt;br /&gt;
** inklusive Update des HA-Bridge internen Gerätestatus per &amp;lt;code&amp;gt;habridgeupdate&amp;lt;/code&amp;gt; Kommando&lt;br /&gt;
*[[ZigBee#Lightify_von_Osram|OSRAM LIGHTIFY Gateway]]&lt;br /&gt;
&lt;br /&gt;
Das HUEBridge Modul erkennt, wenn ein Leuchtmittel zwischen einer Hue und einer deCONZ Bridge (oder umgekehrt) wechselt und verschiebt das zugehörige HUEDevice in FHEM jeweils zum richtigen Bridge-Device. D.h. wenn z.B. zum Firmwareupdate die Bridge gewechselt wird, ist auf FHEM Seite nichts weiter zu tun.&lt;br /&gt;
&lt;br /&gt;
=== Grundlagen - Farbmodelle ===&lt;br /&gt;
Ein HueDevice kann per set-Befehl über unterschiedliche Farbmodelle gesteuert werden. In der folgenden Tabelle ist dargestellt, welche Werte-Kombinationen sinnvoll sind:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Farbmodell !! Bestandteile !! Beispiel&lt;br /&gt;
|-&lt;br /&gt;
| xyY || x- und y-Koordinate im Farbraum, Y ist die Helligkeit || &amp;lt;code&amp;gt; set bulb1 xy 0.4595,0.4105 : bri 220 &amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| hue,sat,bri || Farbwert, Sättigung und Helligkeit || &amp;lt;code&amp;gt; set bulb1 hue 14922 : sat 144 : bri 220 &amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| ct || Farbwert über Farbtemperatur || &amp;lt;code&amp;gt; set bulb1 color 2600 &amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| rgb || Farbbestandteile rot, grün und blau || &amp;lt;code&amp;gt; set bulb1 rgb FFC698 &amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&#039;&#039;&#039;Hinweis:&#039;&#039;&#039; Zur Regelung der Helligkeit sind die Befehle &#039;&#039;bri&#039;&#039; und &#039;&#039;pct&#039;&#039; gleichwertig. &#039;&#039;bri&#039;&#039; hat den Bereich 0..254, &#039;&#039;pct&#039;&#039; 0..100 .&lt;br /&gt;
&lt;br /&gt;
Das Modul lässt die Mischung von Angaben aus unterschiedlichen Farbmodellen technisch zu, jedoch sind diese nicht immer sinnvoll.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;HA-Bridge:&#039;&#039;&#039; In der HA-Bridge können virtuelle Devices definiert werden, welche in FHEM als &#039;&#039;Dimmable light&#039;&#039; eingebunden und verwendet werden können.&lt;br /&gt;
&lt;br /&gt;
Zusätzlich zu den bereits beschriebenen set-Befehlen kann der Zustand der HA-Bridge-Devices mit Hilfe von &#039;&#039;habridgeupdate&#039;&#039; in Kombination mit &#039;&#039;on&#039;&#039;, &#039;&#039;off&#039;&#039;, &#039;&#039;pct&#039;&#039; und &#039;&#039;bri&#039;&#039; aktualisiert werden, ohne dass die HA-Bridge einen Schaltbefehl versendet. Beispiel: &amp;lt;code&amp;gt;set bulb1 habridgeupdate : on : pct 50&amp;lt;/code&amp;gt; Details siehe: [https://github.com/bwssytems/ha-bridge#update-bridge-internal-light-state].&lt;br /&gt;
&lt;br /&gt;
=== Darstellung im Webfrontend ===&lt;br /&gt;
Wenn man die SVG Icons verwendet, ist es sinnvoll, das Attribut color-icons zu setzen. Mit &lt;br /&gt;
:&amp;lt;code&amp;gt;attr HUEDevice1 color-icons 2&amp;lt;/code&amp;gt; &lt;br /&gt;
werden z.B. die Farben und der Dimmzustand der Lampe als Icon dargestellt. Damit das ganze funktioniert, muss noch &lt;br /&gt;
:&amp;lt;code&amp;gt;attr WEB iconPath fhemSVG:openautomation:default&amp;lt;/code&amp;gt; &lt;br /&gt;
gesetzt werden.&lt;br /&gt;
&lt;br /&gt;
=== Spezielle Konfigurationsmöglichkeiten ===&lt;br /&gt;
Zur Syntax der nachfolgenden Attribute (für widgets) siehe {{Link2Forum|Topic=119298|LinkText=&lt;br /&gt;
Patchvorschlag im Forum}}&lt;br /&gt;
==== setList ==== &lt;br /&gt;
Ermöglicht einen indirekten Zugriff auf den Befehl &#039;&#039;setsensor&#039;&#039; der HUEBridge.&lt;br /&gt;
&lt;br /&gt;
Beispiele &lt;br /&gt;
* {{Link2Forum|Topic=118788|LinkText=	&lt;br /&gt;
Eurotonics Spirit bzw. MOES Thermostat}} &lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,11020.msg1192888.html#msg1192888 HueLabs Scene aus FHEM über die HUEBridge ein- und ausschalten] &lt;br /&gt;
&lt;br /&gt;
==== configList ====&lt;br /&gt;
Ermöglicht einen indirekten Zugriff auf den Befehl &#039;&#039;configsensor&#039;&#039; der HUEBridge.&lt;br /&gt;
&lt;br /&gt;
Beispiele &lt;br /&gt;
* {{Link2Forum|Topic=115102|Message=1093876|LinkText=Aqara motion sensor - duration}} &lt;br /&gt;
* {{Link2Forum|Topic=111887|Message=1064164|LinkText=Aqara vibration sensor - sensitivity}}&lt;br /&gt;
* [https://forum.fhem.de/index.php/topic,130869.msg1250786.html#msg1250786 Hue Bewegungsmelder - aktivieren, empfindlichkeit und mehr]&lt;br /&gt;
&lt;br /&gt;
==== weiter Konfigurationsmöglichkeiten ====&lt;br /&gt;
Device spezifische Kommandos hinzufügen - [https://forum.fhem.de/index.php/topic,11020.msg1193583.html#msg1193583 effect] , [https://forum.fhem.de/index.php/topic,125676.msg1208041.html#msg1208041 startup] &lt;br /&gt;
&lt;br /&gt;
== RaspBee &amp;amp; ConBee ==&lt;br /&gt;
Das HUEBridge Modul unterstützt auch die ZigBee Gateway Module RaspBee und ConBee von Dresden Elektronik über die zugehörige deCONZ Software und die Wireless Light Control WebApp und die Phoscon WebApp (kommt zusammen mit deConz). Die hierzu erhältlichen Funk-Vorschaltgeräte sind noch nicht getestet, sollten aber auch funktionieren.&lt;br /&gt;
&lt;br /&gt;
Im diesem {{Link2Forum|Topic=80985|LinkText=Forenbeitrag}} wird über Details der HUE Module diskutiert, die das deCONZ PushAPI über Websockets unterstützen (die entsprechenden Modulversionen sind mittlerweile regulär verfügbar). Sensoren müssen hier nicht mehr gepollt werden.&lt;br /&gt;
&lt;br /&gt;
Mittlerweile funktioniert die Einbindung der RaspBee und ConBee Module auf einem sehr einfachen Weg. Dieser ist in diesem {{Link2Forum|Topic=95288|LinkText=Forenbeitrag}} zusammengefasst. Zusätzliche Plugins sind nicht mehr nötig.&lt;br /&gt;
&lt;br /&gt;
=== Installation von deCONZ in einer Proxmox-VM ===&lt;br /&gt;
Folgende Schritte sind notwendig, um unter Proxmox zu installieren:&lt;br /&gt;
&lt;br /&gt;
* Installation einer Ubuntu oder Debian VM:&lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /var/lib/vz/template/iso/&lt;br /&gt;
wget http://releases.ubuntu.com/18.04/ubuntu-18.04.2-desktop-amd64.iso&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
:oder&lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /var/lib/vz/template/iso/&lt;br /&gt;
wget https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-9.8.0-amd64-xfce-CD-1.iso&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Weiterreichen des USB Devices in die VM:&lt;br /&gt;
: Auflistung der verfügbaren USB Geräte:&lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
root@node1:~# lsusb&lt;br /&gt;
Bus 002 Device 004: ID 0403:6015 Future Technology Devices International, Ltd Bridge(I2C/SPI/UART/FIFO)&lt;br /&gt;
Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub&lt;br /&gt;
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub&lt;br /&gt;
Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub&lt;br /&gt;
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
:Der Conbee meldet sich als &amp;quot;Future Technology Devices International, Ltd Bridge(I2C/SPI/UART/FIFO)&amp;quot;, hier ist die ID wichtig (0403:6015).&lt;br /&gt;
:Anschließend kann das USB Gerät an die VM weitergeleitet werden. Der Wert 804 ist durch die ID der VM zu ersetzen. &lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
qm set 804 -usb0 host=0403:6015&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Installation von deCONZ: &lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt-get update &amp;amp;&amp;amp; apt-get upgrade -y&lt;br /&gt;
wget http://www.dresden-elektronik.de/deconz/ubuntu/beta/deconz-2.05.60-qt5.deb&lt;br /&gt;
sudo dpkg -i deconz-2.05.60-qt5.deb &lt;br /&gt;
sudo apt install -f&lt;br /&gt;
sudo systemctl enable deconz&lt;br /&gt;
reboot now&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Installation von deCONZ in einem Proxmox LXC-Container ===&lt;br /&gt;
&lt;br /&gt;
[[Conbee/deCONZ im Proxmox LXC-Container (Tutorial)]]&lt;br /&gt;
&lt;br /&gt;
=== Installation von deCONZ unter Docker ===&lt;br /&gt;
https://hub.docker.com/r/marthoc/deconz/&lt;br /&gt;
&lt;br /&gt;
=== Installation von deCONZ auf einem RaspberryPI ===&lt;br /&gt;
Für den ConBee2 [https://phoscon.de/en/conbee2/install#raspbian kann der guten Installation von Phoscon gefolgt werden]. Entweder ihr installiert deCONZ direkt (wie hier beschrieben) oder über einen Docker Container. Der Docker Container hat ein paar Einschränkungen bzgl. Firmware Updates.&lt;br /&gt;
&lt;br /&gt;
Der ausführende Benutzer muss dialout Rechte haben um auf /dev/tty* zugreifen zu dürfen:&lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo gpasswd -a pi dialout&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Im Standard wird deCONZ mit dem pi-Benutzer (user id 1000) ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Das deCONZ Repository bei APT hinzufügen (Vorteil davon ist dass später ganz normal mit sudo apt update/upgrade deCONZ aktualisieren könnt):&lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
wget -O - http://phoscon.de/apt/deconz.pub.key | \&lt;br /&gt;
           sudo apt-key add -;&lt;br /&gt;
sudo sh -c &amp;quot;echo &#039;deb http://phoscon.de/apt/deconz \&lt;br /&gt;
            $(lsb_release -cs) main&#039; &amp;gt; \&lt;br /&gt;
            /etc/apt/sources.list.d/deconz.list&amp;quot;;&lt;br /&gt;
sudo apt update&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit der Einführung des Raspberry Pi 3 sind noch weitere Einstellungen notwendig. Diese sind hier: [[Raspberry Pi 3: GPIO-Port Module und Bluetooth|Raspberry Pi 3: GPIO-Port Module und Bluetooth – FHEMWiki]] ausführlich beschrieben.&lt;br /&gt;
&lt;br /&gt;
deCONZ installieren:&lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo apt install deconz&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Wenn ihr euren RaspberryPI mit UI betreibt, kann deCONZ über &#039;&#039;Menu &amp;gt; Programming &amp;gt; deCONZ&#039;&#039; aufgerufen werden. Es gibt aber auch den Service-Modus, der ohne X11 funktionert. Hierfür die Datei &#039;&#039;/lib/systemd/system/deconz.service&#039;&#039; anpassen (ich habe z.B. den Port des Webservers geändert) und den Service wie folgt aktivieren:&lt;br /&gt;
:&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl enable deconz.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== HUE auf der Fritzbox ==&lt;br /&gt;
Da auf der FB standardmäßig kein JSON installiert ist, muss dies nachinstalliert werden:  Man lädt das JSON-Paket http://search.cpan.org/CPAN/authors/id/M/MA/MAKAMAKA/JSON-2.53.tar.gz, packt es aus und kopiert den Inhalt vom &amp;lt;b&amp;gt;lib-Verzeichnis&amp;lt;/b&amp;gt; nach \fhem\lib\perl5\site_perl\5.12.2&lt;br /&gt;
&lt;br /&gt;
== HUE auf der Synology Diskstation ==&lt;br /&gt;
Da auf der DS standardmäßig kein JSON installiert ist, muss dies nachinstalliert werden, die Anleitung dazu {{Link2Forum|Topic=19093|Message=224641|LinkText=in diesem Forenbeitrag}}.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:ZigBee]]&lt;br /&gt;
[[Kategorie:Lichteffektgeräte]]&lt;br /&gt;
[[Kategorie:IP Components]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Modul_Shelly&amp;diff=37898</id>
		<title>Modul Shelly</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Modul_Shelly&amp;diff=37898"/>
		<updated>2022-12-30T08:02:24Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* MQTT */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Modul&lt;br /&gt;
|ModPurpose=Das Modul 36_Shelly.pm stellt ein Interface zur Bedienung von Shelly Devices zur Verfügung&lt;br /&gt;
|ModType=d&lt;br /&gt;
&amp;lt;!-- |ModCategory= (noch?) nicht verwendet --&amp;gt;&lt;br /&gt;
|ModCmdRef=Shelly&lt;br /&gt;
|ModForumArea=Sonstige Systeme&lt;br /&gt;
|ModFTopic=118446&lt;br /&gt;
|ModTechName=36_Shelly.pm&lt;br /&gt;
|ModOwner=Prof. Dr. Peter A. Henning&lt;br /&gt;
}}&lt;br /&gt;
Auf dieser Seite werden die Aktoren des bulgarischen Herstellers Allterco Robotics beschrieben ((Markenname Shelly) sowie deren Ansteuerung mit FHEM und aufgetretene Probleme. &lt;br /&gt;
Für Supportanfragen bitte &#039;&#039;{{Link2Forum|Topic=118446.0|LinkText=diesen Forenthread}}&#039;&#039; verwenden.&lt;br /&gt;
{{Baustelle}}&lt;br /&gt;
&#039;&#039;&#039;Achtung: Diese Seite ist teilweise veraltet, insbesondere unterstützt das Modul weitere Aktoren. Bitte Commandref lesen - diese Seite ist in Überarbeitung&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Es handelt sich um IP-basierte Schalt- und Dimmaktoren, die auf verschiedene Weise angesteuert werden können &lt;br /&gt;
*über die Web-Oberfläche des eingebauten Mikro-Webservers,&lt;br /&gt;
*über eine proprietäre App des Herstellers (Achtung, Cloud!),&lt;br /&gt;
*über das hier beschriebene FHEM-Modul 36_Shelly.pm&lt;br /&gt;
*über MQTT&lt;br /&gt;
Ein Teil der Aktoren verfügt über eine eingebaute Leistungsmessung.&lt;br /&gt;
&lt;br /&gt;
== Geräteübersicht ==&lt;br /&gt;
{| class=&amp;quot;wikitable mw-datatable&amp;quot;&lt;br /&gt;
! style=&amp;quot;width:50px&amp;quot; |Modell&lt;br /&gt;
! style=&amp;quot;width:50px&amp;quot; |Typ&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; |Schaltkanäle&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; |Dimmkanäle&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; |Messkanäle&lt;br /&gt;
! style=&amp;quot;width:650px&amp;quot; |Bemerkungen&lt;br /&gt;
|-&lt;br /&gt;
|Shelly1&lt;br /&gt;
|Schalter&lt;br /&gt;
|1&lt;br /&gt;
| &lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Shelly1PM&lt;br /&gt;
|Schalter mit Leistungsmessung&lt;br /&gt;
|1&lt;br /&gt;
|&lt;br /&gt;
|1 &lt;br /&gt;
|-&lt;br /&gt;
|ShellyPlug, ShellyPlugS&lt;br /&gt;
|Schalter mit Leistungsmessung&lt;br /&gt;
|1&lt;br /&gt;
|&lt;br /&gt;
|1 &lt;br /&gt;
|-&lt;br /&gt;
|ShellyEM&lt;br /&gt;
|Leistungsmessung&lt;br /&gt;
|1&lt;br /&gt;
|&lt;br /&gt;
|2 &lt;br /&gt;
|-&lt;br /&gt;
|Shelly2&lt;br /&gt;
|Schalter/Rollladenaktor &lt;br /&gt;
|2/1&lt;br /&gt;
|&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|Shelly2.5&lt;br /&gt;
|Schalter/Rollladenaktor &lt;br /&gt;
|2/1&lt;br /&gt;
|&lt;br /&gt;
|2&lt;br /&gt;
|-&lt;br /&gt;
|Shelly4Pro&lt;br /&gt;
|Schalter &lt;br /&gt;
|4&lt;br /&gt;
|&lt;br /&gt;
|4&lt;br /&gt;
|-&lt;br /&gt;
|ShellyRGBW&lt;br /&gt;
|Dimmer &lt;br /&gt;
|&lt;br /&gt;
|4&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|ShellyDimmer&lt;br /&gt;
|Dimmer &lt;br /&gt;
|&lt;br /&gt;
|1&lt;br /&gt;
|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Einbindung in FHEM ==&lt;br /&gt;
*Schließen Sie den Aktor nach Vorschrift an&lt;br /&gt;
*Suchen Sie mit einem WLAN-fähigen Gerät (Laptop oder Smartphone) nach dem internen Access Point, der durch den Aktor erzeugt wird. Typischerweise hat dieser eine SSID ähnlich wie&lt;br /&gt;
 shelly1-..., shellyswitch-..., shelly4pro-..., &lt;br /&gt;
*Verbinden Sie Ihr Gerät mit diesem Access Point. Typischerweise bekommt Ihr Gerät dabei die IP-Adresse 192.168.33.2 zugewiesen. &lt;br /&gt;
*Im Browser dieses Gerätes einfach die IP-Adresse 192.168.33.1 aufrufen - das ist der Shelly selbst, in dieser Web-Oberfläche kann man alles konfigurieren. &lt;br /&gt;
**Internen Access Point abschalten&lt;br /&gt;
**Shelly ins häusliche WLAN anmelden. Mit fester IP-Adresse &amp;lt;shelly-ip&amp;gt; natürlich...&lt;br /&gt;
**Testen: Ihr Gerät wieder mit dem häuslichen WLAN verbinden, und im Browser die Adresse &amp;lt;shelly-ip&amp;gt; aufrufen&lt;br /&gt;
*In FHEM definieren&lt;br /&gt;
 define myShelly Shelly &amp;lt;shelly-ip&amp;gt;&lt;br /&gt;
*Auf der Detailseite des Devices muss unbedingt noch das Attribut &amp;lt;code&amp;gt;model&amp;lt;/code&amp;gt; gesetzt werden:&lt;br /&gt;
 attr myShelly model shellyrgbw|shellydimmer|shelly2.5|generic|shelly2|shellyem|shelly4|shellyplug|shelly1|shellybulb|shelly1pm|shellyuni&lt;br /&gt;
Falls es sich um einen Shelly2 oder 2.5 handelt, muss ferner das Attribut &amp;lt;code&amp;gt;mode&amp;lt;/code&amp;gt; auf &amp;quot;roller&amp;quot; oder &amp;quot;relay&amp;quot; gesetzt werden. Mit diesem Modul können alle Daten übertragen und (prinzipiell) alle Konfigurationsänderungen durchgeführt werden, außerdem ist es auf einfachste Weise zu installieren. Das Modul pollt im per Attribut &amp;lt;code&amp;gt;interval&amp;lt;/code&amp;gt; einstellbaren Abstand zyklisch den Aktor auf Statusänderungen (Wert 0 =&amp;gt; kein Polling). Damit der Aktor im Stande ist, irgendwelche Zustandsänderungen &#039;&#039;von sich aus&#039;&#039; an FHEM zu melden, müssen diese als REST-Befehle (also URL-Aufrufe, für Nicht-Experten) in der Konfigurationsoberfläche des Shelly-Aktors eingetragen werden. Siehe CommandRef.&lt;br /&gt;
&lt;br /&gt;
Zum Betrieb ist ferner noch zu bemerken, dass das Modul zwar meldet, ob ein Firmware-Update nötig ist - ausgelöst werden muss dieses aber über die Web-Oberfläche des Shelly selber.&lt;br /&gt;
&lt;br /&gt;
=== MQTT ===&lt;br /&gt;
MQTT (Message Queue Telemetry Transport) ist ein nachrichtenbasiertes Protokoll, bei dem Geräte (Devices) nicht direkt miteinander, sondern mit einem zentralen MQTT-Server (in alter Nomenklatur &#039;&#039;Broker&#039;&#039; genannt) kommunizieren. Eine kurze Einführung in MQTT findet man auf der Seite [[MQTT Einführung]]. Mit entsprechend gesetzten Attributen lassen sich die Shelly-Aktoren auch steuern ([[MQTT2-Module - Praxisbeispiele#Shelly|Praxisbeispiele zu den MQTT2-Modulen]]), für Anfänger ist das allerdings nicht unbedingt zu empfehlen.&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Modul_Shelly&amp;diff=37897</id>
		<title>Modul Shelly</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Modul_Shelly&amp;diff=37897"/>
		<updated>2022-12-30T07:54:12Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* MQTT */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Modul&lt;br /&gt;
|ModPurpose=Das Modul 36_Shelly.pm stellt ein Interface zur Bedienung von Shelly Devices zur Verfügung&lt;br /&gt;
|ModType=d&lt;br /&gt;
&amp;lt;!-- |ModCategory= (noch?) nicht verwendet --&amp;gt;&lt;br /&gt;
|ModCmdRef=Shelly&lt;br /&gt;
|ModForumArea=Sonstige Systeme&lt;br /&gt;
|ModFTopic=118446&lt;br /&gt;
|ModTechName=36_Shelly.pm&lt;br /&gt;
|ModOwner=Prof. Dr. Peter A. Henning&lt;br /&gt;
}}&lt;br /&gt;
Auf dieser Seite werden die Aktoren des bulgarischen Herstellers Allterco Robotics beschrieben ((Markenname Shelly) sowie deren Ansteuerung mit FHEM und aufgetretene Probleme. &lt;br /&gt;
Für Supportanfragen bitte &#039;&#039;{{Link2Forum|Topic=118446.0|LinkText=diesen Forenthread}}&#039;&#039; verwenden.&lt;br /&gt;
{{Baustelle}}&lt;br /&gt;
&#039;&#039;&#039;Achtung: Diese Seite ist teilweise veraltet, insbesondere unterstützt das Modul weitere Aktoren. Bitte Commandref lesen - diese Seite ist in Überarbeitung&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Es handelt sich um IP-basierte Schalt- und Dimmaktoren, die auf verschiedene Weise angesteuert werden können &lt;br /&gt;
*über die Web-Oberfläche des eingebauten Mikro-Webservers,&lt;br /&gt;
*über eine proprietäre App des Herstellers (Achtung, Cloud!),&lt;br /&gt;
*über das hier beschriebene FHEM-Modul 36_Shelly.pm&lt;br /&gt;
*über MQTT&lt;br /&gt;
Ein Teil der Aktoren verfügt über eine eingebaute Leistungsmessung.&lt;br /&gt;
&lt;br /&gt;
== Geräteübersicht ==&lt;br /&gt;
{| class=&amp;quot;wikitable mw-datatable&amp;quot;&lt;br /&gt;
! style=&amp;quot;width:50px&amp;quot; |Modell&lt;br /&gt;
! style=&amp;quot;width:50px&amp;quot; |Typ&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; |Schaltkanäle&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; |Dimmkanäle&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; |Messkanäle&lt;br /&gt;
! style=&amp;quot;width:650px&amp;quot; |Bemerkungen&lt;br /&gt;
|-&lt;br /&gt;
|Shelly1&lt;br /&gt;
|Schalter&lt;br /&gt;
|1&lt;br /&gt;
| &lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Shelly1PM&lt;br /&gt;
|Schalter mit Leistungsmessung&lt;br /&gt;
|1&lt;br /&gt;
|&lt;br /&gt;
|1 &lt;br /&gt;
|-&lt;br /&gt;
|ShellyPlug, ShellyPlugS&lt;br /&gt;
|Schalter mit Leistungsmessung&lt;br /&gt;
|1&lt;br /&gt;
|&lt;br /&gt;
|1 &lt;br /&gt;
|-&lt;br /&gt;
|ShellyEM&lt;br /&gt;
|Leistungsmessung&lt;br /&gt;
|1&lt;br /&gt;
|&lt;br /&gt;
|2 &lt;br /&gt;
|-&lt;br /&gt;
|Shelly2&lt;br /&gt;
|Schalter/Rollladenaktor &lt;br /&gt;
|2/1&lt;br /&gt;
|&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|Shelly2.5&lt;br /&gt;
|Schalter/Rollladenaktor &lt;br /&gt;
|2/1&lt;br /&gt;
|&lt;br /&gt;
|2&lt;br /&gt;
|-&lt;br /&gt;
|Shelly4Pro&lt;br /&gt;
|Schalter &lt;br /&gt;
|4&lt;br /&gt;
|&lt;br /&gt;
|4&lt;br /&gt;
|-&lt;br /&gt;
|ShellyRGBW&lt;br /&gt;
|Dimmer &lt;br /&gt;
|&lt;br /&gt;
|4&lt;br /&gt;
|1&lt;br /&gt;
|-&lt;br /&gt;
|ShellyDimmer&lt;br /&gt;
|Dimmer &lt;br /&gt;
|&lt;br /&gt;
|1&lt;br /&gt;
|1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Einbindung in FHEM ==&lt;br /&gt;
*Schließen Sie den Aktor nach Vorschrift an&lt;br /&gt;
*Suchen Sie mit einem WLAN-fähigen Gerät (Laptop oder Smartphone) nach dem internen Access Point, der durch den Aktor erzeugt wird. Typischerweise hat dieser eine SSID ähnlich wie&lt;br /&gt;
 shelly1-..., shellyswitch-..., shelly4pro-..., &lt;br /&gt;
*Verbinden Sie Ihr Gerät mit diesem Access Point. Typischerweise bekommt Ihr Gerät dabei die IP-Adresse 192.168.33.2 zugewiesen. &lt;br /&gt;
*Im Browser dieses Gerätes einfach die IP-Adresse 192.168.33.1 aufrufen - das ist der Shelly selbst, in dieser Web-Oberfläche kann man alles konfigurieren. &lt;br /&gt;
**Internen Access Point abschalten&lt;br /&gt;
**Shelly ins häusliche WLAN anmelden. Mit fester IP-Adresse &amp;lt;shelly-ip&amp;gt; natürlich...&lt;br /&gt;
**Testen: Ihr Gerät wieder mit dem häuslichen WLAN verbinden, und im Browser die Adresse &amp;lt;shelly-ip&amp;gt; aufrufen&lt;br /&gt;
*In FHEM definieren&lt;br /&gt;
 define myShelly Shelly &amp;lt;shelly-ip&amp;gt;&lt;br /&gt;
*Auf der Detailseite des Devices muss unbedingt noch das Attribut &amp;lt;code&amp;gt;model&amp;lt;/code&amp;gt; gesetzt werden:&lt;br /&gt;
 attr myShelly model shellyrgbw|shellydimmer|shelly2.5|generic|shelly2|shellyem|shelly4|shellyplug|shelly1|shellybulb|shelly1pm|shellyuni&lt;br /&gt;
Falls es sich um einen Shelly2 oder 2.5 handelt, muss ferner das Attribut &amp;lt;code&amp;gt;mode&amp;lt;/code&amp;gt; auf &amp;quot;roller&amp;quot; oder &amp;quot;relay&amp;quot; gesetzt werden. Mit diesem Modul können alle Daten übertragen und (prinzipiell) alle Konfigurationsänderungen durchgeführt werden, außerdem ist es auf einfachste Weise zu installieren. Das Modul pollt im per Attribut &amp;lt;code&amp;gt;interval&amp;lt;/code&amp;gt; einstellbaren Abstand zyklisch den Aktor auf Statusänderungen (Wert 0 =&amp;gt; kein Polling). Damit der Aktor im Stande ist, irgendwelche Zustandsänderungen &#039;&#039;von sich aus&#039;&#039; an FHEM zu melden, müssen diese als REST-Befehle (also URL-Aufrufe, für Nicht-Experten) in der Konfigurationsoberfläche des Shelly-Aktors eingetragen werden. Siehe CommandRef.&lt;br /&gt;
&lt;br /&gt;
Zum Betrieb ist ferner noch zu bemerken, dass das Modul zwar meldet, ob ein Firmware-Update nötig ist - ausgelöst werden muss dieses aber über die Web-Oberfläche des Shelly selber.&lt;br /&gt;
&lt;br /&gt;
=== MQTT ===&lt;br /&gt;
MQTT (Message Queue Telemetry Transport) ist ein nachrichtenbasiertes Protokoll, bei dem Geräte (Devices) nicht direkt miteinander, sondern mit einem zentralen MQTT-Server (in alter Nomenklatur &#039;&#039;Broker&#039;&#039; genannt) kommunizieren. Eine kurze Einführung in MQTT findet man auf der Seite [[MQTT Einführung]]. Mit entsprechend gesetzten Attributen lassen sich die Shelly-Aktoren auch steuern ([[MQTT2-Module - Praxisbeispiele|Praxisbeispiele zu den MQTT2-Modulen]]), für Anfänger ist das allerdings nicht unbedingt zu empfehlen.&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=33312</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=33312"/>
		<updated>2020-05-31T14:38:16Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Weiterer Vorteil ergänzt */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben (https://www.reichelt.de/raspberry-pi-usv-rpi-usv-p169883.html).&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung, Akku-Spannung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
* Der Raspberry Pi kann vom FHEM-Server aus komplett (spannungslos) abgeschaltet werden.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss das I2C-Interface Modul „RPII2C“ zuvor definiert werden (siehe Commandref).&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;pl&amp;quot;&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $s_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung=&amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	if ($usv_meldung ne &amp;quot;&amp;quot;) {&lt;br /&gt;
		fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+) |/is;&lt;br /&gt;
$s_pi = $1;&lt;br /&gt;
if ($s_pi != 0xFF)&lt;br /&gt;
	{&lt;br /&gt;
	$status=$s_pi &amp;amp; 0x3F;&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&amp;lt;br&amp;gt;&lt;br /&gt;
Der Wert des Statusregister wird hier als Dezimalzahl dargestellt und muss zur weiteren Verarbeitung ggf. noch binär ausdekodiert werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== PIUSV+ und Raspberry Pi 4 ==&lt;br /&gt;
Obwohl die PIUSV+ nur 2 A liefern kann, ist der Betrieb mit einem Raspberry Pi 4 durchaus möglich, sofern auf dem Raspberry hauptsächlich der FHEM-Server und keine sonstige hochperformante Software installiert ist.&lt;br /&gt;
Bei einer FHEM-Beispielinstallation (Raspian Buster, FHEM 6.0) mit USB-SSD-Platte (32GB), 3x USB/232-Konverter, einem Homematic-Sender/Empfängermodul (HM-MOD-PRI-PCB) und Nutzung der 1-Wire-, I²C- und 2xGPIO-Schnittstellen am 40pol. Pfostenverbinder beträgt der 5V-Versorgungsstrom ca. 0,9A (entspricht 4,5W).&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;br /&gt;
[[Kategorie:Raspberry Pi]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=DevelopmentModuleIntro&amp;diff=33086</id>
		<title>DevelopmentModuleIntro</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=DevelopmentModuleIntro&amp;diff=33086"/>
		<updated>2020-04-22T07:07:15Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: Änderung wieder rückgängig gemacht, da das Verhalten unter IOS (IPAD) sich nicht geändert hat.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Hinweis|Dieser Text ist in Arbeit und muss noch an einigen Stellen ergänzt werden. }}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Um neue Geräte, Dienste, o.ä. in FHEM verfügbar zu machen, kann man ein eigenes Modul in Perl schreiben. Ein Modul wird in FHEM automatisch geladen, wenn ein entsprechendes Device in FHEM definiert wird. Das Modul ermöglicht eine spezifische Kommunikation mit einem physikalischen Gerät, stellt Ergebnisse (&amp;quot;Readings&amp;quot;) und Events innerhalb von FHEM zur Verfügung und erlaubt es, das Gerät mit &amp;quot;Set&amp;quot;-/&amp;quot;Get&amp;quot;-Befehlen zu beeinflussen. Dieser Artikel soll den Einstieg in die Entwicklung eigener Module erleichtern.&lt;br /&gt;
&lt;br /&gt;
Mit dem FHEM-Befehl &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt; werden Devices in FHEM basierend auf einem Modul definiert. Dieser Befehl sorgt dafür, dass ein neues Modul bei Bedarf geladen und initialisiert wird. Ein gutes Beispiel ist hierbei die zentrale Konfigurationsdatei &amp;quot;fhem.cfg&amp;quot; in der sämtliche Devices in Form von &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Statements gespeichert sind.&lt;br /&gt;
&lt;br /&gt;
Damit das funktioniert müssen der Name des Moduls und der Name der [[#X_Initialize|Initialisierungsfunktion]]  identisch sein. Das folgende Beispiel soll dies verdeutlichen:&lt;br /&gt;
&lt;br /&gt;
Ein Jeelink USB-Stick könnte beispielsweise mit dem Befehl &amp;lt;code&amp;gt;define JeeLink1 &#039;&#039;JeeLink&#039;&#039; /dev/ttyUSB0@57600&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
In fhem.pl wird der &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl verarbeitet und geprüft, ob ein Modul mit dem Namen &amp;quot;JeeLink&amp;quot; schon geladen ist. Falls nicht, wird ein Modul mit Namen XY_JeeLink.pm im Modulverzeichnis (z.B. /opt/fhem/FHEM) gesucht und, falls vorhanden, anschließend geladen. &lt;br /&gt;
Danach wird die Funktion &amp;lt;code&amp;gt;&#039;&#039;JeeLink&#039;&#039;_Initialize()&amp;lt;/code&amp;gt; aufgerufen um das Modul in FHEM zu registrieren. Eine Moduldatei muss dazu eine Funktion &amp;lt;code&amp;gt;&#039;&#039;&amp;amp;lt;Modulname&amp;amp;gt;&#039;&#039;_Initialize()&amp;lt;/code&amp;gt; enthalten. Durch den Aufruf dieser Funktion wird FHEM mitgeteilt, welche Funktionalitäten dieses Modul unterstützt und durch welche Perl-Funktionen im Modul selbst diese ausimplementiert werden.&lt;br /&gt;
&lt;br /&gt;
In der Initialisierungsfunktion des Moduls werden die Namen aller weiteren Perl-Funktionen des Moduls, die von fhem.pl aus aufgerufen werden, bekannt gemacht. Dazu wird für jedes Modul ein eigener Hash (genauer &amp;quot;Modul-Hash&amp;quot;) mit entsprechenden Werten gefüllt, der in fhem.pl für jedes Modul entsprechend abgelegt wird. Dadurch weiß FHEM wie dieses Modul anzusprechen ist.&lt;br /&gt;
&lt;br /&gt;
== Grundlegender Aufbau eines Moduls ==&lt;br /&gt;
&lt;br /&gt;
=== Dateiname ===&lt;br /&gt;
&lt;br /&gt;
Ein FHEM-Modul wird als Perl-Modul mit der Dateiendung *.pm abgespeichert. Der Dateiname folgt dabei folgendem Schema:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;&#039;&#039;[&#039;&#039;&#039;Schlüsselnummer&#039;&#039;&#039;]&#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;_&amp;lt;/font&amp;gt;&#039;&#039;[&#039;&#039;&#039;Modulname&#039;&#039;&#039;]&#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;.pm&amp;lt;/font&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Schlüsselnummer&#039;&#039;&#039; - Eine zweistellige Zahl zwischen 00 - 99. Die Schlüsselnummer hat aktuell keine technische Relevanz mehr. In früheren FHEM-Versionen ist sie relevant für [[#Zweistufiges_Modell_f.C3.BCr_Module|zweistufige Module]] (Reihenfolge für [[DevelopmentModuleAPI#Dispatch|Dispatch()]] um logische Module zu prüfen). Die allgemeine Empfehlung ist hierbei eine Schlüsselnummer eines Moduls zu verwenden, welches eine ähnliche Funktionalität bietet. Die Schlüsselnummer 99 hat hierbei eine besondere Bedeutung, da alle Module mit dieser Schlüsselnummer beim Start von FHEM automatisch geladen werden, selbst, wenn sie in der Konfiguration nicht verwendet werden. Daher wird für myUtils 99 als Schlüsselnummer verwendet (99_myUtils.pm). Module mit der Schlüsselnummer 99 werden im SVN nicht akzeptiert (siehe [[SVN Nutzungsregeln]])&lt;br /&gt;
* &#039;&#039;&#039;Modulname&#039;&#039;&#039; - Der Name des Moduls wie er in FHEM bei dem Anlegen einer Gerätedefinition zu verwenden ist. Der Modulname sollte nur aus den folgenden möglichen Zeichen bestehen: Groß-/Kleinbuchstaben, Zahlen sowie Unterstrich (_)&lt;br /&gt;
&lt;br /&gt;
=== Inhaltlicher Aufbau ===&lt;br /&gt;
&lt;br /&gt;
Ein Modul ist inhaltlich in folgende Abschnitte unterteilt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
#  72_MYMODULE.pm &lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
package main;&lt;br /&gt;
&lt;br /&gt;
# Laden evtl. abhängiger Perl- bzw. FHEM-Hilfsmodule&lt;br /&gt;
use HttpUtils;&lt;br /&gt;
use [...]&lt;br /&gt;
&lt;br /&gt;
# FHEM Modulfunktionen&lt;br /&gt;
&lt;br /&gt;
sub MYMODULE_Initialize() {&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub MYMODULE_Define() {&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
# Eval-Rückgabewert für erfolgreiches&lt;br /&gt;
# Laden des Moduls&lt;br /&gt;
1;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Beginn der Commandref&lt;br /&gt;
&lt;br /&gt;
=pod&lt;br /&gt;
=item [helper|device|command]&lt;br /&gt;
=item summary Kurzbeschreibung in Englisch was MYMODULE steuert/unterstützt&lt;br /&gt;
=item summary_DE Kurzbeschreibung in Deutsch was MYMODULE steuert/unterstützt&lt;br /&gt;
&lt;br /&gt;
=begin html&lt;br /&gt;
 Englische Commandref in HTML&lt;br /&gt;
=end html&lt;br /&gt;
&lt;br /&gt;
=begin html_DE&lt;br /&gt;
 Deutsche Commandref in HTML&lt;br /&gt;
=end html&lt;br /&gt;
&lt;br /&gt;
# Ende der Commandref&lt;br /&gt;
=cut&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man kann hierbei von folgender Reihenfolge sprechen:&lt;br /&gt;
&lt;br /&gt;
# Perl-Code, welcher das Modul implementiert&lt;br /&gt;
# Die Zeile &amp;lt;code&amp;gt;1;&amp;lt;/code&amp;gt; nachdem der Perl-Code abgeschlossen ist. Dies dient FHEM der Erkennung, dass das Modul erfolgreich und vollständig geladen wurde. Sollte diese Zeile nicht enthalten sein, wird FHEM beim Laden des Moduls die Fehlermeldung &amp;lt;code&amp;gt;Error:Modul 72_MYMODULE deactivated&amp;lt;/code&amp;gt; in das Logfile schreiben.&lt;br /&gt;
# Commandref zur Dokumentation des Moduls. Diese Dokumentation soll dem User die möglichen Befehle/Attribute/Readings/Events vermitteln. Weitere Informationen und Hinweise findet man in den [[Guidelines zur Dokumentation]].&lt;br /&gt;
&lt;br /&gt;
== Der Hash einer Geräteinstanz ==&lt;br /&gt;
Eine Besonderheit in Perl sind [http://de.wikipedia.org/wiki/Assoziatives_Array#Perl assoziative Arrays], (nicht ganz richtig als &amp;quot;Hash&amp;quot; bezeichnet) in denen die Adressierung nicht über eine Zählvariable erfolgt, sondern über einen beliebigen String. Die internen Abläufe bei der Adressierung führen dazu, dass die Speicherung in und der Abruf aus Hashes relativ langsam ist.&lt;br /&gt;
&lt;br /&gt;
Der zentrale Speicherort für Informationen einer Geräteinstanz bei FHEM ist ein solcher Hash, der seinerseits in fhem.pl von einem globalen Hash referenziert wird. &lt;br /&gt;
&lt;br /&gt;
In fhem.pl werden alle Gerätedefinitionen in dem globalen Hash &amp;lt;code&amp;gt;%defs&amp;lt;/code&amp;gt; abgelegt. Der Inhalt von &amp;lt;code&amp;gt;$defs{&#039;&#039;&amp;amp;lt;Name&amp;amp;gt;&#039;&#039;}&amp;lt;/code&amp;gt; in fhem.pl verweist dabei auf den Hash der Geräteinstanz in Form einer Hashreferenz. Diesen Verweis (also nur die Adresse) bekommen die Funktionen eines Moduls übergeben (i.d.R. als &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; bezeichnet), welche direkt von fhem.pl aufgerufen werden. In dem Hash stehen beispielsweise die internen Werte des Geräts, die im Frontend als &amp;quot;Internals&amp;quot; angezeigt werden, sowie die Readings des Geräts. &lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
*&amp;lt;code&amp;gt;$hash-&amp;gt;{NAME}&amp;lt;/code&amp;gt; enthält den Namen der Geräteinstanz, &lt;br /&gt;
*&amp;lt;code&amp;gt;$hash-&amp;gt;{TYPE}&amp;lt;/code&amp;gt; enthält die Typbezeichnung des Geräts (Modulname)&lt;br /&gt;
&lt;br /&gt;
==Ausführung von Modulen==&lt;br /&gt;
FHEM arbeitet intern nicht parallel, sondern arbeitet alle Aufgaben seriell nacheinander kontinuierlich ab. Daher wäre es ungünstig, wenn Module Daten von einem physikalischen Gerät abfragen wollen und dabei innerhalb der selben Funktion auf die Antwort des Geräts warten. In dieser Zeit, in der FHEM auf die Antwort des Gerätes warten muss, wäre der Rest von FHEM blockiert. Da immer nur eine Aufgabe zur selben Zeit bearbeitet wird, müssen alle weiteren Aufgaben solange warten. Eine Datenkommunikation innerhalb eines Moduls sollte daher immer ohne Blockierung erfolgen. Dadurch kann FHEM die Wartezeit effizient für andere Aufgaben nutzen um bspw. anstehende Daten für andere Module zu verarbeiten. Es gibt in FHEM entsprechende Mechanismen, welche eine &amp;quot;Non-Blocking&amp;quot;-Kommunikation über verschiedene Wege (z.B. seriell, HTTP, TCP, ...) ermöglichen.&lt;br /&gt;
&lt;br /&gt;
Dafür werden in FHEM zwei zentrale Listen gepflegt, in der die Filedeskriptoren der geöffneten Kommunikatonsverbindungen gespeichert sind. Auf Linux- bzw. Unix-basierten Plattformen wird der select-Befehl des Betriebssystems verwendet um Filedeskriptoren auf lesbare Daten zu überprüfen. In FHEM gibt es dazu eine Liste (&amp;lt;code&amp;gt;%selectlist&amp;lt;/code&amp;gt;), in der die Filedeskriptoren sämtlicher Geräte (z.B. serielle Verbindung, TCP-Verbindung, etc.) gespeichert sind. &lt;br /&gt;
&lt;br /&gt;
In der zentralen Schleife (Main-Loop) von fhem.pl wird mit &amp;lt;code&amp;gt;select()&amp;lt;/code&amp;gt; überwacht, ob über eine der geöffneten Schnittstellen Daten zum Lesen anstehen. Wenn dies der Fall ist, dann wird die Lesefunktion ([[#X_Read|X_Read]]) des zuständigen Moduls aufgerufen, damit es die Daten entgegennimmt und verarbeitet. Anschließend wird die Schleife weiter ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Auf Windows-Systemen funktioniert dies anders. Hier können USB/Seriell-Geräte nicht per &amp;lt;code&amp;gt;select()&amp;lt;/code&amp;gt; überwacht werden. In FHEM unter Windows werden daher diese Schnittstellen kontinuierlich abgefragt ob Daten bereitstehen. Dafür müssen Module zusätzlich zur Lesefunktion eine Abfragefunktion ([[#X_Ready|X_Ready]]) implementieren, welche prüft, ob Daten zum Lesen anstehen. Auch auf Linux/Unix-Plattformen hat diese Funktion eine Aufgabe. Falls nämlich eine Schnittstelle ausfällt, beziehungsweise ein CUL oder USB-zu-Seriell Adapter ausgesteckt wird, dann wird über diese Funktion regelmäßig geprüft ob die Schnittstelle wieder verfügbar wird.&lt;br /&gt;
&lt;br /&gt;
Innerhalb der eigentlichen Lesefunktion (X_Read) werden dann die Daten vom zugehörigen Gerät gelesen, das nötige Protokoll implementiert um die Daten zu interpretieren und Werte in Readings geschrieben.&lt;br /&gt;
&lt;br /&gt;
Auch wenn von einem Anwender über einen Get-Befehl Daten aktiv von einem Gerät angefordert werden, sollte nicht blockierend gewartet werden. Eine asynchrone Ausgabe, sobald das Ergebnis vorliegt, ist über [[DevelopmentModuleAPI#asyncOutput|asyncOutput()]] möglich. Siehe {{Link2Forum|Topic=43771|Message=357870|LinkText=Beschreibung}} und {{Link2Forum|Topic=43771|Message=360935|LinkText=Beispiel}}. Weitere Anwendungsbeispiele finden sich im  {{Link2Forum|Topic=43052|Message=353477|LinkText=PLEX Modul}} und im überarbeiteten und nicht-blockierenden {{Link2Forum|Topic=42771|Message=348498|LinkText=SYSSTAT Modul}}.&lt;br /&gt;
&lt;br /&gt;
== Wichtige globale Variablen aus fhem.pl ==&lt;br /&gt;
&lt;br /&gt;
FHEM arbeitet mit einer Vielzahl an internen Variablen. Die nun folgenden aufgelisteten Variablen sind die wichtigsten, welche man im Rahmen der Modulprogrammierung kennen sollte:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Variable !! Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; || Dient der Erkennung für fhem.pl sowie den Modulen, ob FHEM den Initialisierungsvorgang abgeschlossen hat. Beim Starten von FHEM ist &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; gleich &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;. Erst, wenn das Einlesen der Konfiguration, sowie des State-Files (Readings) abgeschlossen ist, wird &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; auf &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; gesetzt.&lt;br /&gt;
Das gleiche Verfahren wird auch bei dem Befehl &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt; angewandt. Während &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt; ausgeführt wird (Konfiguration löschen, neu einlesen), ist &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; gleich &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dies ist insbesondere in der [[#X_Define|Define]]-Funktion eines Moduls relevant. Durch eine Prüfung auf &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; kann man erkennen, ob eine Definition von Hand (&amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; = 1) oder im Rahmen der Initialisierung (FHEM Start / Rereadcfg =&amp;gt; &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; = 0) erfolgte. Während der Initialisierung stehen bspw. die gesetzten Attribute der Definition noch nicht zur Verfügung und können daher nicht ausgewertet werden (siehe . &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt; || In &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt; werden sämtliche gesetzten Attribute aller Geräte gespeichert. Diese Datenstruktur wird generell durch den &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt;-Befehl verwaltet. Hierbei wird einem Gerätenamen eine Mehrzahl an Attributnamen mit einem Wert zugeordnet. Attribut-Inhalte können über die Funktion [[DevelopmentModuleAPI#AttrVal|AttrVal()]] ausgelesen werden.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%cmds&amp;lt;/code&amp;gt; || In &amp;lt;code&amp;gt;%cmds&amp;lt;/code&amp;gt; wird jedem in FHEM existierendem Befehl die entsprechende Funktion zugewiesen, welche diesen Befehl umsetzt. Module können durch das Eintragen eines Befehlsnamen samt Funktion in &amp;lt;code&amp;gt;%cmds&amp;lt;/code&amp;gt; über die [[#X_Initialize|Initialize]]-Funktion eines Moduls einen (oder mehrere) eigene Befehle in FHEM registrieren.&lt;br /&gt;
&lt;br /&gt;
Die Struktur ist dabei wiefolgt:&lt;br /&gt;
&lt;br /&gt;
  $cmds{&#039;&#039;&amp;amp;lt;Befehlsname&amp;amp;gt;&#039;&#039;} = {  Fn  =&amp;gt; &amp;quot;&#039;&#039;&amp;amp;lt;Funktionsname&amp;amp;gt;&#039;&#039;&amp;quot;,&lt;br /&gt;
                            Hlp =&amp;gt; &amp;quot;&#039;&#039;&amp;amp;lt;Aufrufsyntax&amp;amp;gt;&#039;&#039;&amp;quot;};&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%data&amp;lt;/code&amp;gt;|| Der eigentliche Zweck von &amp;lt;code&amp;gt;%data&amp;lt;/code&amp;gt; ist dem Nutzer eine Möglichkeit zum Speichern von temporären Daten im globalen Kontext zu ermöglichen. Einige Module verwenden &amp;lt;code&amp;gt;%data&amp;lt;/code&amp;gt; jedoch auch um modul- &amp;amp; geräteübergreifend Daten auszutauschen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%defs&amp;lt;/code&amp;gt;|| In &amp;lt;code&amp;gt;%defs&amp;lt;/code&amp;gt; werden sämtliche Gerätedefinitionen, bzw. die Hash-Referenzen auf diese, gespeichert. Hier ist jedem Gerätenamen eine Hash-Referenz zugeordnet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%modules&amp;lt;/code&amp;gt;|| In &amp;lt;code&amp;gt;%modules&amp;lt;/code&amp;gt; sind alle geladenen Module gelistet mit ihren entsprechenden Initialisierungsdaten (Funktionsnamen, Attribut-Listen, spezielle Einstellungen, ...). Hier wird für jeden Modulname der Modul-Hash aus der [[#X_Initialize|Initialize]]-Funktion gespeichert. &lt;br /&gt;
Desweiteren legen viele Module, welche nach dem [[DevelopmentModuleIntro#Zweistufiges_Modell_f.C3.BCr_Module|zweistufigen Modulkonzept]] hier eine Rückwärtszuordnung von Geräteadressen zu Geräte-Hash an.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt;|| In &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt; sind alle zu prüfenden Verbindungen mit ihrer entsprechendem Geräte-Hash gelistet. FHEM prüft alle hier gelisteten Geräte regelmäßig über eine Aufruf der entsprechenden [[#X_Ready|Ready]]-Funktion.&lt;br /&gt;
&lt;br /&gt;
Bei einer Nutzung von dem Hilfsmodul [[DevIo|DevIo.pm]] zum Aufbau einer Kommunikationsverbindung, kümmert sich DevIo selbständig um den entsprechenden Eintrag in &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%selectlist&amp;lt;/code&amp;gt;|| In &amp;lt;code&amp;gt;%selectlist&amp;lt;/code&amp;gt; sind alle geöffneten Verbindungen mit ihrer entsprechendem Geräte-Hash gelistet. FHEM prüft alle hier gelisteten Geräte, ob der geöffnete Filedeskriptor unter &amp;lt;code&amp;gt;$hash-&amp;gt;{FD}&amp;lt;/code&amp;gt; Daten zum Lesen bereitgestellt hat. Ist dass der Fall, wird die entsprechende [[#X_Read|Read]]-Funktion aufgerufen, um anstehende Daten durch das Modul zu verarbeiten.&lt;br /&gt;
Bei einer Nutzung von dem Hilfsmodul [[DevIo|DevIo.pm]] zum Aufbau einer Kommunikationsverbindung, kümmert sich DevIo selbständig um den entsprechenden Eintrag in &amp;lt;code&amp;gt;%selectlist&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Es gibt durchaus viele weitere globale Variablen, die jedoch für sehr spezielle Anwendungsfälle und z.T. nur einzelne Module gedacht sind und daher hier nicht aufgeführt werden.&lt;br /&gt;
&lt;br /&gt;
== Internals ==&lt;br /&gt;
Daten, die ein Modul im Geräte-Hash speichert nennt man Internals. Sie werden als Unterstruktur des Hashes der jeweiligen Geräteinstanz gespeichert, beispielswiese &amp;lt;code&amp;gt;$hash-&amp;gt;{NAME}&amp;lt;/code&amp;gt; für den Gerätenamen, welcher beim Define-Befehl übergeben wurde und als Internal gespeichert wird. Diese Daten spielen für FHEM eine sehr wichtige Rolle, da sämtliche gerätespezifischen Daten als Internal im Gerätehash gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Falls Werte wie z.B. ein Intervall nicht über den Define-Befehl gesetzt werden sollen und im Betrieb einfach änderbar sein sollten, ist eine alternative Möglichkeit die Speicherung in so genannten Attributen. Dann würde man den Define-Befehl so implementieren, dass er kein Intervall übergeben bekommt und statt dessen das Interval als Attribut über den Befehl &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt; gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Generell werden alle Werte, welche direkt in der ersten Ebene von &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; (Gerätehash) gespeichert werden auf der Detail-Seite einer Definition in der FHEMWEB Oberfläche angezeigt. Es gibt jedoch Ausnahmen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$hash-&amp;gt;{helper}{URL}&amp;lt;/code&amp;gt; - Alle Elemente, welche als Unterelement wieder einen Hash besitzen werden nicht in FHEMWEB dargestellt. Typischerweise speichern Module Daten unter &amp;lt;code&amp;gt;$hash-&amp;gt;{helper}&amp;lt;/code&amp;gt; interne Daten zwischen, die für den User nicht relevant sind, sondern nur der internen Verarbeitung dienen.&lt;br /&gt;
* &amp;lt;code&amp;gt;$hash-&amp;gt;{&#039;&#039;&#039;.&#039;&#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;ELEMENT&amp;lt;/font&amp;gt;}&amp;lt;/code&amp;gt; - Alle Knoten, welche mit einem Punkt beginnen werden in der FHEMWEB Oberfläche nicht angezeigt. Man kann diese Daten jedoch beim Aufruf des [[List|list-Kommandos]] einsehen.&lt;br /&gt;
&lt;br /&gt;
Es gibt bereits vorbelegte Internals welche in FHEM dazu dienen definitionsbezogene Informationen wie bspw. Namen und Readings zu speichern. Dies sind im besonderen:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;min-width: 13em;&amp;quot; | Internal !!  Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{NAME}&amp;lt;/code&amp;gt;  || Der Definitionsname, mit dem das Gerät angelegt wurde.  &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{READINGS}&amp;lt;/code&amp;gt;  || Enthält alle aktuell vorhandenen Readings. Daten unterhalb dieses Knotens sollte man nicht direkt manipulieren. Um Readings zu Erzeugen gibt es entsprechende [[DevelopmentModuleAPI#Readings_.2F_Events|Reading-Funktionen]].&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{NR}&amp;lt;/code&amp;gt;  || Die Positions-Nr. der Definition innerhalb der Konfiguration. Diese dient dazu die Konfiguration in der gleichen Reihenfolge zu speichern, wie die einzelnen Geräte angelegt wurden.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{TYPE}&amp;lt;/code&amp;gt;  || Der Modulname, mit welchem die Definition angelegt wurde.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{DEF}&amp;lt;/code&amp;gt;  || Sämtliche Argumente, welche beim &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl nach dem Modulnamen übergeben wurden.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{CFGFN}&amp;lt;/code&amp;gt;  || Der Dateiname der Konfigurationsdatei in der diese Definition enthalten ist (sofern nicht in fhem.cfg). Dieser Wert ist nur gefüllt, wenn man mit mehreren Konfigurationsdateien arbeitet, welche dann in fhem.cfg via include-Befehl eingebunden werden.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{NTFY_ORDER}&amp;lt;/code&amp;gt;  || Sofern das Modul Events via [[DevelopmentModuleIntro#X_Notify|Notify-Funktion]] verarbeitet enthält jede Definition eine Notify-Order als Zeichenkette bestehend aus dem Notify Order Prefix und dem Definitionsnamen. Details zur Funktionsweise gibt es in der Beschreibung zur [[DevelopmentModuleIntro#X_Notify|Notify-Funktion]] im Abschnitt &amp;quot;Reihenfolge für den Aufruf der Notify-Funktion beeinflussen&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{NOTIFYDEV}&amp;lt;/code&amp;gt;  || Sofern das Modul Events via NotifyFn verarbeitet kann man damit die Definitionen, von denen man Events erhalten will begrenzen. Details zur Funktionsweise gibt es in der Beschreibung zur [[DevelopmentModuleIntro#X_Notify|Notify-Funktion]] im Abschnitt &amp;quot;Begrenzung der Aufrufe auf bestimmte Geräte&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{IODev}&amp;lt;/code&amp;gt;  || Hier wird das zugeordnete IO-Gerät durch [[DevelopmentModuleAPI#AssignIoPort|AssignIoPort()]] gespeichert, welches für den Datentransport und -empfang dieses logischen Gerätes zuständig ist. Dieser Wert existiert nur bei Modulen die nach dem [[DevelopmentModuleIntro#Zweistufiges_Modell_f.C3.BCr_Module|zweistufigen Modulkonzept]] arbeiten. &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{CHANGED}&amp;lt;/code&amp;gt;  || Hier werden alle Events kurzzeitig gesammelt, welche für die Eventverarbeitung anstehen. Insbesondere die [[DevelopmentModuleAPI#Readings_.2F_Events|Reading-Funktionen]] speichern hier alle Events zwischen um sie nach Abschluss via [[DevelopmentModuleAPI#DoTrigger|DoTrigger()]] zu verarbeiten. &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{FD}&amp;lt;/code&amp;gt;  || Wenn die Definition eine Netzwerkverbindung oder serielle Schnittstelle geöffnet hat (z.B. via [[DevIo]]), so wird der entsprechende File-Deskriptor in diesem Internal gespeichert. Damit kann FHEM alle geöffneten Filedeskriptoren der entsprechenden Definition zuordnen um bei ankommenden Daten die Definition via [[DevelopmentModuleIntro#X_Read|Read-Funktion]] damit zu versorgen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{EXCEPT_FD}&amp;lt;/code&amp;gt;  || Ähnlich wie &amp;lt;code&amp;gt;$hash-&amp;gt;{FD}&amp;lt;/code&amp;gt;. Sofern die Definition in &amp;lt;code&amp;gt;[[#Wichtige_globale_Variablen_aus_fhem.pl|%selectlist]]&amp;lt;/code&amp;gt; eingetragen ist und ein Fildeskriptor in diesem Internal gesetzt ist, wird bei einer auftretenden Exception bzw. Interrupt die [[DevelopmentModuleIntro#X_Except|Except]]-Funktion des entsprechenden Moduls aufgerufen um darauf zu reagieren.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Generell sollte man die meisten der hier genannten systemweiten Internals nicht modifizieren, da ansonsten die korrekte Funktionsweise von FHEM nicht mehr garantiert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Readings ==&lt;br /&gt;
Daten, welche von einem Gerät gelesen werden und in FHEM in einer für Menschen verständlichen Form zur Verfügung gestellt werden können, werden Readings genannt. Sie geben den Status des Gerätes wieder und erzeugen Events innerhalb von FHEM auf die andere Geräte reagieren können. Sie werden als Unterstruktur des Hashes der jeweiligen Geräteinstanz gespeichert, beispielsweise &lt;br /&gt;
*&amp;lt;code&amp;gt;$hash-&amp;gt;{READINGS}{temperature}{VAL}&amp;lt;/code&amp;gt; für die Temperatur eines Fühlers&lt;br /&gt;
*&amp;lt;code&amp;gt;$hash-&amp;gt;{READINGS}{temperature}{TIME}&amp;lt;/code&amp;gt; für den Zeitstempel der Messung&lt;br /&gt;
&lt;br /&gt;
Für den lesenden Zugriff auf Readings steht die Funktion &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#ReadingsVal|ReadingsVal()]]&amp;lt;/code&amp;gt; zur Verfügung. Ein direkter Zugriff auf die Datenstruktur sollte nicht vorgenommen werden.&lt;br /&gt;
&lt;br /&gt;
Readings werden im Statefile von FHEM automatisch auf der Festplatte zwischengespeichert, damit sie nach einem Neustart sofort wieder zur Verfügung stehen. Dadurch ist der letzte Status eines Gerätes vor einem Neustart nachvollziehbar.&lt;br /&gt;
&lt;br /&gt;
Readings, die mit einem Punkt im Namen beginnen, haben eine funktionale Besonderheit. Sie werden im FHEMWEB nicht angezeigt und können somit als &amp;quot;Permanentspeicher&amp;quot; für kleinere Daten innerhalb des Moduls genutzt werden. Um größere Datenmengen permanent zu speichern sollte man jedoch die Funktion &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#setKeyValue|setKeyValue()]]&amp;lt;/code&amp;gt; verwenden.&lt;br /&gt;
&lt;br /&gt;
Zum Setzen von Readings sollen &lt;br /&gt;
*bei Gruppen von Readings der Funktionsblock &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsBeginUpdate|readingsBeginUpdate()]]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsBulkUpdate|readingsBulkUpdate()]]&amp;lt;/code&amp;gt; (mehrfach wiederholt), &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsEndUpdate|readingsEndUpdate()]]&amp;lt;/code&amp;gt;&lt;br /&gt;
*bei einzelnen Updates die Funktion &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsSingleUpdate|readingsSingleUpdate()]]&amp;lt;/code&amp;gt; &lt;br /&gt;
aufgerufen werden. Dabei kann man auch angeben, ob dabei ein Event ausgelöst werden soll oder nicht. Events erzeugen, je nach Hardwareperformance, spürbare Last auf dem System (siehe [[DevelopmentModuleIntro#X_Notify|NotifyFn]]), das Ändern von Readings ohne dass dabei Events erzeugt werden jedoch nicht.&lt;br /&gt;
&lt;br /&gt;
Eine Sequenz zum Setzen von Readings könnte folgendermaßen aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
readingsBeginUpdate($hash);&lt;br /&gt;
readingsBulkUpdate($hash, $readingName1, $wert1 );&lt;br /&gt;
readingsBulkUpdate($hash, $readingName2, $wert2 );&lt;br /&gt;
readingsEndUpdate($hash, 1);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um Readings zu löschen, wird für die Modulprogrammierung die Funktion &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsDelete|readingsDelete()]]&amp;lt;/code&amp;gt; empfohlen. Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
readingsDelete($hash, $readingsname) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{Hinweis|&#039;&#039;&#039;Hintergrundinfo dazu aus dem Forum:&#039;&#039;&#039; {{Link2Forum|Topic=83069|Message=753066}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CommandDeleteReading()&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;deletereading&amp;lt;/code&amp;gt; ist eher fuer den Endbenutzer und seine userReadings gedacht, und macht bei den Modulen die unnoetige Schleife ueber [[DevelopmentModuleAPI#devspec2array|devspec2array()]]. Wenn der Modulautor beim Aufruf auch &amp;lt;code&amp;gt;$cl&amp;lt;/code&amp;gt; weitergibt, und der Anwender meint, dieses Geraet auf blacklist setzen zu muessen, dann kann das Modul sein eigenes Reading nicht entfernen, und das ist kontraproduktiv.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
FHEM verfügt über einen Event-Mechanismus um Änderungen verschiedenster Art an einzelne oder alle Definitionen mitzuteilen. Jedes Modul (und damit alle Definitionen dieses Moduls) können auf Events von FHEM selber (Definition &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt;) oder von anderen Definitionen reagieren und dadurch selber aktiv werden. Ein Event wird innerhalb von FHEM als Zeichenkette behandelt.&lt;br /&gt;
&lt;br /&gt;
Events sind grundsätzlich immer definitionsbezogen. Das bedeutet, dass ein Event immer in Verbindung mit einem Definitionsnamen erzeugt wird. Jede Definition, welche ein Event verarbeitet, erhält den Definitions-Hash (&amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;) der auslösenden Definition.&lt;br /&gt;
&lt;br /&gt;
Events werden typischerweise bei der Erstellung von Readings implizit für jedes einzelne Reading erzeugt. Es gibt jedoch auch Events die nichts mit Readings zu tun haben um anderweitige Änderungen bekannt zu geben.&lt;br /&gt;
&lt;br /&gt;
Eigene Events können in FHEM mit der Funktion [[DevelopmentModuleAPI#DoTrigger|DoTrigger()]] erzeugt werden. Um auf Events in einem Modul reagieren zu können, muss eine [[#X_Notify|Notify]]-Funktion implementiert sein. Sobald ein oder mehrere Events für eine Definition getriggert werden, prüft FHEM, welche Definitionen über Events der auslösenden Definition informiert werden möchten. Diese werden dann nacheinander in einer bestimmten Reihenfolge durch Aufruf der [[#X_Notify|Notify]]-Funktion über anstehende Events in Kenntnis gesetzt. Es obliegt dann dem jeweiligen Modul, wie es auf die Events reagiert.&lt;br /&gt;
&lt;br /&gt;
=== globale Events ===&lt;br /&gt;
&lt;br /&gt;
Als &amp;quot;globale Events&amp;quot; werden alle Events bezeichnet, die durch die Definition &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt; erzeugt werden. Es handelt sich hierbei um Events die Strukturänderungen in der Konfiguration, als auch systemweite Ereignisse zu FHEM selbst signalisieren.&lt;br /&gt;
&lt;br /&gt;
Hier eine kurze Zusammenfassung, welche Events durch &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt; getriggert werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Allgemeine Events:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event-Text !! Beschreibung.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;INITIALIZED&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Der Start von FHEM ist abgeschlossen. Sämtliche Definitionen und Attribute wurden aus der Konfiguration (fhem.cfg oder configDB) eingelesen, sowie sämtliche Readings sind aus dem State-File eingelesen und stehen nun voll umfänglich zur Verfügung.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;REREADCFG&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Die Konfiguration wurde erneut eingelesen. Dies bedeutet, es wurden alle Definitionen/Attribute/Readings aus FHEM entfernt und durch Einlesen der Konfiguration neu angelegt. (FHEM-Befehl: &amp;quot;rereadcfg&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;SAVE&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Die laufende Konfiguration soll gespeichert werden (in fhem.cfg oder configDB). Dieses Event wird &#039;&#039;&#039;VOR&#039;&#039;&#039; dem Speichern der Konfiguration getriggert. Sobald der Trigger verarbeitet wurde, beginnt das Speichern der Konfiguration. (FHEM-Befehl: &amp;quot;save&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;SHUTDOWN&amp;lt;/code&amp;gt;&#039;&#039;&#039; || FHEM wird sich beenden. (FHEM-Befehl: &amp;quot;shutdown&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt; DELAYEDSHUTDOWN &amp;lt;/code&amp;gt;&#039;&#039;&#039; || FHEM wird sich beenden. (FHEM-Befehl: &amp;quot;shutdown&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;UPDATE&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Es wurde ein Update erfolgreich installiert. (FHEM-Befehl: &amp;quot;update&amp;quot;)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Definitionsbezogene Events:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event-Text !! Beschreibung.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;DEFINED &#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Es wurde eine neue Definition mit Namen &amp;lt;code&amp;gt;&#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; angelegt. (FHEM-Befehl: &amp;quot;define&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;DELETED &#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Die Definition mit dem Namen &amp;lt;code&amp;gt;&#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; wurde gelöscht. (FHEM-Befehl: &amp;quot;delete&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;RENAMED &#039;&#039;&amp;lt;Alt&amp;gt;&#039;&#039; &#039;&#039;&amp;lt;Neu&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Die Definition mit dem Namen &amp;lt;code&amp;gt;&#039;&#039;&amp;lt;Alt&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; wurde in den Namen &amp;lt;code&amp;gt;&#039;&#039;&amp;lt;Neu&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; umbenannt. (FHEM-Befehl: &amp;quot;rename&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;MODIFIED &#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Die Definition mit dem Namen &amp;lt;code&amp;gt;&#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; wurde modifiziert. (FHEM-Befehl: &amp;quot;modify&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;UNDEFINED &#039;&#039;&amp;lt;Name&amp;gt; &amp;lt;Modul&amp;gt; &amp;lt;Define-Parameter&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Es wurde eine Nachricht von einem physikalischen Modul (siehe [[#Zweistufiges Modell für Module|zweistufiges Modulkonzept]]) erhalten, für die keine passende logische Definition in FHEM existiert. Details dazu, siehe dazu Abschnitt [[#Automatisches Anlegen von logischen Gerätedefinitionen (autocreate)|Automatisches Anlegen von logischen Gerätedefinitionen (autocreate)]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Begrenzung von Events ===&lt;br /&gt;
&lt;br /&gt;
Ein Modul, welches Events verarbeitet, kann die Eventverarbeitung auf bestimmte Definitionen begrenzen. Dadurch werden nur Events an das Modul gemeldet (via [[#X_Notify|X_Notify()]]), welche von einer oder mehreren bestimmten Definitionen getriggert wurden. Dadurch werden unnötige Events nicht an das Modul gemeldet und schont somit Ressourcen.&lt;br /&gt;
&lt;br /&gt;
Standardmäßig werden sämtliche Events ohne Begrenzung an ein Modul gemeldet, welches eine [[#X_Notify|Notify]]-Funktion implementiert hat und somit Events verarbeiten kann. Details zur Begrenzung von Events findet man in der Beschreibung zur Modulfunktion [[#X_Notify|X_Notify()]].&lt;br /&gt;
&lt;br /&gt;
=== Reihenfolge der Eventverarbeitung ===&lt;br /&gt;
&lt;br /&gt;
Ein getriggertes Event wird nacheinander gegen jede Definition geprüft, deren Modul eine [[#X_Notify|Notify]]-Funktion implementiert hat. Dies bedeutet, jede Definition wird nacheinander durch Aufruf der [[#X_Notify|Notify]]-Funktion mit dem Definitionshash der auslösenden Definition aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Unter bestimmten Umständen kann es erforderlich sein, in diese Reihenfolge einzugreifen. Beispielsweise wenn das eigene Modul und deren Definitionen das Event als letztes oder erstes verarbeiten müssen. Ein Beispiel bietet hierbei das Modul [[dewpoint]], welches Events vor allen anderen Modulen verarbeiten muss.&lt;br /&gt;
&lt;br /&gt;
Details, wie man die Reihenfolge der Eventverarbeitung steuern kann, findet man in der Beschreibung zur Modulfunktion [[#X_Notify|X_Notify()]].&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Damit der Nutzer das Verhalten einer einzelnen Gerätedefinition zur Laufzeit individuell anpassen kann, gibt es in FHEM für jede Definition sogenannte Attribute, welche mit dem Befehl &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt; gesetzt werden können.&lt;br /&gt;
Diese stehen dann dem Modul unmittelbar zur Verfügung um das Verhalten während der Ausführung zu beeinflussen. Attribute werden zusammen mit dem &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl der jeweiligen Definition beim Speichern der aktuellen Konfiguration von FHEM in die Konfigurationsdatei geschrieben. Beim Neustart werden die entsprechenden Befehle ausgeführt um alle Definition inkl. Attribute wieder anzulegen. Zur Laufzeit werden Attribute in dem globalen Hash &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt; mit dem Definitionsnamen als Index (&amp;lt;code&amp;gt;$attr{$name} = $value&amp;lt;/code&amp;gt;) gespeichert. Ein Attribut mit dem Namen &amp;lt;code&amp;gt;header&amp;lt;/code&amp;gt; würde beispielsweise mit &amp;lt;code&amp;gt;$attr{$name}{header}&amp;lt;/code&amp;gt; adressiert. Generell sollte &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt; nicht durch direkten Zugriff manipuliert/benutzt werden.&lt;br /&gt;
&lt;br /&gt;
Zum Auslesen von Attributen sollte die Funktion [[DevelopmentModuleAPI#AttrVal|AttrVal()]] verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Welche Attribute ein Modul unterstützt muss in der Funktion &amp;lt;code&amp;gt;[[#X_Initialize|X_Initialize]]&amp;lt;/code&amp;gt; durch Setzen von &amp;lt;code&amp;gt;$hash-&amp;gt;{AttrList}&amp;lt;/code&amp;gt; bekannt gemacht werden (siehe unten).&lt;br /&gt;
&lt;br /&gt;
Wenn beim Setzen von Attributen in einer Gerätedefinition entsprechende Werte geprüft werden sollen oder zusätzliche Funktionalitäten implementiert werden müssen, dann muss dies in der Funktion &amp;lt;code&amp;gt;[[#X_Attr|X_Attr]]&amp;lt;/code&amp;gt; (siehe unten) implementiert werden. Hier kann man bspw. einen Syntaxcheck für Attribut-Werte implementieren um ungültige Werte zurückzuweisen.&lt;br /&gt;
&lt;br /&gt;
== Modulfunktionen ==&lt;br /&gt;
&lt;br /&gt;
Damit fhem.pl ein Modul nutzen kann, muss dieses entsprechende Funktionen mit einer vorgegebenen Aufrufsyntax implementieren. Durch die Bekanntgabe dieser modulspezifischen Funktionen können Daten zwischen fhem.pl und einem Modul entsprechend ausgetauscht werden. Es gibt verschiedene Arten von Funktionen die ein Modul anbieten muss bzw. kann, je nach Funktionsumfang.&lt;br /&gt;
&lt;br /&gt;
=== Die wichtigsten Funktionen in einem Modul ===&lt;br /&gt;
&lt;br /&gt;
Folgende Funktion muss ein Modul mit dem beispielhaften Namen &amp;quot;X&amp;quot; mindestens bereitstellen:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;text-align:left&amp;quot; | Funktionsname !! style=&amp;quot;text-align:left&amp;quot; | Kurzbeschreibung&lt;br /&gt;
|-&lt;br /&gt;
|  [[#X_Initialize|X_Initialize]] || Initialisiert das Modul und gibt den Namen zusätzlicher Modulfunktionen bekannt, sowie modulspezifische Einstellungen. Wird direkt nach dem erfolgreichen Laden des Moduls durch fhem.pl aufgerufen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die folgenden Funktionen sind die wichtigsten Funktionen, welche je nach Anwendungsfall zu implementieren sind. Es handelt sich hierbei um die wichtigsten Vertreter, welche in den meisten Modulen Verwendung finden. Nicht alle Funktionen machen jedoch in jedem Modul Sinn. Generell sollte auch hier bei jeder Funktion der Modulname vorangestellt werden um ein einheitliches Namensschema zu gewährleisten. Hier die wichtigsten Modulfunktionen:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;text-align:left&amp;quot; | Funktionsname !! style=&amp;quot;text-align:left&amp;quot; class=&amp;quot;unsortable&amp;quot; | Kurzbeschreibung&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Define|X_Define]] || Wird im Rahmen des &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehls aufgerufen.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Undef|X_Undef]] || Wird im Rahmen des &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt;-Befehls, sowie &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt;-Befehl aufgerufen. Dient zum Abbau von offenen Verbindungen, Timern, etc.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Delete|X_Delete]] || Wird im Rahmen des beim &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt;-Befehls aufgerufen wenn das Gerät endgültig gelöscht wird um weiterführende Aktionen vor dem Löschen durchzuführen.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Get|X_Get]] || Wird im Rahmen des &amp;lt;code&amp;gt;get&amp;lt;/code&amp;gt;-Befehls aufgerufen um Daten vom Gerät abzufragen&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Set|X_Set]]  || Wird im Rahmen des &amp;lt;code&amp;gt;set&amp;lt;/code&amp;gt;-Befehls aufgerufen um Daten an das Gerät zu senden.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Attr|X_Attr]]  || Wird im Rahmen des &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt;-Befehls aufgerufen um Attributwerte zu prüfen)&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Read|X_Read]]  || Wird durch FHEM aufgerufen, wenn ein gelisteter Filedeskriptor in &amp;lt;code&amp;gt;[[#Wichtige_globale_Variablen_aus_fhem.pl|%selectlist]]&amp;lt;/code&amp;gt; Daten zum Lesen bereitstellt.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Ready|X_Ready]]  || Wird unter Windows durch FHEM aufgerufen um zyklisch einen seriellen Filedeskriptor auf lesbare Daten zu prüfen. Unter Linux dient diese Funktion dem Wiederaufbau verlorener Verbindungen.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Notify|X_Notify]]  || Verarbeitet Events von anderen Geräten innerhalb von FHEM&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Rename|X_Rename]] || Wird aufgerufen, wenn ein Gerät umbenannt wird.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Shutdown|X_Shutdown]] || Wird beim Herunterfahren von FHEM ausgeführt.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_DelayedShutdown | X_DelayedShutdown]] || Wird beim Herunterfahren von FHEM ausgeführt.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Diese Funktionen werden in diesem Abschnitt genauer beschrieben.&lt;br /&gt;
&lt;br /&gt;
==== X_Initialize ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; im Namen muss dabei auf den Namen des Moduls bzw. des definierten Gerätetyps geändert werden. Im Modul mit der Datei &amp;lt;code&amp;gt;36_JeeLink.pm&amp;lt;/code&amp;gt; beispielsweise ist der Name der Funktion &amp;lt;code&amp;gt;JeeLink_Initialize&amp;lt;/code&amp;gt;. Die Funktion wird von fhem.pl nach dem Laden des Moduls aufgerufen und bekommt eine leere Hashreferenz für den Initialisierungsvorgang übergeben. &lt;br /&gt;
&lt;br /&gt;
Dieser Hash muss nun von X_Initialize mit allen modulrelevanten Funktionsnamen gefüllt werden. Anschließend wird dieser Hash durch fhem.pl im globalen Hash &amp;lt;code&amp;gt;%modules&amp;lt;/code&amp;gt; gespeichert. &amp;lt;code&amp;gt;$modules{ModulName}&amp;lt;/code&amp;gt; wäre dabei der Hash für das Modul mit dem Namen &amp;lt;code&amp;gt;ModulName&amp;lt;/code&amp;gt;. Es handelt sich also nicht um den oben beschriebenen Hash der Geräteinstanzen sondern einen Hash, der für jedes Modul existiert und modulspezifische Daten wie bspw. die implementierten Modulfunktionen enthält. Die Initialize-Funktion setzt diese Funktionsnamen, in den Hash des Moduls wie folgt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
$hash-&amp;gt;{DefFn}                = &amp;quot;X_Define&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{UndefFn}              = &amp;quot;X_Undef&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{DeleteFn}             = &amp;quot;X_Delete&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{SetFn}                = &amp;quot;X_Set&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{GetFn}                = &amp;quot;X_Get&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{AttrFn}               = &amp;quot;X_Attr&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{ReadFn}               = &amp;quot;X_Read&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{ReadyFn}              = &amp;quot;X_Ready&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{NotifyFn}             = &amp;quot;X_Notify&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{RenameFn}             = &amp;quot;X_Rename&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{ShutdownFn}           = &amp;quot;X_Shutdown&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{DelayedShutdownFn}    = &amp;quot;X_ DelayedShutdown&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um eine entsprechende Funktion in FHEM bekannt zu machen muss dazu der Funktionsname, wie er im Modul als &amp;lt;code&amp;gt;sub &amp;amp;lt;&#039;&#039;Funktionsname&#039;&#039;&amp;amp;gt;() { ... }&amp;lt;/code&amp;gt; definiert ist, als Zeichenkette in &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; gesetzt werden. Dabei sollten die entsprechenden Funktionsnamen immer den Modulnamen (in diesem Beispiel &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;) als Präfix verwenden.&lt;br /&gt;
Auf diese Weise können sämtliche modulspezifisch implementierten Funktionen wie &amp;lt;code&amp;gt;X_Read&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;X_Parse&amp;lt;/code&amp;gt; etc. durch Zuweisung an &amp;lt;code&amp;gt;$hash-&amp;gt;{ReadFn}&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;$hash-&amp;gt;{ParseFn}&amp;lt;/code&amp;gt; usw. bekannt gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Darüber hinaus sollten die vom Modul unterstützten Attribute definiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
$hash-&amp;gt;{AttrList} =&lt;br /&gt;
  &amp;quot;do_not_notify:1,0 &amp;quot; . &lt;br /&gt;
  &amp;quot;header &amp;quot; .&lt;br /&gt;
  $readingFnAttributes;  &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Auflistung aller unterstützten modulspezifischen Attribute erfolgt in Form einer durch Leerzeichen getrennten Liste in &amp;lt;code&amp;gt;$hash-&amp;gt;{AttrList}&amp;lt;/code&amp;gt;. Es gibt in FHEM globale Attribute, die in allen Gerätedefinitionen verfügbar sind und nur modulspezifische Attribute die jedes Modul via &amp;lt;code&amp;gt;$hash-&amp;gt;{AttrList}&amp;lt;/code&amp;gt; über die eigene Initialize-Funktion setzt.  In fhem.pl werden dann die entsprechenden Attributwerte beim Aufruf eines &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt;-Befehls in die globale Datenstruktur &amp;lt;code&amp;gt;$attr{$name}&amp;lt;/code&amp;gt;, z.B. &amp;lt;code&amp;gt;$attr{$name}{header}&amp;lt;/code&amp;gt; für das Attribut &amp;lt;code&amp;gt;header&amp;lt;/code&amp;gt; gespeichert. Falls im Modul weitere Aktionen oder Prüfungen beim Setzen eines Attributs nötig sind, dann kann wie im Beispiel oben die [[#X_Attr|Attr]]-Funktion implementiert und in der Initialize-Funktion bekannt gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Die Variable &amp;lt;code&amp;gt;$readingFnAttributes&amp;lt;/code&amp;gt;, die im obigen Beispiel an die Liste der unterstützten Attribute angefügt wird, definiert Attributnamen, die dann zusätzlich gemacht werden, wenn das Modul zum Setzen von Readings die Funktionen &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsBeginUpdate|readingsBeginUpdate()]]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsBulkUpdate|readingsBulkUpdate()]]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsEndUpdate|readingsEndUpdate()]]&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsSingleUpdate|readingsSingleUpdate()]]&amp;lt;/code&amp;gt; verwendet. In diesen Funktionen werden Attribute wie &amp;lt;code&amp;gt;event-min-interval&amp;lt;/code&amp;gt; oder auch &amp;lt;code&amp;gt;event-on-change-reading&amp;lt;/code&amp;gt; ausgewertet. Für Details hierzu siehe commandref zu {{Link2CmdRef|Anker=readingFnAttributes|Label=readingFnAttributes}}.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von parseParams()&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion &amp;lt;code&amp;gt; [[DevelopmentModuleAPI#parseParams|parseParams()]]&amp;lt;/code&amp;gt; unterstützt Modul-Autoren beim Parsen von Übergabeparametern, welche bei &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;get&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;set&amp;lt;/code&amp;gt; Kommandos an die entsprechenden Modulfunktionen übergeben werden. Dadurch lassen sich auf einfache Weise insbesondere komplexe Parameter (wie bspw. Perl-Ausdrücke) sehr einfach parsen.&lt;br /&gt;
&lt;br /&gt;
Diese Zusatzfunktion kann man in der Initialize-Funktion einfach über folgenden Parameter für [[#X_Define|Define]]-, [[#X_Get|Get]]- und [[#X_Set|Set]]-Funktion modulweit aktivieren:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;$hash-&amp;gt;{parseParams} = 1;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Sobald es gesetzt ist wird automatisch durch fhem.pl &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#parseParams|parseParams()]]&amp;lt;/code&amp;gt; aufgerufen und die an die [[#X_Define|Define]]-, [[#X_Get|Get]]- und [[#X_Set|Set]]-Funktion übergebenen Parameter ändern sich wie weiter unten in den jeweiligen Funktionen beschrieben.&lt;br /&gt;
&lt;br /&gt;
==== X_Define ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $def ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Define-Funktion eines Moduls wird von FHEM aufgerufen wenn der Define-Befehl für ein Geräte ausgeführt wird und das Modul bereits geladen und mit der Initialize-Funktion initialisiert ist. Sie ist typischerweise dazu da, die übergebenen Parameter zu prüfen und an geeigneter Stelle zu speichern sowie einen Kommunikationsweg zum Gerät zu öffnen (z.B. TCP-Verbindung, USB-Schnittstelle o.ä.) oder einen [[#Pollen_von_Geräten|Status-Timer]] zu starten.&lt;br /&gt;
Sie beginnt typischerweise mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $def ) = @_;&lt;br /&gt;
	my @a = split( &amp;quot;[ \t][ \t]*&amp;quot;, $def );&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als Übergabeparameter bekommt die Define-Funktion den Hash der Geräteinstanz sowie den die im &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl übergebenen Parameter. Welche bzw. wie viele Parameter &lt;br /&gt;
akzeptiert werden und welcher Syntax diese entsprechen müssen ist Sache dieser Funktion. Im obigen Beispiel wird die Argumentzeile &amp;lt;code&amp;gt;$def&amp;lt;/code&amp;gt; in ein Array aufgeteilt (durch Leerzeichen/Tabulator getrennt) und so können die vom Modul bzw. der Define-Funktion erwarteten Werte über das Array der Reihe nach verarbeitet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
my $name   = $a[0];&lt;br /&gt;
my $module = $a[1];&lt;br /&gt;
my $url    = $a[2];&lt;br /&gt;
my $inter  = 300;&lt;br /&gt;
&lt;br /&gt;
if(int(@a) == 4) { &lt;br /&gt;
	$inter = $a[3]; &lt;br /&gt;
	if ($inter &amp;lt; 5) {&lt;br /&gt;
		return &amp;quot;interval too small, please use something &amp;gt; 5s, default is 300 seconds&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit die übergebenen Werte auch anderen Funktionen zur Verfügung stehen und an die jeweilige Geräteinstanz gebunden sind, werden die Werte typischerweise als Internals im Hash der Geräteinstanz gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
$hash-&amp;gt;{url} 		= $url;&lt;br /&gt;
$hash-&amp;gt;{Interval}	= $inter;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald alle Parameter korrekt verarbeitet wurden, wird in der Regel die erste Verbindung zum Gerät aufgebaut. Je nach Art des Geräts kann das eine permanente Datenverbindung sein (z.B. serielle Schnittstelle oder TCP-Verbindung) oder das Starten eines regelmäßigen Timers, der zyklisch den Status z.B. via [[HttpUtils|HTTP]] ausliest.&lt;br /&gt;
&lt;br /&gt;
Sollten im Rahmen der Define-Funktion Syntax-Probleme der Übergabeparameter festgestellt werden oder es kann bspw. keine Verbindung aufgebaut werden, so ist als Funktionsrückgabewert eine entsprechende Fehlermeldung zurückzugeben. Nur wenn alle Übergabeparameter akzeptiert werden, darf &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurückgegeben werden. Sobald eine Define-Funktion eine Fehlermeldung zurückmeldet, wird der define-Befehl durch FHEM zurückgewiesen und der User erhält die Fehlermeldung, welche die Define-Funktion produziert hat, als Ausgabe zurück.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Verfügbarkeit von Attributen&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Während die Define-Funktion ausgeführt wird, sollte man nicht davon ausgehen, dass alle vom Nutzer konfigurierten Attribute via [[DevelopmentModuleAPI#AttrVal|AttrVal()]] verfügbar sind. Attribute stehen in der Define-Funktion nur dann zur Verfügung, wenn FHEM sich nicht in der Initialisierungsphase befindet (globale Variable &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; ist wahr; der Nutzer hat die Gerätedefinition modifiziert). Daher sollte man weiterführende Funktion, welche auf gesetzte Attribute angewiesen sind, nur dann in der Define-Funktion starten, wenn &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; zutrifft.&lt;br /&gt;
&lt;br /&gt;
Andernfalls sollte man den Aufruf in der Notify-Funktion durchführen sobald &amp;lt;code&amp;gt;global:INITIALIZED&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;global:REREADCFG&amp;lt;/code&amp;gt; getriggert wurde:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $def ) = @_;&lt;br /&gt;
 &lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	$hash-&amp;gt;{NOTIFYDEV} = &amp;quot;global&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	X_FunctionWhoNeedsAttr($hash) if($init_done);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub X_Notify($$)&lt;br /&gt;
{&lt;br /&gt;
	my ($own_hash, $dev_hash) = @_;&lt;br /&gt;
	my $ownName = $own_hash-&amp;gt;{NAME}; # own name / hash&lt;br /&gt;
 &lt;br /&gt;
	return &amp;quot;&amp;quot; if(IsDisabled($ownName)); # Return without any further action if the module is disabled&lt;br /&gt;
 &lt;br /&gt;
	my $devName = $dev_hash-&amp;gt;{NAME}; # Device that created the events&lt;br /&gt;
	my $events = deviceEvents($dev_hash, 1);&lt;br /&gt;
&lt;br /&gt;
	if($devName eq &amp;quot;global&amp;quot; &amp;amp;&amp;amp; grep(m/^INITIALIZED|REREADCFG$/, @{$events}))&lt;br /&gt;
	{&lt;br /&gt;
		 X_FunctionWhoNeedsAttr($hash);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dadurch wird die Modulfunktion X_FunctionWhoNeedsAttr() nach dem Start erst aufgerufen, wenn alle Attribute aus der Konfiguration geladen wurden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von parseParams()&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Aufteilen und Parsen von &amp;lt;code&amp;gt;$def&amp;lt;/code&amp;gt; lässt sich die Funktion [[DevelopmentModuleAPI#parseParams|parseParams()]] verwenden um die einzelnen Argumente einfach zu parsen. Wenn in [[#X_Initialize|X_Initialize()]] &amp;lt;code&amp;gt;$hash-&amp;gt;{parseParams} = 1;&amp;lt;/code&amp;gt; gesetzt wurde dann wird parseParams() automatisch aufgerufen und X_Define() ändert sich wie folgt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $a, $h ) = @_;&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die genauen Möglichkeiten von parseParams() sind in dem entsprechenden [[DevelopmentModuleAPI#parseParams|Artikel]] dokumentiert.&lt;br /&gt;
&lt;br /&gt;
==== X_Undef ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Undef ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Die Undef-Funktion wird aufgerufen wenn ein Gerät mit &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; gelöscht wird oder bei der Abarbeitung des Befehls &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt;, der ebenfalls alle Geräte löscht und danach das Konfigurationsfile neu einliest. Entsprechend müssen in der Funktion typische Aufräumarbeiten durchgeführt werden wie das saubere Schließen von Verbindungen oder das Entfernen von internen Timern, sofern diese im Modul zum Pollen verwendet wurden (siehe Abschnitt [[#Pollen_von_Geräten|Pollen von Geräten]]). &lt;br /&gt;
&lt;br /&gt;
Zugewiesene Variablen im Hash der Geräteinstanz, Internals oder Readings müssen hier nicht gelöscht werden. In fhem.pl werden die entsprechenden Strukturen beim Löschen der Geräteinstanz ohnehin vollständig gelöscht.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Undef($$)    &lt;br /&gt;
{                     &lt;br /&gt;
	my ( $hash, $name) = @_;       &lt;br /&gt;
	DevIo_CloseDev($hash);         &lt;br /&gt;
	RemoveInternalTimer($hash);    &lt;br /&gt;
	return undef;                  &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollten im Rahmen der Undef-Funktion Probleme festgestellt werden, die ein Löschen nicht zulassen, so ist als Funktionsrückgabewert eine entsprechende Fehlermeldung zurückzugeben. Nur wenn die Undef-Funktion erfolgreich durchgeführt wurde, darf &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurückgegeben werden. Nur dann wird eine Gerätedefinition von FHEM auch tatsächlich gelöscht bzw. neu angelegt. Sollte die Undef-Funktion jedoch eine Fehlermeldung zurückgeben, wird der entsprechende Vorgang (&amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt;) für dieses Gerät abgebrochen. Es bleibt dann unverändert in FHEM bestehen.&lt;br /&gt;
&lt;br /&gt;
==== X_Delete ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Delete ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Delete-Funktion ist das Gegenstück zur Funktion [[#X_Define|X_Define]] und wird aufgerufen wenn ein Gerät mit dem Befehl &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; gelöscht wird. &lt;br /&gt;
&lt;br /&gt;
Wenn ein Gerät in FHEM gelöscht wird, wird zuerst die Funktion [[#X_Undef|X_Undef]] aufgerufen um offene Verbindungen zu schließen, anschließend wird die Funktion X_Delete aufgerufen. Diese dient eher zum Aufräumen von dauerhaften Daten, welche durch das Modul evtl. für dieses Gerät spezifisch erstellt worden sind. Es geht hier also eher darum, alle Spuren sowohl im laufenden FHEM-Prozess, als auch dauerhafte Daten bspw. im physikalischen Gerät zu löschen die mit dieser Gerätedefinition zu tun haben.&lt;br /&gt;
&lt;br /&gt;
Dies kann z.B. folgendes sein:&lt;br /&gt;
&lt;br /&gt;
* Löschen von Dateien im Dateisystem die während der Nutzung dieses Geräts angelegt worden sind.&lt;br /&gt;
* Lösen von evtl. Pairings mit dem physikalischen Gerät &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Delete($$)    &lt;br /&gt;
{                     &lt;br /&gt;
	my ( $hash, $name ) = @_;       &lt;br /&gt;
&lt;br /&gt;
	# Löschen von Geräte-assoziiertem Temp-File&lt;br /&gt;
	unlink($attr{global}{modpath}.&amp;quot;/FHEM/FhemUtils/$name.tmp&amp;quot;;)&lt;br /&gt;
&lt;br /&gt;
	return undef;&lt;br /&gt;
}    &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollten im Rahmen der Delete-Funktion Probleme festgestellt werden, die ein Löschen nicht zulassen, so ist als Funktionsrückgabewert eine entsprechende Fehlermeldung zurückzugeben. Nur die Delete-Funktion erfolgreich durchgeführt wurde, darf &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurückgegeben werden. Nur dann wird eine Gerätedefinition von FHEM auch tatsächlich gelöscht. Sollte die Delete-Funktion eine Fehlermeldung zurückgeben, wird der Löschvorgang abgebrochen und das Gerät bleibt weiter in FHEM bestehen.&lt;br /&gt;
&lt;br /&gt;
==== X_Get ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Get ($$@)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name, $opt, @args ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $result;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Die Get-Funktion wird aufgerufen wenn der FHEM-Befehl &amp;lt;code&amp;gt;get&amp;lt;/code&amp;gt; für eine Definition dieses Moduls ausgeführt wird. Mit &amp;lt;code&amp;gt;get&amp;lt;/code&amp;gt; werden typischerweise Werte von einem Gerät abgefragt. In vielen Modulen wird auf diese Weise auch der Zugriff auf generierte Readings ermöglicht. Der Get-Funktion wird dabei der Definitions-Hash &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;, der Definitionsname &amp;lt;code&amp;gt;$name&amp;lt;/code&amp;gt;, sowie die Aufrufparameter &amp;lt;code&amp;gt;$opt&amp;lt;/code&amp;gt; plus optional weiterer Parameter &amp;lt;code&amp;gt;@args&amp;lt;/code&amp;gt; übergeben. Als Rückgabewert &amp;lt;code&amp;gt;$result&amp;lt;/code&amp;gt; wird das Ergebnis des entsprechenden Befehls in Form einer Zeichenkette zurückgegeben. Der Rückgabewert &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; hat hierbei keine besondere Bedeutung und wird behandelt wie eine leere Zeichenkette &amp;lt;code&amp;gt;&amp;quot;&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Get($$@)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name, $opt, @args ) = @_;&lt;br /&gt;
&lt;br /&gt;
	return &amp;quot;\&amp;quot;get $name\&amp;quot; needs at least one argument&amp;quot; unless(defined($opt));&lt;br /&gt;
&lt;br /&gt;
	if($opt eq &amp;quot;status&amp;quot;) &lt;br /&gt;
	{&lt;br /&gt;
	   ...&lt;br /&gt;
	}&lt;br /&gt;
	elsif($opt eq &amp;quot;power&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
	   ...&lt;br /&gt;
	}&lt;br /&gt;
	...&lt;br /&gt;
	else&lt;br /&gt;
	{&lt;br /&gt;
		return &amp;quot;Unknown argument $opt, choose one of status power [...]&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn eine unbekannte Option an die Get-Funktion übergeben wird, so muss als Rückgabewert der Funktion eine bestimmte Syntax eingehalten werden um FHEM mitzuteilen, welche Optionen für einen Get-Befehl aktuell unterstützt werden. Dies gilt insbesondere für den Aufruf &amp;lt;code&amp;gt;get &amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;&#039;&#039;&amp;lt;NAME&amp;gt;&#039;&#039;&amp;lt;/font&amp;gt; &amp;lt;u&amp;gt;&#039;&#039;&#039;?&#039;&#039;&#039;&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt;, welche durch verschiedene Module (z.B. FHEMWEB) benutzt wird, um eine Liste aller unterstützten Befehle für eine Definition zu ermitteln. Die Rückgabe muss dabei folgender Syntax entsprechen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&#039;&#039;&#039;unknown&#039;&#039;&#039; argument &#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;[Parameter]&amp;lt;/font&amp;gt;&#039;&#039; &#039;&#039;&#039;choose one of&#039;&#039;&#039; &#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;[Liste möglicher Optionen]&amp;lt;/font&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei sind die fett gedruckten Teile der Rückmeldung besonders wichtig. Sind diese nicht vorhanden, können Module wie FHEMWEB nicht die möglichen Get-Kommandos für das entsprechende Gerät ermitteln. Es muss am Anfang der Meldung das Stichwort &amp;quot;unknown&amp;quot; vorkommen gefolgt von einer frei definierbaren Fehlermeldung (i.d.R der übergebene Parameter, welcher ungültig ist). Anschließend folgt &amp;quot;choose one of&amp;quot; mit einer anschließenden Liste möglicher Optionen getrennt durch ein Leerzeichen. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;return &amp;quot;unknown argument $opt choose one of status temperature humidity&amp;quot;;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden als mögliche Optionen für einen Get-Befehl folgende Parameter angegeben:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;temperature&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;humidity&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies würde in folgenden, mögliche Get-Befehle für einen User resultieren:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;get &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; status&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;get &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; temperature&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;get &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; humidity&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im weiteren Verlauf der Get-Funktion könnte man dann mit dem physischen Gerät kommunizieren und den gefragten Wert direkt abfragen und diesen als Return-Wert der Get-Funktion zurückgeben. Vielfach werden aber auch die vorhandenen Readings zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von parseParams()&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in [[#X_Initialize|X_Initialize()]] &amp;lt;code&amp;gt;$hash-&amp;gt;{parseParams} = 1;&amp;lt;/code&amp;gt; gesetzt wurde dann wird [[DevelopmentModuleAPI#parseParams|parseParams()]] automatisch aufgerufen und X_Get() ändert sich wie folgt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Get($$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $a, $h ) = @_;&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die genauen Möglichkeiten von parseParams() sind in dem entsprechenden [[DevelopmentModuleAPI#parseParams|Artikel]] dokumentiert.&lt;br /&gt;
&lt;br /&gt;
==== X_Set ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Set ($$@)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name, $cmd, @args ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	return $error;&lt;br /&gt;
	return ($error, $skip_trigger);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Set-Funktion ist das Gegenteil zur [[#X_Get|Get]]-Funktion. Sie ist dafür gedacht, Daten zum physischen Gerät zu schicken, bzw. entsprechende Aktionen im Gerät selber auszulösen. Ein Set-Befehl dient daher der direkten Steuerung des physikalischen Gerätes in dem es bspw. Zustände verändert (wie &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt;). Der Set-Funktion wird dabei der Definitions-Hash &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;, der Definitionsname &amp;lt;code&amp;gt;$name&amp;lt;/code&amp;gt;, sowie die Aufrufparameter &amp;lt;code&amp;gt;$cmd&amp;lt;/code&amp;gt; und optional weitere Argumente &amp;lt;code&amp;gt;@args&amp;lt;/code&amp;gt; übergeben. Als Rückgabewert &amp;lt;code&amp;gt;$error&amp;lt;/code&amp;gt; kann eine Fehlermeldung in Form Zeichenkette zurückgegeben werden. Der Rückgabewert &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; bedeutet hierbei, dass der Set-Befehl erfolgreich durchgeführt wurde. Eine Set-Funktion gibt daher nur im Fehlerfall eine Rückmeldung mit einer entsprechenden Fehlermeldung. Der Wert &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; wird als &amp;quot;erfolgreich&amp;quot; interpretiert. &lt;br /&gt;
&lt;br /&gt;
Standardmäßig wird jeder Set-Befehl, welcher erfolgreich ausgeführt wurde (&amp;lt;code&amp;gt;$error&amp;lt;/code&amp;gt; ist &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt;), als Event getriggert um dies bspw. in einem FileLog festzuhalten. Dieses Verhalten kann optional unterbunden werden indem der optionale zweite Rückgabewert &amp;lt;code&amp;gt;$skip_trigger&amp;lt;/code&amp;gt; auf &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; gesetzt wird. Damit wird das Generieren eines Events für das erfolgreich ausgeführte Set-Kommando unterbunden. Falls nicht gesetzt, wird ein Event erzeugt (&amp;lt;code&amp;gt;$cmd&amp;lt;/code&amp;gt; mit sämtlichen &amp;lt;code&amp;gt;@args&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Rückmeldungen (Fehler) von set-Befehlen sämtlicher Module, die im Rahmen der Ausführung eines getriggerten [[Notify]] auftreten, werden im FHEM Logfile festgehalten.&lt;br /&gt;
&lt;br /&gt;
Falls nur interne Daten, die ausschließlich für das Modul relevant sind, gesetzt werden müssen, so sollte statt Set die [[#X_Attr|Attr]]-Funktion verwendet werden. Attribute werden bei Save-Config auch in der Fhem.cfg gesichert. Set-Befehle nicht, da sie nur zu Steuerungszwecken im laufenden Betrieb von FHEM dienen.&lt;br /&gt;
 &lt;br /&gt;
Eine Set-Funktion ist ähnlich aufgebaut wie die Get-Funktion, sie bekommt jedoch in der Regel weitere zusätzliche Parameter (&amp;lt;code&amp;gt;@args&amp;lt;/code&amp;gt;) übergeben um Zustände zu setzen/ändern. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Set($@)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name, $cmd, @args ) = @_;&lt;br /&gt;
&lt;br /&gt;
	return &amp;quot;\&amp;quot;set $name\&amp;quot; needs at least one argument&amp;quot; unless(defined($cmd));&lt;br /&gt;
&lt;br /&gt;
	if($cmd eq &amp;quot;status&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
	   if($args[0] eq &amp;quot;up&amp;quot;)&lt;br /&gt;
	   {&lt;br /&gt;
	      ...&lt;br /&gt;
	   }&lt;br /&gt;
	   elsif($args[0] eq &amp;quot;down&amp;quot;)&lt;br /&gt;
	   {&lt;br /&gt;
	      ...&lt;br /&gt;
	   }&lt;br /&gt;
	   else&lt;br /&gt;
	   {&lt;br /&gt;
	      return &amp;quot;Unknown value $args[0] for $cmd, choose one of status power&amp;quot;;&lt;br /&gt;
	   }   &lt;br /&gt;
	}&lt;br /&gt;
	elsif($cmd eq &amp;quot;power&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
	   if($args[0] eq &amp;quot;on&amp;quot;)&lt;br /&gt;
	   {&lt;br /&gt;
	      ...&lt;br /&gt;
	   }&lt;br /&gt;
	   elsif($args[0] eq &amp;quot;off&amp;quot;)&lt;br /&gt;
	   {&lt;br /&gt;
	      ...&lt;br /&gt;
	   }  &lt;br /&gt;
	   else&lt;br /&gt;
	   {&lt;br /&gt;
	      return &amp;quot;Unknown value $args[0] for $cmd, choose one of status power&amp;quot;;&lt;br /&gt;
	   }       &lt;br /&gt;
	}&lt;br /&gt;
	...&lt;br /&gt;
	else&lt;br /&gt;
	{&lt;br /&gt;
		return &amp;quot;Unknown argument $cmd, choose one of status power&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn eine unbekannte Option an die Set-Funktion übergeben wird, so muss als Rückgabewert der Funktion eine bestimmte Syntax eingehalten werden um FHEM mitzuteilen, welche Optionen für einen Set-Befehl aktuell unterstützt werden. Dies gilt insbesondere für den Aufruf &amp;lt;code&amp;gt;set &amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;&#039;&#039;&amp;lt;NAME&amp;gt;&#039;&#039;&amp;lt;/font&amp;gt; &amp;lt;u&amp;gt;&#039;&#039;&#039;?&#039;&#039;&#039;&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt;, welcher durch verschiedene Module (z.B. FHEMWEB) benutzt wird, um eine Liste aller unterstützten Befehle für eine Definition zu ermitteln. Die Rückgabe muss dabei folgender Syntax entsprechen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&#039;&#039;&#039;unknown&#039;&#039;&#039; argument &#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;[Parameter]&amp;lt;/font&amp;gt;&#039;&#039; &#039;&#039;&#039;choose one of&#039;&#039;&#039; &#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;[Liste möglicher Optionen]&amp;lt;/font&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei sind die fett gedruckten Teile der Rückmeldung besonders wichtig. Sind diese nicht vorhanden, können Module wie FHEMWEB nicht die möglichen Set-Kommandos für das entsprechende Gerät ermitteln. Es muss am Anfang der Meldung das Stichwort &amp;quot;unknown&amp;quot; vorkommen gefolgt von einer frei definierbaren Fehlermeldung (i.d.R der übergebene Parameter, welcher ungültig ist). Anschließend folgt &amp;quot;choose one of&amp;quot; mit einer anschließenden Liste möglicher Optionen getrennt durch ein Leerzeichen. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;return &amp;quot;unknown argument $cmd choose one of status power&amp;quot;;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden als mögliche Optionen für einen Set-Befehl folgende Parameter angegeben:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;power&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies würde in folgenden, mögliche Set-Befehle für einen User resultieren:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;set &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; status&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;set &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; power&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von SetExtensions.pm&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn man dem Nutzer zusätzlich zu den Set-Befehlen &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; auch weiterführende Befehle wie &amp;lt;code&amp;gt;on-for-timer&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;on-till&amp;lt;/code&amp;gt;, usw. anbieten möchte, obwohl die zu steuernde Hardware solche Kommandos nicht unterstützt, kann man dies über das Hilfsmodul SetExtensions.pm realisieren.&lt;br /&gt;
&lt;br /&gt;
Das Hilfsmodul SetExtensions.pm bietet weiterführende Set-Kommandos basierend auf den Befehlen &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; an. Dabei werden durch interne Timer bzw. eigens angelegten [[at]]-Definitionen diese Befehle durch FHEM selber umgesetzt. Je nach ausgeführtem Befehl wird der &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;- bzw. &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt;-Befehl dann durch FHEM zum richtigen Zeitpunkt ausgeführt. Vorausgesetzt das Modul unterstützt in der Set-Funktion die Befehle &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt;, so werden durch den Einsatz von SetExtensions.pm folgende Befehle zusätzlich unterstützt:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Set-Kommando !! Beispiel !! Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-for-timer &#039;&#039;&amp;amp;lt;Dauer&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-for-timer 120&amp;lt;/code&amp;gt; || Schaltet das Gerät sofort mit dem &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;-Befehl ein und nach der angegebenen Dauer in Sekunden via &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; wieder aus.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-for-timer &#039;&#039;&amp;amp;lt;Dauer&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-for-timer 120&amp;lt;/code&amp;gt; || Schaltet das Gerät sofort mit dem &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt;-Befehl aus und nach der angegebenen Dauer in Sekunden via &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; wieder ein.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-till &#039;&#039;&amp;amp;lt;Zeitpunkt&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-till 16:30&amp;lt;/code&amp;gt; || Schaltet das Gerät sofort mit dem &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;-Befehl ein und zum angegebenen Zeitpunkt via &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; wieder aus.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-till &#039;&#039;&amp;amp;lt;Zeitpunkt&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-till 16:30&amp;lt;/code&amp;gt; || Schaltet das Gerät sofort mit dem &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt;-Befehl aus und zum angegebenen Zeitpunkt via &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; wieder ein.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-till-overnight &#039;&#039;&amp;amp;lt;Zeitpunkt&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-till-overnight 01:00&amp;lt;/code&amp;gt; || Ähnlich wie &amp;lt;code&amp;gt;on-till&amp;lt;/code&amp;gt;. Der übergebene Zeitpunkt wird aber nicht geprüft, ob er für den heutigen Tag bereits überschritten wurde. Dadurch kann man Abends einen Zeitpunkt setzen, der erst am nächsten Tag zutrifft.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-till-overnight &#039;&#039;&amp;amp;lt;Zeitpunkt&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-till-overnight 01:00&amp;lt;/code&amp;gt; || Ähnlich wie &amp;lt;code&amp;gt;off-till&amp;lt;/code&amp;gt;. Der übergebene Zeitpunkt wird aber nicht geprüft, ob er für den heutigen Tag bereits überschritten wurde. Dadurch kann man Abends einen Zeitpunkt setzen, der erst am nächsten Tag zutrifft.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;blink &#039;&#039;&amp;amp;lt;Anzahl&amp;amp;gt; &amp;amp;lt;Interval&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;blink 3 1&amp;lt;/code&amp;gt; || Schaltet das Gerät via &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; für &amp;lt;code&amp;gt;&#039;&#039;&amp;amp;lt;Interval&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; Sekunden ein und anschließend via &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; wieder aus. Nach &amp;lt;code&amp;gt;&#039;&#039;&amp;amp;lt;Interval&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; Sekunden wird das ganze wiederholt, solange bis die angegebene Anzahl erreicht ist.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;intervals &#039;&#039;&amp;amp;lt;Start&amp;amp;gt;-&amp;amp;lt;Ende&amp;amp;gt;&#039;&#039; &#039;&#039;&amp;amp;lt;Start&amp;amp;gt;-&amp;amp;lt;Ende&amp;amp;gt;&#039;&#039; ...&amp;lt;/code&amp;gt; || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;intervals 07:00-08:00 16:30-18:00&amp;lt;/code&amp;gt; || Schaltet das Gerät innerhalb der übergebenen Zeiträumen via &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; ein. Sobald die aktuelle Zeit ausserhalb dieser Zeiträume liegt, wird das Gerät via &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; wieder ausgeschaltet. Es können dabei beliebig viele Zeiträume angegeben werden.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;toggle&amp;lt;/code&amp;gt; || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;toggle&amp;lt;/code&amp;gt;  || Sofern der aktuelle Status &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; ist, wird das Gerät via &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; ausgeschaltet. Andernfalls wird es via &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; eingeschaltet.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Eine kurze Beschreibung zu den möglichen Befehlen durch SetExtensions.pm gibt es auch in der commandref zum {{Link2CmdRef|Anker=set|Label=set-Befehl}}.&lt;br /&gt;
&lt;br /&gt;
Um SetExtensions.pm in der Set-Funktion nutzen zu können müssen folgende Aktionen durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Laden von SetExtensions.pm via &amp;lt;code&amp;gt;use SetExtensions;&amp;lt;/code&amp;gt; am Anfang des Moduls&lt;br /&gt;
# Aufruf und Rückgabe der Funktion [[DevelopmentModuleAPI#SetExtensions|SetExtensions()]] sofern die Set-Funktion mit dem übergebenen Befehl nichts anfangen kann.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
use SetExtensions;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
sub X_Set($@)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name, $cmd, @args ) = @_;&lt;br /&gt;
	my $cmdList = &amp;quot;on off&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	return &amp;quot;\&amp;quot;set $name\&amp;quot; needs at least one argument&amp;quot; unless(defined($cmd));&lt;br /&gt;
&lt;br /&gt;
	if($cmd eq &amp;quot;on&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
		# Gerät einschalten...&lt;br /&gt;
	}&lt;br /&gt;
	elsif($cmd eq &amp;quot;off&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
		# Gerät ausschalten...&lt;br /&gt;
	}&lt;br /&gt;
	...&lt;br /&gt;
	else # wenn der übergebene Befehl nicht durch X_Set() verarbeitet werden kann, Weitergabe an SetExtensions()&lt;br /&gt;
	{&lt;br /&gt;
		return SetExtensions($hash, $cmdList, $name, $cmd, @args);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte der übergebene Set-Befehl auch für SetExtensions unbekannt sein (bspw. &amp;lt;code&amp;gt;set &#039;&#039;&amp;amp;lt;Name&amp;amp;gt;&#039;&#039; ?&amp;lt;/code&amp;gt;), so generiert SetExtensions() eine entsprechende Usage-Meldung, welche innerhalb der Set-Funktion an FHEM zurückgegeben werden muss.&lt;br /&gt;
&lt;br /&gt;
Eine ausführliche Beschreibung zu der Funktion SetExtensions() gibt es in der  [[DevelopmentModuleAPI#SetExtensions|API-Referenz]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von parseParams()&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in [[#X_Initialize|X_Initialize()]] &amp;lt;code&amp;gt;$hash-&amp;gt;{parseParams} = 1;&amp;lt;/code&amp;gt; gesetzt wurde dann wird [[DevelopmentModuleAPI#parseParams|parseParams()]] automatisch aufgerufen und X_Set() ändert sich wie folgt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Set($$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $a, $h ) = @_;&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die genauen Möglichkeiten von parseParams() sind in dem entsprechenden [[DevelopmentModuleAPI#parseParams|Artikel]] dokumentiert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von FHEMWEB-Widgets&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das GUI-Modul [[FHEMWEB]] kann für die einzelnen Set-Optionen, die das Modul versteht, automatisch Eingabehilfen wie Drop-Down Boxen oder Slider erzeugen. In der Detailansicht der GUI kann der Anwender dann die jeweiligen Werte komfortabel auswählen. Dafür muss die Set-Funktion, wenn sie mit der Option &amp;lt;code&amp;gt;?&amp;lt;/code&amp;gt; aufgerufen wird, nicht nur einen Text mit  &amp;lt;code&amp;gt;&amp;quot;Unknown ... choose one of ...&amp;quot;&amp;lt;/code&amp;gt; zurückgeben sondern den einzelnen Set-Optionen in diesem Rückgabetext nach einem Doppelpunkt entsprechende Zusatzinformationen anhängen.&lt;br /&gt;
Meist prüft man in den Modulen gar nicht auf die Option &amp;lt;code&amp;gt;?&amp;lt;/code&amp;gt; sondern gibt generell bei unbekannten Optionen diesen Text zurück. Das Modul FHEMWEB ermittelt die Syntax eines Gerätes jedoch immer mit dem Befehl:&lt;br /&gt;
 set &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; ?&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
	return &amp;quot;Unknown argument $cmd, choose one of status:up,down power:on,off on:noArg off:noArg&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit Kommata getrennte Werte ergeben eine Drop-Down Liste, mit der der User die Werte auswählen kann&lt;br /&gt;
&amp;lt;pre&amp;gt;timer:30,120,300&lt;br /&gt;
mode:verbose,ultra,relaxed&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wird kein Doppelpunkt zum Kommando angegeben, so wird eine Eingabezeile angezeigt, die die freie Eingabe eines Wertes erlaubt.&lt;br /&gt;
&lt;br /&gt;
Man kann jedoch die Eingabe-/Auswahlmöglichkeiten durch Widgets vereinfachen. Dazu gibt man hinter dem Doppelpunkt einen Widgetnamen und widgetspezifische Parameter an. Es existieren mehrere solcher Widgets in FHEMWEB. Die gebräuchlichsten sind:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Zusatz !! Beispiel !! Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;noArg&#039;&#039;&#039; || &amp;lt;code&amp;gt;reset:noArg&amp;lt;/code&amp;gt;|| Es werden keine weiteren Argumente mehr benötigt. In so einem Fall wird bei der Auswahl keine Textbox oder ähnliches angezeigt, da keine weiteren Argumente für diesen Befehl notwendig sind.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;slider&#039;&#039;&#039;,&amp;lt;min&amp;gt;,&amp;lt;step&amp;gt;,&amp;lt;max&amp;gt; || &amp;lt;code&amp;gt;dim:slider,0,1,100&amp;lt;/code&amp;gt;|| Es wird ein Schieberegler angezeigt um den Parameter auszuwählen. Dabei werden als Zusatzparameter Minimum, Schrittweite und Maximum angegeben.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;colorpicker&#039;&#039;&#039; || &amp;lt;code&amp;gt;rgb:colorpicker,RGB&amp;lt;/code&amp;gt;|| Es wird ein Colorpicker angezeigt, der dem Anwender die Auswahl einer Farbe ermöglicht. Die genaue Parametersyntax kann man dem Artikel zum  [[Color#Colorpicker|Colorpicker]] entnehmen.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;multiple&#039;&#039;&#039; || &amp;lt;code&amp;gt;group:multiple,Telefon,Multimedia,Licht,Heizung&amp;lt;/code&amp;gt; || Es erscheint ein Auswahldialog, wo man verschiedene Werte durch klicken auswählen kann. Optional kann man in einem Freitext eigene Werte ergänzen. dieser Dialog wird bspw. bei der Raum-Auswahl (Attribut &amp;quot;room&amp;quot;) oder der Gruppen-Auswahl (Attribut &amp;quot;group&amp;quot;) in FHEMWEB genutzt. &lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;sortable&#039;&#039;&#039; || &amp;lt;code&amp;gt;command:sortable,monday,tuesday,...&amp;lt;/code&amp;gt; || Es erscheint ein Auswahldialog, wo man verschiedene Werte auswählen und sortieren kann. Man kann dabei Werte durch Klicken auswählen und durch Drag&#039;n&#039;Drop sortieren.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Es gibt noch weitere solcher Widgets. Eine genaue Auflistung dazu findet sich in der {{Link2CmdRef|Anker=widgetOverride}} unter widgetOverride zu FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweise&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Damit in einer Eingabe bereits der aktuelle Wert vorbelegt bzw. in einer Auswahlliste der aktuelle Wert vorselektiert ist, muss es im Modul bzw. Gerät ein Reading mit dem gleichen Namen wie die Set-Option geben. Der Wert des gleichnamigen Readings wird dann als Vorbelegung / Vorselektion verwendet. &lt;br /&gt;
* Der User kann sich in der Raumübersicht nach wie vor via [[WebCmd|webCmd]] eine entsprechende Steuerung anlegen.&lt;br /&gt;
&lt;br /&gt;
==== X_Attr ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Attr($$$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $cmd, $name, $attrName, $attrValue  ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Attr-Funktion dient der Prüfung von Attributen, welche über den &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt;-Befehl gesetzt werden können. Sobald versucht wird, ein Attribut für ein Gerät zu setzen, wird vorher die Attr-Funktion des entsprechenden Moduls aufgerufen um zu prüfen, ob das Attribut aus Sicht des Moduls korrekt ist.&lt;br /&gt;
Liegt ein Problem mit dem Attribut bzw. dem Wert vor, so muss die Funktion eine aussagekräftige Fehlermeldung zurückgeben, welche dem User angezeigt wird.&lt;br /&gt;
Sofern das übergebene Attribut samt Inhalt korrekt ist, gibt die Attr-Funktion den Wert &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurück. Erst dann wird das Attribut in der globalen Datenstruktur &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt; gespeichert und ist somit erst aktiv.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Attr($$$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $cmd, $name, $attrName, $attrValue ) = @_;&lt;br /&gt;
    &lt;br /&gt;
  	# $cmd  - Vorgangsart - kann die Werte &amp;quot;del&amp;quot; (löschen) oder &amp;quot;set&amp;quot; (setzen) annehmen&lt;br /&gt;
	# $name - Gerätename&lt;br /&gt;
	# $attrName/$attrValue sind Attribut-Name und Attribut-Wert&lt;br /&gt;
    &lt;br /&gt;
	if ($cmd eq &amp;quot;set&amp;quot;) {&lt;br /&gt;
		if ($aName eq &amp;quot;Regex&amp;quot;) {&lt;br /&gt;
			eval { qr/$aVal/ };&lt;br /&gt;
			if ($@) {&lt;br /&gt;
				Log3 $name, 3, &amp;quot;X ($name) - Invalid regex in attr $name $aName $aVal: $@&amp;quot;;&lt;br /&gt;
				return &amp;quot;Invalid Regex $aVal: $@&amp;quot;;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	return undef;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zusätzlich ist es möglich auch übergebene Attributwerte zu verändern bzw. zu korrigieren, indem man im Parameterarray &amp;lt;code&amp;gt;@_&amp;lt;/code&amp;gt; den ursprünglichen Wert anpasst. Dies erfolgt im Beispiel über die Modifikation des Wertes mit Index 3 (entspricht dem 4. Element) im Parameterarray, also &amp;lt;code&amp;gt;$_[3]&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Da das Attribut zum Zeitpunkt des Aufrufs der Attr-Funktion noch nicht gespeichert ist, wird der neue Wert zu diesem Zeitpunkt noch nicht via [[DevelopmentModuleAPI#AttrVal|AttrVal()]] zurückgegeben. Erst, wenn die Attr-Funktion mit &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; beendet ist, wird der neue Wert in FHEM gespeichert und steht dann via AttrVal() zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Die Attr-Funktion bekommt nicht den Hash der Geräteinstanz übergeben, da sie normalerweise keine Werte dort speichern muss, sondern lediglich das Attribut auf Korrektheit prüfen muss.&lt;br /&gt;
Im obigen Beispiel wird für ein Attribut mit Namen &amp;quot;Regex&amp;quot; geprüft ob der reguläre Ausdruck fehlerhaft ist. Sofern dieser OK ist, wird &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurückgegeben und fhem.pl speichert den Wert des Attributs in &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Attributnamen mit Platzhaltern&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls man Attribute in der [[#X_Initialize|Initialize]]-Funktion mit Platzhaltern definiert (Wildcard-Attribute) wie z.B.:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
    $hash-&amp;gt;{AttrList} =&lt;br /&gt;
      &amp;quot;reading[0-9]*Name &amp;quot; .&lt;br /&gt;
    # usw.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
dann können Anwender Attribute wie reading01Name, reading02Name etc. setzen. Leider funktioniert das bisher nicht durch Klicken in der Web-Oberfläche, da FHEMWEB nicht alle denkbaren Ausprägungen in einem Dropdown anbieten kann. Der Benutzer muss solche Attribute manuell über den &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt;-Befehl eingeben.&lt;br /&gt;
&lt;br /&gt;
Man kann jedoch in der Attr-Funktion neu gesetzte Ausprägungen von Wildcard-Attributen an die gerätespezifische userattr-Variable anfügen. Dann können bereits gesetzte Attribute in FHEMWEB durch Klicken ausgewählt und geändert werden.&lt;br /&gt;
Dazu reicht ein Aufruf der Funktion [[DevelopmentModuleAPI#addToDevAttrList|addToDevAttrList()]]: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
    addToDevAttrList($name, $aName);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Read ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Read ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Die X_Read-Funktion wird aufgerufen, wenn ein dem Gerät zugeordneter Filedeskriptor (serielle Schnittstelle, TCP-Verbindung, ...) Daten zum Lesen bereitgestellt hat. Die Daten müssen nun eingelesen und interpretiert werden.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird über eine serielle Schnittstelle (beziehungsweise über einen USB-To-Serial-Konverter) von einem angeschlossenen Gerät gelesen. Dazu werden die bisher verfügbaren Daten mit der Funktion [[DevIo#DevIo_SimpleRead()|DevIo_SimpleRead()]] gelesen. Da die Übertragung möglicherweise noch nicht vollständig ist, kann es sein, dass kurz darauf die X_Read-Funktion wieder aufgerufen wird und ein weiterer Teil oder der Rest der Daten gelesen werden kann.&lt;br /&gt;
Die Funktion muss daher prüfen ob schon alle erwarteten Daten angekommen sind und gegebenenfalls die bisher gelesenen Daten in einem eigenen Puffer (idealerweise in &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;) zwischenspeichern (siehe auch [[DevIo#Hinweis bei der Datenverarbeitung (Buffering)|DevIo]]). Im Beispiel ist dies &amp;lt;code&amp;gt;$hash-&amp;gt;{helper}{BUFFER}&amp;lt;/code&amp;gt; an den die aktuell gelesenen Daten angehängt werden, bis die folgende Prüfung ein für das jeweilige Protokoll vollständige Frame erkennt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Read($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
	my $name = $hash-&amp;gt;{NAME};&lt;br /&gt;
	&lt;br /&gt;
	# einlesen der bereitstehenden Daten&lt;br /&gt;
	my $buf = DevIo_SimpleRead($hash);		&lt;br /&gt;
	return &amp;quot;&amp;quot; if ( !defined($buf) );&lt;br /&gt;
	Log3 $name, 5, &amp;quot;X ($name) - received data: &amp;quot;.$buf;    &lt;br /&gt;
&lt;br /&gt;
	# Daten in Hex konvertieren und an den Puffer anhängen&lt;br /&gt;
	$hash-&amp;gt;{helper}{BUFFER} .= unpack (&#039;H*&#039;, $buf);	&lt;br /&gt;
	Log3 $name, 5, &amp;quot;X ($name) - current buffer content: &amp;quot;.$hash-&amp;gt;{helper}{BUFFER};&lt;br /&gt;
&lt;br /&gt;
	# prüfen, ob im Buffer ein vollständiger Frame zur Verarbeitung vorhanden ist.&lt;br /&gt;
	if ($hash-&amp;gt;{helper}{BUFFER} =~ &amp;quot;ff1002(.{4})(.*)1003(.{4})ff(.*)&amp;quot;) {&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die zu lesenden Nutzdaten können dann je nach Protokoll des Geräts beispielsweise an einer festgelegten Stelle im Frame (dann in &amp;lt;code&amp;gt;$hash-&amp;gt;{helper}{BUFFER}&amp;lt;/code&amp;gt;) stehen oder aus dem Kontext mit einem Regex-Match extrahiert werden und via [[DevelopmentModuleAPI#Readings_.2F_Events|Reading-Funktionen]] in Readings gespeichert werden (siehe unten).&lt;br /&gt;
&lt;br /&gt;
Der Rückgabewert der Read-Funktion wird nicht geprüft und hat daher keinerlei Bedeutung.&lt;br /&gt;
&lt;br /&gt;
==== X_Ready ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Ready ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
    &lt;br /&gt;
	return $success;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wird im Main-Loop aufgerufen falls das Modul in der globalen Liste &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt; existiert. Diese Funktion hat, je nachdem auf welchem OS FHEM ausgeführt wird, unterschiedliche Aufgaben:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;UNIX-artiges Betriebssystem:&#039;&#039;&#039; prüfen, ob eine Verbindung nach einem Verbindungsabbruch wieder aufgebaut werden kann. Sobald der Verbindungsaufbau erfolgreich war, muss die Funktion einen erfolgreichen Wahrheitswert zurückliefern (z.B. &amp;quot;1&amp;quot;) und den eigenen Eintrag entsprechend aus &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt; löschen.&lt;br /&gt;
* &#039;&#039;&#039;Windows-Betriebssystem:&#039;&#039;&#039; prüfen, ob lesbare Daten für ein serielles Device (via COM1, COM2, ...) vorliegen. Sofern lesbare Daten vorliegen, muss Funktion einen erfolgreichen Wahrheitswert zurückliefern (z.B. &amp;quot;1&amp;quot;). Zusätzlich dazu muss die Funktion, wie bei UNIX-artigen Betriebssystem, ebenfalls bei einem Verbindungsabbruch einen neuen Verbindungsversuch initiieren. Der Eintrag in &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt; bleibt solange erhalten, bis die Verbindung seitens FHEM beendet wird.&lt;br /&gt;
&lt;br /&gt;
Der Windows-spezifische Teil zur Datenprüfung ist dabei nur zu implementieren, wenn das Modul über eine serielle Verbindung kommuniziert.&lt;br /&gt;
&lt;br /&gt;
Bei der Nutzung des Moduls [[DevIo]] wird dem Modulentwickler der Umgang mit &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt; abgenommen, da DevIo sich selbst um die entsprechenden Einträge kümmert und diese selbstständig wieder entfernt.&lt;br /&gt;
&lt;br /&gt;
In der Regel sieht eine Ready-Funktion immer gleich aus.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Ready($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
      &lt;br /&gt;
	# Versuch eines Verbindungsaufbaus, sofern die Verbindung beendet ist.&lt;br /&gt;
	return DevIo_OpenDev($hash, 1, undef ) if ( $hash-&amp;gt;{STATE} eq &amp;quot;disconnected&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
	# This is relevant for Windows/USB only&lt;br /&gt;
	if(defined($hash-&amp;gt;{USBDev})) {&lt;br /&gt;
		my $po = $hash-&amp;gt;{USBDev};&lt;br /&gt;
		my ( $BlockingFlags, $InBytes, $OutBytes, $ErrorFlags ) = $po-&amp;gt;status;&lt;br /&gt;
		return ( $InBytes &amp;gt; 0 );&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Notify ====&lt;br /&gt;
&lt;br /&gt;
Die X_Notify-Funktion wird aus der Funktion [[DevelopmentModuleAPI#DoTrigger|DoTrigger()]] in fhem.pl heraus aufgerufen sobald ein Modul Events erzeugt hat. Damit kann ein Modul auf Events anderer Module reagieren. Typische Beispiele sind dabei das [[FileLog]]-Modul oder das [[notify]]-Modul.&lt;br /&gt;
&lt;br /&gt;
Die Notify-Funktion bekommt dafür zwei Hash-Referenzen übergeben: den Hash des eigenen Geräts und den Hash des Geräts, das die Events erzeugt hat. &lt;br /&gt;
Über den Hash des eigenen Geräts kann die Notify-Funktion beispielsweise auf die Internals oder Attribute des eigenen Geräts zugreifen.&lt;br /&gt;
Über den Hash des Gerätes und der [[DevelopmentModuleAPI#deviceEvents|deviceEvents()]]-Funktion kann man auf die generierten Events zugreifen. Über den zweiten Parameter dieser Routine lässt sich bestimmen ob für das Reading &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; ein &#039;normales&#039; Event (d.h. in der form &amp;lt;code&amp;gt;state: &amp;lt;wert&amp;gt;&amp;lt;/code&amp;gt;) erzeugen soll (Wert: 1) oder ob z.b. aus Gründen der Rückwärtskompatibilität ein Event ohne &amp;lt;code&amp;gt;state: &amp;lt;/code&amp;gt; erzeugt werden soll. Falls dem Anwender die Wahl des verwendeten Formats überlassen werden soll ist hierzu das {{Link2CmdRef|Anker=addStateEvent|Lang=de|Label=addStateEvent-Attribut}} vorzusehen.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff auf &amp;lt;code&amp;gt;$hash-&amp;gt;{CHANGED}&amp;lt;/code&amp;gt; ist nicht mehr zu empfehlen.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Notify($$)&lt;br /&gt;
{&lt;br /&gt;
  my ($own_hash, $dev_hash) = @_;&lt;br /&gt;
  my $ownName = $own_hash-&amp;gt;{NAME}; # own name / hash&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot; if(IsDisabled($ownName)); # Return without any further action if the module is disabled&lt;br /&gt;
&lt;br /&gt;
  my $devName = $dev_hash-&amp;gt;{NAME}; # Device that created the events&lt;br /&gt;
&lt;br /&gt;
  my $events = deviceEvents($dev_hash,1);&lt;br /&gt;
  return if( !$events );&lt;br /&gt;
&lt;br /&gt;
  foreach my $event (@{$events}) {&lt;br /&gt;
    $event = &amp;quot;&amp;quot; if(!defined($event));&lt;br /&gt;
&lt;br /&gt;
    # Examples:&lt;br /&gt;
    # $event = &amp;quot;readingname: value&amp;quot; &lt;br /&gt;
    # or&lt;br /&gt;
    # $event = &amp;quot;INITIALIZED&amp;quot; (for $devName equal &amp;quot;global&amp;quot;)&lt;br /&gt;
    #&lt;br /&gt;
    # processing $event with further code&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Begrenzung der Aufrufe auf bestimmte Geräte&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da die Notify-Funktion für jedes definierte Gerät mit all seinen Events aufgerufen wird, muss sie in einer Schleife jedesmal prüfen und entscheiden, ob es mit dem jeweiligen Event etwas anfangen kann. Ein Gerät, das die Notify-Funktion implementiert, sieht dafür typischerweise einen regulären Ausdruck vor, welcher für die Filterung verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Wenn man nur gezielt von bestimmten Definitionen Events erhalten will, kann man diese auch in Form einer {{Link2CmdRef|Lang=de|Anker=devspec|Label=devspec}} in &amp;lt;code&amp;gt;$hash-&amp;gt;{NOTIFYDEV}&amp;lt;/code&amp;gt; angeben. Bspw. kann man in der Define-Funktion diesen Wert setzen. Dadurch wird die Notify-Funktion nur aufgerufen wenn eine der Definitionen, auf welche die devspec passt, ein Event erzeugt hat. Ein typischer Fall ist die Begrenzung von Events auf &amp;quot;global&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
in der Define-Funktion:&lt;br /&gt;
&lt;br /&gt;
$hash-&amp;gt;{NOTIFYDEV} = &amp;quot;global&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{NOTIFYDEV} = &amp;quot;global,Definition_.*&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{NOTIFYDEV} = &amp;quot;global,Definition_A,Definition_B&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{NOTIFYDEV} = &amp;quot;global,TYPE=CUL_HM&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies schont insbesondere bei grossen Installationen Ressourcen, da die Notify-Funktion nicht sämtliche Events, sondern nur noch Events der gewünschten Definitionen erhält. Dadurch erfolgen deutlich weniger Aufrufe der Notify-Funktion, was Systemressourcen schont.&lt;br /&gt;
&lt;br /&gt;
Sofern in der [[#X_Define|Define-Funktion]] eine Regexp als Argument übergeben wird, die ähnlich wie beim Modul [[notify]] auf Events wie &amp;lt;code&amp;gt;&amp;amp;lt;Definitionsname&amp;amp;gt;&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;&amp;amp;lt;Definitionsname&amp;amp;gt;:&amp;amp;lt;Event&amp;amp;gt;&amp;lt;/code&amp;gt; reagiert, so sollte man in der Define-Funktion die Funktion [[DevelopmentModuleAPI#notifyRegexpChanged|notifyRegexpChanged()]] verwenden. Diese versucht einen passenden Eintrag für &amp;lt;code&amp;gt;$hash-&amp;gt;{NOTIFYDEV}&amp;lt;/code&amp;gt; basierend auf der übergebenen Regexp zu setzen, sofern dies möglich ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Reihenfolge für den Aufruf der Notify-Funktion beeinflussen&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald ein Event ausgelöst wurde, stellt sich FHEM eine Liste aller relevanten Geräte-Hashes zusammen, welche via Notify-Funktion prüfen müssen, ob das Event relevant ist. Dabei wird die Liste nach &amp;lt;code&amp;gt;$hash-&amp;gt;{NTFY_ORDER}&amp;lt;/code&amp;gt; sortiert. Diese enthält ein Order-Präfix in Form einer Ganzzahl, sowie den Namen der Definition (Bsp: &amp;lt;code&amp;gt;&#039;&#039;&#039;50&#039;&#039;&#039;-Lampe_Wohnzimmer&amp;lt;/code&amp;gt;). Dadurch kann man jedoch nicht sicherstellen, dass Events von bestimmten Modulen zuerst verarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn das eigene Modul bei der Eventverarbeitung gegenüber den anderen Modulen eine bestimmte Reihenfolge einhalten muss, kann man in der [[#X_Initialize|Initialize]]-Funktion durch Setzen von &amp;lt;code&amp;gt;$hash-&amp;gt;{NotifyOrderPrefix}&amp;lt;/code&amp;gt; diese Reihenfolge beeinflussen. Standardmäßig werden Module immer mit einem Order-Präfix von &amp;quot;50-&amp;quot; in FHEM registriert. Durch die Veränderung dieses Präfixes kann man das eigene Modul in der Reihenfolge gegenüber anderen Modulen bei der Eventverarbeitung beeinflussen. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	$hash-&amp;gt;{NotifyOrderPrefix} = &amp;quot;45-&amp;quot;  # Alle Definitionen des Moduls X werden bei der Eventverarbeitung zuerst geprüft&lt;br /&gt;
	&lt;br /&gt;
	# oder...&lt;br /&gt;
	&lt;br /&gt;
	$hash-&amp;gt;{NotifyOrderPrefix} = &amp;quot;55-&amp;quot;  # Alle Definitionen des Moduls X werden bei der Eventverarbeitung als letztes geprüft&lt;br /&gt;
	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Da dieses Präfix bei eventverarbeitenden Definitionen in &amp;lt;code&amp;gt;$hash-&amp;gt;{NTFY_ORDER}&amp;lt;/code&amp;gt; dem Definitionsnamen vorangestellt wird bewirkt es bei einer normalen aufsteigenden Sortierung nach &amp;lt;code&amp;gt;$hash-&amp;gt;{NTFY_ORDER}&amp;lt;/code&amp;gt; eine veränderte Reihenfolge. Alle Module die in der Initialize-Funktion nicht &amp;lt;code&amp;gt;$hash-&amp;gt;{NotifyOrderPrefix}&amp;lt;/code&amp;gt; explizit setzen, werden mit &amp;quot;50-&amp;quot; als Standardwert vorbelegt.&lt;br /&gt;
&lt;br /&gt;
==== X_Rename ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Rename($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $new_name, $old_name) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Rename-Funktion wird ausgeführt, nachdem ein Gerät umbenannt wurde. Auf diese Weise kann ein Modul auf eine Namensänderung reagieren, wenn das Gerät &amp;lt;code&amp;gt;$old_name&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;$new_name&amp;lt;/code&amp;gt; umbenannt wurde. Ein typischer Fall ist das Umsetzen der Namensänderungen bei Daten die mittels [[DevelopmentModuleAPI#setKeyValue|setKeyValue()]] gespeichert wurden. Hierbei müssen die Daten, welche unter dem alten Namen gespeichert sind, auf den neuen Namen geändert werden.&lt;br /&gt;
&lt;br /&gt;
Der Rename-Funktion wird lediglich der alte, sowie der neue Gerätename übergeben. Der Rückgabewert wird nicht ausgewertet.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Rename($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $new_name, $old_name ) = @_;&lt;br /&gt;
&lt;br /&gt;
	my $old_index = &amp;quot;Module_X_&amp;quot;.$old_name.&amp;quot;_data&amp;quot;;&lt;br /&gt;
	my $new_index = &amp;quot;Module_X_&amp;quot;.$new_name.&amp;quot;_data&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	my ($err, $data) = getKeyValue($old_index);&lt;br /&gt;
	return undef unless(defined($old_pwd));&lt;br /&gt;
&lt;br /&gt;
	setKeyValue($new_index, $data);&lt;br /&gt;
	setKeyValue($old_index, undef);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_DelayedShutdown ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_DelayedShutdown($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	return $delay_needed;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Mit der X_DelayedShutdown Funktion kann eine Definition das Stoppen von FHEM verzögern um asynchron hinter sich aufzuräumen. Dies kann z.B. der ordnungsgemäße Verbindungsabbau mit dem physikalischen Gerät sein (z.B. Session beenden, Logout, etc.), welcher mehrfache Requests/Responses benötigt. Als Übergabeparameter wird der Geräte-Hash &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; bereitgestellt. Je nach Rückgabewert &amp;lt;code&amp;gt;$delay_needed&amp;lt;/code&amp;gt; wird der Stopp von FHEM verzögert. Ist ein verzögerter Stopp von FHEM notwendig, darf der Rückgabewert in diesem Fall nicht &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; sein.&lt;br /&gt;
&lt;br /&gt;
Im Unterschied zur [[#X_Shutdown|Shutdown]]-Funktion steht vor einem bevorstehenden Stopp von FHEM für einen User-konfigurierbaren Zeitraum (global-Attribut: &amp;lt;code&amp;gt;maxShutdownDelay&amp;lt;/code&amp;gt; / Standard: 10 Sekunden) weiterhin die asynchrone FHEM Infrastruktur ([[DevIo]]/[[#X_Read|Read]]-Funktion und [[DevelopmentModuleAPI#InternalTimer|InternalTimer]]) zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Sobald alle nötigen Maßnahmen erledigt sind, muss der Abschluss mit [[DevelopmentModuleAPI#CancelDelayedShutdown|CancelDelayedShutdown(&amp;lt;code&amp;gt;$name&amp;lt;/code&amp;gt;)]] an FHEM zurückgemeldet werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_DelayedShutdown($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
&lt;br /&gt;
	# Aufräumen starten&lt;br /&gt;
	&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Shutdown ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Shutdown ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Mit der X_Shutdown Funktion kann ein Modul Aktionen durchführen bevor FHEM gestoppt wird. Dies kann z.B. der ordnungsgemäße Verbindungsabbau mit dem physikalischen Gerät sein (z.B. Session beenden, Logout, etc.). Nach der Ausführung der Shutdown-Fuktion wird FHEM sofort beendet. Falls vor dem Herunterfahren von FHEM asynchrone Kommunikation (via [[DevIo]]/[[#X_Read|X_Read]]) notwendig ist um eine vorhandene Verbindung sauber zu beenden, sollte man [[#X_DelayedShutdownFn|X_DelayedShutdownFn]] verwenden.&lt;br /&gt;
&lt;br /&gt;
Als Übergabeparameter wird der Geräte-Hash bereitgestellt. Der Rückgabewert einer Shutdown-Funktion wird nicht ausgewertet und ist daher irrelevant.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Shutdown($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
&lt;br /&gt;
	# Verbindung schließen&lt;br /&gt;
	DevIo_CloseDev($hash);&lt;br /&gt;
	return undef;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Funktionen für zweistufiges Modulkonzept ===&lt;br /&gt;
&lt;br /&gt;
Für das [[#Zweistufiges_Modell_für_Module|zweistufige Modulkonzept]] gibt es weiterhin:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;text-align:left&amp;quot; | Funktionsname !! style=&amp;quot;text-align:left&amp;quot; class=&amp;quot;unsortable&amp;quot; | Kurzbeschreibung&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Parse|X_Parse]] || Zustellen von Daten via [[DevelopmentModuleAPI#Dispatch|Dispatch()]] vom physischen Modul zum logischen Modul zwecks der Verarbeitung.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Write|X_Write]]|| Zustellen von Daten via [[DevelopmentModuleAPI#Dispatch|IOWrite()]] vom logischen zum physischen Modul um diese an die Hardware weiterzureichen.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Fingerprint|X_Fingerprint]] || Rückgabe eines &amp;quot;Fingerabdrucks&amp;quot; einer Nachricht. Dient der Erkennung von Duplikaten im Rahmen von [[DevelopmentModuleAPI#Dispatch|Dispatch()]]. Kann im physischen, als auch logischen Modul benutzt werden.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Für das zweistufige Modulkonzept muss in einem logischen Modul eine [[#X_Parse|Parse]]-Funktion im Modul-Hash registriert werden. In einem physikalischen Modul muss eine [[#X_Write|Write]]-Funktion registriert sein. Diese dienen dem Datenaustausch in beide Richtungen und werden von dem jeweils anderen Modul indirekt aufgerufen.&lt;br /&gt;
&lt;br /&gt;
In der [[#X_Initialize|Initialize]]-Funktion werden diese wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
$hash-&amp;gt;{ParseFn}       = &amp;quot;X_Parse&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{WriteFn}       = &amp;quot;X_Write&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{FingerprintFn} = &amp;quot;X_Fingerprint&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktionen werden in diesem Abschnitt genauer beschrieben.&lt;br /&gt;
&lt;br /&gt;
==== X_Parse ====&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;u&amp;gt;&#039;&#039;&#039;ACHTUNG&#039;&#039;&#039;:&amp;lt;/u&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
Dieser Abschnitt geht davon aus, dass das Modul mit dem Namen &amp;quot;X&amp;quot; ein &#039;&#039;&#039;logisches Modul&#039;&#039;&#039; im Sinne des zweistufigen Modulkonzepts ist, also Daten mit einem übergeordneten, physikalischen Modul austauscht.}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Parse ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $io_hash, $message) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	return $found;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion X_Parse wird aufgerufen, sobald von dem IO-Gerät &amp;lt;code&amp;gt;$io_hash&amp;lt;/code&amp;gt; eine Nachricht &amp;lt;code&amp;gt;$message&amp;lt;/code&amp;gt; via [[DevelopmentModuleAPI#Dispatch|Dispatch()]] zur Verarbeitung angefragt wird. Die Parse-Funktion muss dann prüfen, zu welcher Gerätedefinition diese Nachricht gehört und diese entsprechend verarbeiten.&lt;br /&gt;
&lt;br /&gt;
Üblicherweise enthält eine Nachricht immer eine Komponente durch welche sich die Nachricht einem Gerät zuordnen lässt (z.B. Adresse, ID-Nummer, ...). Eine solche Identifikation sollte man im Rahmen der [[#X_Define|Define]]-Funktion im logischen Modul an geeigneter Stelle speichern, um in der Parse-Funktion eine einfache Zuordnung von Adresse/ID einer Nachricht zur entsprechenden Gerätedefinition zu haben. Dazu wird in der Regel im Modul-Hash im modulspezifischen Bereich eine Liste &amp;lt;code&amp;gt;defptr&amp;lt;/code&amp;gt; (Definition Pointer) geführt, welche jede eindeutige Adresse/ID dem entsprechenden Geräte-Hash zuordnet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sub X_Define ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $def) = @_;&lt;br /&gt;
	my @a = split(&amp;quot;[ \t][ \t]*&amp;quot;, $def);&lt;br /&gt;
	my $name = $a[0];&lt;br /&gt;
&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	# erstes Argument ist die eindeutige Geräteadresse&lt;br /&gt;
	my $address = $a[1];&lt;br /&gt;
&lt;br /&gt;
	# Adresse rückwärts dem Hash zuordnen (für ParseFn)&lt;br /&gt;
	$modules{X}{defptr}{$address} = $hash;&lt;br /&gt;
&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auf Basis dieses Definition Pointers kann die Parse-Funktion nun sehr einfach prüfen, ob für die empfangene Nachricht bereits eine entsprechende Gerätedefinition existiert. Sofern diese existiert, kann die Nachricht entsprechend verarbeitet werden. Sollte jedoch keine passende Gerätedefinition zu der empfangenen Nachricht existieren, so muss die Parse-Funktion den Gerätenamen &amp;quot;UNDEFINED&amp;quot; zusammen mit den Argumenten für einen &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl zurückgeben, welcher ein passendes Gerät in FHEM anlegen würde (durch [[autocreate]]).&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sub X_Parse ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $io_hash, $message) = @_;&lt;br /&gt;
	&lt;br /&gt;
	# Die Stellen 10-15 enthalten die eindeutige Identifikation des Geräts&lt;br /&gt;
	my $address = substr($message, 10, 5); &lt;br /&gt;
&lt;br /&gt;
	# wenn bereits eine Gerätedefinition existiert (via Definition Pointer aus Define-Funktion)&lt;br /&gt;
	if(my $hash = $modules{X}{defptr}{$address}) &lt;br /&gt;
	{&lt;br /&gt;
		...  # Nachricht für $hash verarbeiten&lt;br /&gt;
		&lt;br /&gt;
		# Rückgabe des Gerätenamens, für welches die Nachricht bestimmt ist.&lt;br /&gt;
		return $hash-&amp;gt;{NAME}; &lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
	{&lt;br /&gt;
		# Keine Gerätedefinition verfügbar&lt;br /&gt;
		# Daher Vorschlag define-Befehl: &amp;lt;NAME&amp;gt; &amp;lt;MODULNAME&amp;gt; &amp;lt;ADDRESSE&amp;gt;&lt;br /&gt;
		return &amp;quot;UNDEFINED X_&amp;quot;.$address.&amp;quot; X $address&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Write ====&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;u&amp;gt;&#039;&#039;&#039;ACHTUNG&#039;&#039;&#039;:&amp;lt;/u&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
Dieser Abschnitt geht davon aus, dass das Modul mit dem Namen &amp;quot;X&amp;quot; ein &#039;&#039;&#039;physisches Modul&#039;&#039;&#039; im Sinne des zweistufigen Modulkonzepts ist, also Daten mit untergeordneten logischen Modulen austauscht. }}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Write ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, @arguments) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	return $return;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Write-Funktion wird durch die Funktion [[DevelopmentModuleAPI#IOWrite|IOWrite()]] aufgerufen, sobald eine logische Gerätedefinition Daten per IO-Gerät an die Hardware übertragen möchte. Dazu kümmert sich die Write-Funktion um die Übertragung der Nachricht in geeigneter Form an die verbundene Hardware. Als Argumente wird der Hash des physischen Gerätes übertragen, sowie alle weiteren Argumente, die das logische Modul beim Aufruf von IOWrite() mitgegeben hat. Im Normalfall ist das ein Skalar mit der zu sendenden Nachricht in Textform. Es kann aber auch sein, dass weitere Daten zum Versand notwendig sind (evtl. Schlüssel, Session-Key, ...). Daher ist die Parametersyntax einer zu schreibenden Nachricht via IOWrite-/Write-Funktion zwischen logischem und physikalischem Modul abzustimmen.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Write ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $message, $address) = @_;&lt;br /&gt;
	&lt;br /&gt;
	DevIo_SimpleWrite($hash, $address.$message, 2);&lt;br /&gt;
&lt;br /&gt;
	return undef;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Fingerprint ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Fingerprint($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $io_name, $msg ) = @_;&lt;br /&gt;
 &lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return ( $io_name, $fingerprint );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Fingerprint-Funktion dient der Erkennung von Duplikaten empfangener Nachrichten. Diese Funktion kann dabei sowohl im physischen, als auch im logischen Modul implementiert sein - je nachdem auf welcher Ebene man für eine Nachricht einen Fingerprint bilden kann. &lt;br /&gt;
&lt;br /&gt;
Als Parameter wird der Name des IO-Geräts &amp;lt;code&amp;gt;$io_name&amp;lt;/code&amp;gt; übergeben, sowie die Nachricht &amp;lt;code&amp;gt;$msg&amp;lt;/code&amp;gt;, welche empfangen wurde. Nun muss aus dieser Nachricht ein eindeutiger Fingerprint gebildet werden. Dies bedeutet, dass alle variablen Inhalte, die aufgrund des Empfangs dieser Nachricht über unterschiedliche IO-Geräte enthalten sein können, entfernt werden müssen. Dies können bspw. Empfangsadressen von IO-Geräten sein oder Session-ID&#039;s die in der Nachricht enthalten sind. Alle Fingerprints sämtlicher Nachrichten, die innerhalb der letzten 500 Millisekunden (konfigurierbar via &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt; Attribut &amp;lt;code&amp;gt;dupTimeout&amp;lt;/code&amp;gt;) empfangen wurden, werden gegen diesen generierten Fingerprint getestet. Sollte innerhalb dieser Zeit bereits eine Nachricht mit diesem Fingerprint verarbeitet worden sein, so wird sie als Duplikat erkannt und nicht weiter verarbeitet. In diesem Fall gibt [[DevelopmentModuleAPI#Dispatch|Dispatch()]] den Namen der Gerätedefinition zurück, welche eine Nachricht mit dem selben Fingerprint bereits verarbeitet hat. Es erfolgt dann kein Aufruf der [[#X_Parse|Parse]]-Funktion.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Fingerprint($$)&lt;br /&gt;
{&lt;br /&gt;
  my ( $io_name, $msg ) = @_;&lt;br /&gt;
&lt;br /&gt;
  substr( $msg, 2, 2, &amp;quot;--&amp;quot; ); # entferne Empfangsadresse&lt;br /&gt;
  substr( $msg, 4, 1, &amp;quot;-&amp;quot; );  # entferne Hop-Count&lt;br /&gt;
&lt;br /&gt;
  return ( $io_name, $msg );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es wird zuerst, sofern implementiert, die Fingerprint-Funktion des physischen Moduls aufgerufen. Sollte sich hierdurch kein Duplikat erkennen lassen, wird die Fingerprint-Funktion jedes möglichen geladenen logischen Moduls aufgerufen, sofern implementiert. &lt;br /&gt;
&lt;br /&gt;
Sollte sowohl im physischen, als auch im logischen Modul keine Fingerprint-Funktion implementiert sein, so wird keinerlei Duplikatserkennung durchgeführt.&lt;br /&gt;
&lt;br /&gt;
=== FHEMWEB-spezifische Funktionen ===&lt;br /&gt;
&lt;br /&gt;
FHEMWEB bietet Modul-Autoren die Möglichkeit an durch spezielle Funktionsaufrufe in Modulen, eigene HTML-Inhalte zu verwenden. Dadurch können in Verbindung mit zusätzlichem JavaScript komplexe Dialoge/Inhalte/Steuermöglichkeiten dargestellt werden. &lt;br /&gt;
&lt;br /&gt;
Eine genaue Auflistung aller FHEMWEB-spezifischen Funktionsaufrufe gibt es in dem separaten Artikel [[DevelopmentFHEMWEB]]&lt;br /&gt;
&lt;br /&gt;
=== sonstige Funktionen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden weitere Funktionen behandelt die zum Teil aus FHEM, aber auch aus anderen Modulen aufgerufen werden. Sie sind dabei nur in speziellen Anwendungsfällen relevant. Hier eine Auflistung aller sonstigen Modulfunktionen:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Funktionsname !! class=&amp;quot;unsortable&amp;quot; | Kurzbeschreibung&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_DbLog_split|X_DbLog_split]] || Wird durch das Modul 93_DbLog.pm aufgerufen. Dient dem korrekten Split eines moduleigenen Events in Name/Wert/Einheit für die Nutzung einer Datenbank.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Except|X_Except]]|| Wird aufgerufen, sobald ein ein geöffneter Filedescriptor in [[#Wichtige_globale_Variablen_aus_fhem.pl|&amp;lt;code&amp;gt;%selectlist&amp;lt;/code&amp;gt;]], der unter &amp;lt;code&amp;gt;$hash-&amp;gt;{EXCEPT_FD}&amp;lt;/code&amp;gt; im Geräte-Hash gesetzt ist, einen Interrupt bzw. Exception auslöst.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Copy|X_Copy]]|| Wird durch das Modul 98_copy.pm aufgerufen im Rahmen des &amp;lt;code&amp;gt;copy&amp;lt;/code&amp;gt;-Befehls sobald ein Gerät kopiert wurde.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_State|X_State]]|| Wird aufgerufen im Rahmen des &amp;lt;code&amp;gt;setstate&amp;lt;/code&amp;gt;-Befehls bevor der Status einer Gerätedefinition bzw. eines zugehörigen Readings gesetzt wird.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_AsyncOutput|X_AsyncOutput]]|| Nur relevant für Module die via [[TcpServerUtils]] eine Client-Verbindung zu FHEM ermöglichen (z.B. FHEMWEB und telnet). Ermöglicht die asynchrone Ausgabe von Daten via [[DevelopmentModuleAPI#asyncOutput|asyncOutput()]] an einen einzelnen verbundenen Client.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_ActivateInform|X_ActivateInform]]|| Nur relevant für Module die via [[TcpServerUtils]] eine Client-Verbindung zu FHEM ermöglichen (z.B. FHEMWEB und telnet). Ermöglicht das Aktivieren des inform-Mechanismus zum Senden von Events für einen einzelnen verbundenen Client.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Authorize|X_Authorize]]|| Wird aufgerufen im Rahmen von [[DevelopmentModuleAPI#Authorized|Authorized()]] um eine gewünschte Vorgangs-Art zu autorisieren.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Authenticate|X_Authenticate]]||  Wird aufgerufen im Rahmen von [[DevelopmentModuleAPI#Authenticate|Authenticate()]] um eine Authentifizierung zu prüfen und ggf. zu genehmigen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In der [[#X_Initialize|Initialize]]-Funktion werden diese wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
$hash-&amp;gt;{DbLog_splitFn} = &amp;quot;X_DbLog_split&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{ExceptFn} = &amp;quot;X_Except&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{CopyFn} = &amp;quot;X_Copy&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{AsyncOutputFn} = &amp;quot;X_AsyncOutput&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{ActivateInformFn} = &amp;quot;X_ActivateInform&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{StateFn} = &amp;quot;X_State&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{AuthorizeFn} = &amp;quot;X_Authorize&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{AuthenticateFn} = &amp;quot;X_Authenticate&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Funktionen werden in diesem Abschnitt genauer beschrieben.&lt;br /&gt;
==== X_DbLog_split ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_DbLog_split ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $event, $device_name ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
    &lt;br /&gt;
	return  ( $reading, $value, $unit );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die DbLog_split-Funktion wird durch das Modul [[DbLog]] aufgerufen, sofern der Nutzer DbLog benutzt. Sofern diese Funktion implementiert ist, kann der Modul-Autor das Auftrennen von Events in den Reading-Namen, -Wert und der Einheit selbst steuern. Andernfalls nimmt DbLog diese Auftrennung selber mittels Trennung durch Leerzeichen sowie vordefinierten Regeln zu verschiedenen Modulen vor. Je nachdem, welche Readings man in seinem Modul implementiert, passt diese standardmäßige Trennung jedoch nicht immer.&lt;br /&gt;
&lt;br /&gt;
Der Funktion werden folgende Eingangsparameter übergeben:&lt;br /&gt;
# Das generierte Event (Bsp: &amp;lt;code&amp;gt;temperature: 20.5 °C&amp;lt;/code&amp;gt;)&lt;br /&gt;
# Der Name des Geräts, welche das Event erzeugt hat (Bsp: &amp;lt;code&amp;gt;Temperatursensor_Wohnzimmer&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
Es ist nicht möglich in der DbLog_split-Funktion auf die verarbeitende DbLog-Definition zu referenzieren.&lt;br /&gt;
&lt;br /&gt;
Als Rückgabewerte muss die Funktion folgende Werte bereitstellen:&lt;br /&gt;
# Name des Readings (Bsp: &amp;lt;code&amp;gt;temperature&amp;lt;/code&amp;gt;)&lt;br /&gt;
# Wert des Readings (Bsp: &amp;lt;code&amp;gt;20.5&amp;lt;/code&amp;gt;)&lt;br /&gt;
# Einheit des Readings (Bsp: &amp;lt;code&amp;gt;°C&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_DbLog_splitFn($$)&lt;br /&gt;
{&lt;br /&gt;
	my ($event, $device) = @_;&lt;br /&gt;
	my ($reading, $value, $unit);&lt;br /&gt;
        my $devhash = $defs{$device}&lt;br /&gt;
&lt;br /&gt;
	if($event =~ m/temperature/) {&lt;br /&gt;
	   $reading = &#039;temperature&#039;;&lt;br /&gt;
	   $value = substr($event,12,4);&lt;br /&gt;
	   $unit = &#039;°C&#039;;&lt;br /&gt;
	}   &lt;br /&gt;
        &lt;br /&gt;
        return ($reading, $value, $unit);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Except ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Except ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die X_Except-Funktion wird durch fhem.pl aufgerufen, wenn die Gerätedefinition &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;[[#Wichtige_globale_Variablen_aus_fhem.pl|%selectlist]]&amp;lt;/code&amp;gt; aufgeführt ist und der Filedeskriptor in &amp;lt;code&amp;gt;$hash-&amp;gt;{EXCEPT_FD}&amp;lt;/code&amp;gt; eine Exception bzw. Interrupt auslöst. &lt;br /&gt;
&lt;br /&gt;
Der Rückgabewert wird nicht ausgewertet und ist daher irrelevant.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
use IO::File;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
sub X_Except ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	# Filehandle aus Filedescriptor erstellen&lt;br /&gt;
	my $filehandle = IO::File-&amp;gt;new_from_fd($hash-&amp;gt;{EXCEPT_FD}, &#039;r&#039;);&lt;br /&gt;
	seek($filehandle,0,0);	&lt;br /&gt;
&lt;br /&gt;
	# aktuellen Inhalt auslesen&lt;br /&gt;
	my $current_value = $filehandle-&amp;gt;getline;&lt;br /&gt;
&lt;br /&gt;
	if($current_value eq &amp;quot;1&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
		...&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
	{&lt;br /&gt;
		...&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Copy ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Copy ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $old_name, $new_name ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die X_Copy-Funktion wird durch das Modul [[copy]] aufgerufen nachdem ein Nutzer eine Gerätedefinition über den Befehl &amp;lt;code&amp;gt;copy&amp;lt;/code&amp;gt; kopiert hat. Dazu werden als Funktionsparameter die Definitionsnamen der alten und neuen Gerätedefinition übergeben. Es dient dazu zusätzliche Daten aus der zu kopierenden Gerätedefinition in die neue Definition zu übernehmen. Der Befehl &amp;lt;code&amp;gt;copy&amp;lt;/code&amp;gt; überträgt lediglich &amp;lt;code&amp;gt;$hash-&amp;gt;{DEF}&amp;lt;/code&amp;gt; in die neue Definition sowie sämtliche gesetzte Attribute. Weitere Daten müssen dann durch die X_Copy-Funktion übertragen werden. &lt;br /&gt;
&lt;br /&gt;
Die X_Copy-Funktion wird erst nach dem erfolgtem Kopiervorgang aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Der Rückgabewert wird nicht ausgewertet und ist daher irrelevant.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sub X_Copy ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $old_name, $new_name ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	my $old_hash = $defs{$old_name};&lt;br /&gt;
	my $new_hash = $defs{$new_name};&lt;br /&gt;
&lt;br /&gt;
	# copy also temporary session key&lt;br /&gt;
	$new_hash-&amp;gt;{helper}{SESSION_KEY} = $old_hash-&amp;gt;{helper}{SESSION_KEY};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_AsyncOutput ====&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=&#039;&#039;&#039;ACHTUNG:&#039;&#039;&#039; Diese Funktion ist nur relevant, wenn man ein Frontend-Modul erstellt über das FHEM von einem Anwender bedient werden kann (FHEMWEB, telnet, yowsup, telegram, alexa-fhem, homebridge-fhem, tabletui, ...).}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_AsyncOutput ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $client_hash, $text ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion X_AsyncOutput wird durch [[DevelopmentModuleAPI#asyncOutput|asyncOutput()]] von anderen Modulen aufgerufen. Es erlaubt diesen anderen Modulen die Ausgabe von asynchronen Befehlsergebnissen &amp;lt;code&amp;gt;$text&amp;lt;/code&amp;gt; zuvor ausgeführter set-/get-Befehle an den entsprechenden Client (identifiziert durch den Client-Hash &amp;lt;code&amp;gt;$client_hash&amp;lt;/code&amp;gt; der temporären Definition) zurückzugeben. &lt;br /&gt;
&lt;br /&gt;
Wenn ein Client einen set-/get-Befehl ausführt, wird der Client-Hash bei der Ausführung dieser Befehle an die jeweiligen Module übermittelt. Sobald ein Befehl ausgeführt wird, der seine Ausgabe asynchron ausführen möchte und die Client-Verbindung des Server-Moduls dies unterstützt (&amp;lt;code&amp;gt;$client_hash-&amp;gt;{canAsyncOutput}&amp;lt;/code&amp;gt; ist gesetzt), merkt sich das befehlsausführende Modul den Client-Hash und gibt das Ergebnis des Befehls zu späterer Zeit via [[DevelopmentModuleAPI#asyncOutput|asyncOutput()]] an den ursprünglichen Client zurück. Die Funktion X_AsyncOutput des Server-Moduls kümmert sich darum das Ergebnis dem entsprechenden Client in der notwendigen Form zuzustellen.&lt;br /&gt;
&lt;br /&gt;
Der Rückgabewert von X_AsyncOutput() wird als Rückgabewert für asyncOutput() verwendet. Man kann hier im Fehlerfall eine Fehlermeldung angeben und im Erfolgsfall &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt;. Der Rückgabewert wird aber aktuell nicht ausgewertet.&lt;br /&gt;
&lt;br /&gt;
==== X_ActivateInform====&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=&#039;&#039;&#039;ACHTUNG:&#039;&#039;&#039; Diese Funktion ist nur relevant, wenn man ein Frontend-Modul erstellt über das FHEM von einem Anwender bedient werden kann (FHEMWEB, telnet, yowsup, telegram, alexa-fhem, homebridge-fhem, tabletui, ...).}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_ActivateInform($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $client_hash, $arg ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion X_ActivateInform wird aktuell nur durch den [[update]]-Befehl aufgerufen, sofern ein Client eines Frontend-Moduls diesen Befehl aufgerufen hat um den Inform-Mechanismus (Senden von Events) zu aktivieren. Dadurch wird im Falle von [[update]] die umgehende Anzeige der Logmeldungen für den ausführenden Client aktiviert. In [[FHEMWEB]] geschieht das über den Event-Monitor, bei telnet mit der direkten Ausgabe.&lt;br /&gt;
&lt;br /&gt;
Da diese Funktion aktuell nur speziell für den update-Befehl implementiert ist, kann man aktuell keine genaue Angaben zu den möglichen Werten von &amp;lt;code&amp;gt;$arg&amp;lt;/code&amp;gt; geben. Dieser Parameter dient dazu genauer zu spezifizieren was exakt an Events an den entsprechenden Client &amp;lt;code&amp;gt;$client_hash&amp;lt;/code&amp;gt; zu senden ist. Aktuell wird dazu die Parametersyntax des inform-Befehls verwendet (on|off|log|raw|timer|status).&lt;br /&gt;
&lt;br /&gt;
==== X_State ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_State($$$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $time, $readingName, $value ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die X_State-Funktion wird durch fhem.pl aufgerufen, sobald über den Befehl &amp;lt;code&amp;gt;setstate&amp;lt;/code&amp;gt; versucht wird ein Wert für ein Reading oder den Status (&amp;lt;code&amp;gt;$hash-&amp;gt;{STATE}&amp;lt;/code&amp;gt;) einer Gerätedefinition zu setzen. Dieser Befehl wird primär beim Starten von FHEM aufgerufen sobald das State-File eingelesen wird. Je nachdem, ob im gegebenen Fall ein Reading oder der Definitionsstatus gesetzt wird, haben die Übergabeparameter verschiedene Werte:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Funktionsparameter!! Wert beim Setzen eines Readings !! Wert beim Setzen eines Definitionsstatus&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; || colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; | Die Hashreferenz der betreffenden Gerätedefinition&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$time&amp;lt;/code&amp;gt;|| Der Zeitstempel auf welchen das Reading &amp;lt;code&amp;gt;$readingName&amp;lt;/code&amp;gt; gesetzt werden soll. Das Ergebnis entspricht dem Rückgabewert der Funktion || Der aktuelle Zeitstempel zum jetzigen Zeitpunkt.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$readingName&amp;lt;/code&amp;gt;|| Der Name des Readings, welches auf einen neuen Wert gesetzt werden soll. || Statischer Wert &amp;quot;STATE&amp;quot; um anzuzeigen, dass es sich um den Definitionsstatus handelt, welcher gesetzt werden soll (&amp;lt;code&amp;gt;$hash-&amp;gt;{STATE}&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$value&amp;lt;/code&amp;gt; || Den Wert, welchen das Reading &amp;lt;code&amp;gt;$readingName&amp;lt;/code&amp;gt; annehmen soll. || Den Wert, welchen die Gerätedefinition als Status annehmen soll.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Wenn via &amp;lt;code&amp;gt;setstate&amp;lt;/code&amp;gt; ein Reading gesetzt wird, kann die X_State-Funktion das Setzen dieses Readings durch die Rückgabe einer aussagekräftigen Fehlermeldung unterbinden. Sofern &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurückgegeben wird, wird das entsprechende Reading auf den übergebenen Status gesetzt.&lt;br /&gt;
&lt;br /&gt;
Wenn via &amp;lt;code&amp;gt;setstate&amp;lt;/code&amp;gt; der Definitionsstatus gesetzt wird, wird die X_State-Funktion erst nach dem Setzen des Status aufgerufen. Man kann dabei zwar eine Fehlermeldung zurückgeben, der Status wird aber dennoch übernommen. Die Fehlermeldung wird lediglich dem Nutzer angezeigt.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_State($$$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $time, $readingName, $value ) = @_;&lt;br /&gt;
&lt;br /&gt;
	return undef if($readingName &amp;quot;STATE&amp;quot; || $value ne &amp;quot;inactive&amp;quot;);&lt;br /&gt;
	readingsSingleUpdate($hash, &amp;quot;state&amp;quot;, &amp;quot;inactive&amp;quot;, 1);&lt;br /&gt;
	return undef;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Authorize ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Authorize($$$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $client_hash, $type, $arg ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $authorized;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Authorize-Funktion wird von fhem.pl aufgerufen um zu erfragen, ob ein bestimmter Client &amp;lt;code&amp;gt;$client_hash&amp;lt;/code&amp;gt; die Aktion &amp;lt;code&amp;gt;$type&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;$arg&amp;lt;/code&amp;gt; ausführen darf. Auf diese Weise können Module Einfluss nehmen, welcher User welche Funktionen in FHEM nutzen darf. Wenn ein Client eine Aktion ausführen möchte, werden alle Module, die eine Authorize-Funktion implementiert haben, gefragt, ob diese Aktion ausgeführt werden darf. Als Rückgabewert wird das Ergebnis der Überprüfung zurückgegeben, wobei &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (unbekannt / nicht zuständig), &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (erlaubt) oder &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (verboten) zurückgegeben werden können.&lt;br /&gt;
&lt;br /&gt;
Es gibt aktuell folgende &amp;lt;code&amp;gt;$type&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;$arg&amp;lt;/code&amp;gt; Kombinationen, mit denen die Authorize-Funktion aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! $type !! $arg !! Überschrift&lt;br /&gt;
|- &lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&#039;&#039;&#039;$type&#039;&#039;&#039; = &amp;quot;cmd&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Befehlsausführung&#039;&#039;&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&#039;&#039;&#039;$arg&#039;&#039;&#039; = &amp;quot;set Lampe on&amp;quot;&amp;lt;/code&amp;gt; || Jeglicher FHEM-Befehl, der ausgeführt werden soll, wird in &amp;lt;code&amp;gt;$arg&amp;lt;/code&amp;gt; hinterlegt, sodass innerhalb einer Authorize-Funktion der Befehl genauer geparst werden kann um zu entscheiden, ob dieser Befehl erlaubt ist, oder nicht.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&#039;&#039;&#039;$arg&#039;&#039;&#039; = &amp;quot;perl&amp;quot;&amp;lt;/code&amp;gt; || Ausführen von Perl-Befehlen jeglicher Art. Der genaue Befehl wird dabei nicht an die Authorize-Funktion übergeben.&lt;br /&gt;
&lt;br /&gt;
Bsp: &amp;lt;code&amp;gt;{ReadingsVal(&amp;quot;Lampe&amp;quot;, &amp;quot;state&amp;quot;, &amp;quot;off&amp;quot;}&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&#039;&#039;&#039;$arg&#039;&#039;&#039; = &amp;quot;shell&amp;quot;&amp;lt;/code&amp;gt; || Ausführen von Shell-Befehlen jeglicher Art. Der genaue Befehl wird dabei nicht an die Authorize-Funktion übergeben.&lt;br /&gt;
&lt;br /&gt;
Bsp: &amp;lt;code&amp;gt;&amp;quot;/opt/fhem/myScript.sh&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&#039;&#039;&#039;$type&#039;&#039;&#039; = &amp;quot;devicename&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Sichtbarkeit von Geräten/Definitionen&#039;&#039; &lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; |  &amp;lt;code&amp;gt;&#039;&#039;&#039;$arg&#039;&#039;&#039; = &amp;quot;Licht_Wohnzimmer&amp;quot;&amp;lt;/code&amp;gt; || Sichtbarkeit des jeweiligen Gerät/Definition in FHEM. Dies bedeutet konkret die Auffindbarkeit im &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;-Befehl, sowie der Suche via [[DevelopmentModuleAPI#devspec2array|devspec2array()]]. Wird eine solche Anfrage durch die Authorize-Funktion abgelehnt, ist das entsprechende Gerät bzw. Definition für den jeweiligen Client nicht sichtbar.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== X_Authenticate ====&lt;br /&gt;
{{Link2Forum|Topic=72757|Message=644098}}&lt;br /&gt;
&lt;br /&gt;
== Bereitstellen eines eigenen Befehls (Befehlsmodul) ==&lt;br /&gt;
&lt;br /&gt;
Ein Modul kann primär einen neuen FHEM-Befehl bereitstellen. Man spricht in so einem Fall nicht von einem Gerätemodul, sondern einem Befehlsmodul. Ein solches Befehlsmodul stellt nur einen einzelnen Befehl bereit, der dem Modulnamen entsprechen muss. Nur, wenn der Modulname dem Befehlsname entspricht, kann FHEM das Modul beim ersten Ausführen dieses unbekannten Befehls finden und nachladen.&lt;br /&gt;
&lt;br /&gt;
Der entsprechende Befehl wird dazu in der [[#X_Initialize|Initialize]]-Funktion im globalen Hash &amp;lt;code&amp;gt;[[DevelopmentModuleIntro#Wichtige_globale_Variablen_aus_fhem.pl|%cmds]]&amp;lt;/code&amp;gt; registriert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($$) {&lt;br /&gt;
&lt;br /&gt;
    $cmds{X} = { Fn           =&amp;gt; &amp;quot;CommandX&amp;quot;,&lt;br /&gt;
                 Hlp          =&amp;gt; &amp;quot;&amp;lt;argument1&amp;gt; [optional_argument2], print something very useful&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
                 # optionaler Filter für Clientmodule als regulärer Ausdruck&lt;br /&gt;
                 ClientFilter =&amp;gt; &amp;quot;FHEMWEB&amp;quot;&lt;br /&gt;
                };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit wird der neue Befehl &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; in FHEM registriert. Die Funktion mit dem Namen &amp;lt;code&amp;gt;CommandX&amp;lt;/code&amp;gt; setzt diesen Befehl innerhalb des Moduls um. Desweiteren wird eine kurze Aufrufsyntax mitgegeben, welche beim Aufruf des &amp;lt;code&amp;gt;help&amp;lt;/code&amp;gt;-Befehls dem Nutzer angezeigt wird um als Gedankenstütze zu dienen. Optional kann man mittels &amp;lt;code&amp;gt;ClientFilter&amp;lt;/code&amp;gt; (regulärer Ausdruck für Modulnamen) die Ausführbarkeit nur auf bestimmte Client-Module (wie FHEMWEB oder telnet) beschränken. &lt;br /&gt;
&lt;br /&gt;
Nun muss noch die Funktion &amp;lt;code&amp;gt;CommandX&amp;lt;/code&amp;gt; im Rahmen des Moduls implementiert werden, welche den Befehl &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; umsetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub CommandX($$)&lt;br /&gt;
{&lt;br /&gt;
 	my ($client_hash, $arguments) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	return $output;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dabei werden der Befehlsfunktion zwei Parameter übergeben. Zuerst die Hash-Referenz des aufrufenden Clients (sofern manuell ausgeführt, ansonsten &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt;) zwecks Rechteprüfung via [[allowed|allowed-Definitionen]]. Anschließend folgen die Aufrufparameter als zusammenhängende Zeichenkette. Die Trennung der einzelnen Argumente obligt der Funktion (bspw. via [[DevelopmentModuleAPI#parseParams|parseParams()]]). Als Funktionsrückgabewert wird eine Ausgabemeldung erwartet, die dem Nutzer angezeigt werden soll.&lt;br /&gt;
&lt;br /&gt;
== Pollen von Geräten ==&lt;br /&gt;
Wenn Geräte von sich aus keine Informationen senden sondern abgefragt werden müssen, kann man im Modul die Funktion [[DevelopmentModuleAPI#InternalTimer|InternalTimer()]] verwenden um einen Funktionsaufruf zu einem späteren Zeitpunkt durchführen zu können. Man übergibt dabei den Zeitpunkt für den nächsten Aufruf, den Namen der Funktion, die aufgerufen werden soll, sowie den zu übergebenden Parameter. Als zu übergebender Parameter wird üblicherweise der Hash der betroffenen Geräteinstanz verwendet. Damit hat die aufgerufene Funktion Zugriff auf alle wichtigen Daten der Geräteinstanz. Eventuell zusätzlich benötigte Werte können einfach als weitere Internals über den Hash zugänglich gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise könnte man für das Abfragen eines Geräts in der [[#X_Define|Define]]-Funktion den Timer folgendermaßen setzen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
InternalTimer(gettimeofday()+2, &amp;quot;X_GetUpdate&amp;quot;, $hash);	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alternativ kann man auch in der [[#X_Notify|Notify]]-Funktion auf das Event &amp;lt;code&amp;gt;global:INITIALIZED&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;global:REREADCFG&amp;lt;/code&amp;gt; reagieren und erst dort, den Timer anstoßen, sobald die Konfiguration komplett eingelesen wurde. Dies ist insbesondere notwendig, wenn man sicherstellen will, dass alle Attribute aus der Konfiguration gesetzt sind, sobald man einen Status-Update initiiert.&lt;br /&gt;
&lt;br /&gt;
In der Funktion &amp;lt;code&amp;gt;X_GetUpdate&amp;lt;/code&amp;gt; selbst wird dann der Timer neu gesetzt, so dass nach einem Intervall die Funktion erneut aufgerufen wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_GetUpdate($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
	my $name = $hash-&amp;gt;{NAME};&lt;br /&gt;
	Log3 $name, 4, &amp;quot;X: GetUpdate called ...&amp;quot;;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	# neuen Timer starten in einem konfigurierten Interval.&lt;br /&gt;
	InternalTimer(gettimeofday()+$hash-&amp;gt;{Interval}, &amp;quot;X_GetUpdate&amp;quot;, $hash);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Innerhalb der Funktion kann man nun das Gerät abfragen und die abgefragten Werte in Readings speichern. Falls das Abfragen der Werte jedoch zu einer Verzögerung und damit zu einer Blockade von FHEM führen kann, ist es möglich, in der GetUpdate-Funktion nur die Aufforderung zum Senden bestimmter Daten an das angeschlossene Gerät zu senden und dann das Lesen über die oben beschriebene [[#X_Read|Read]]-Funktion zu implementieren.&lt;br /&gt;
&lt;br /&gt;
Eine genaue Beschreibung der Timer-Funktion gibt es [[DevelopmentModuleAPI#Timer|hier im Wiki]]&lt;br /&gt;
&lt;br /&gt;
== Logging / Debugging ==&lt;br /&gt;
Um Innerhalb eines Moduls eine Log-Meldung in die FHEM-Logdatei zu schreiben, wird die Funktion [[DevelopmentModuleAPI#Log3|Log3()]] aufgerufen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
Log3 $name, 3, &amp;quot;X ($name) - Problem erkannt ...&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Eine genaue Beschreibung zu der Funktion inkl. Aufrufparameter findet man [[DevelopmentModuleAPI#Log3|hier]]. Es ist generell ratsam in der Logmeldung sowohl den Namen des eigenen Moduls zu schreiben, sowie den Namen des Geräts, welche diese Logmeldung produziert, da die Meldung, so wie sie ist, direkt in das Logfile wandert und es für User ohne diese Informationen schwierig ist, die Meldungen korrekt zuzuordnen.&lt;br /&gt;
&lt;br /&gt;
Die Funktion Log3() verwendet den Namen der Geräteinstanz um das &amp;lt;code&amp;gt;verbose&amp;lt;/code&amp;gt;-Attribut zu prüfen. In der Regel wird bei Modulfunktionen jedoch immer nur der Gerätehash &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; übergeben. Um den Namen der Definition zu ermitteln ist es daher notwendig sich diesen aus dem Hash extrahieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
my $name = $hash-&amp;gt;{NAME};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um für eine einzelne Geräteinstanz das Verbose-Level zu erhöhen, ohne gleich für das gesamte FHEM den globalen Verbose-Level zu erhöhen und damit alle Meldungen zu erzeugen, kann man den Befehl &lt;br /&gt;
&amp;lt;code&amp;gt;attr &amp;lt;NAME&amp;gt; verbose&amp;lt;/code&amp;gt; verwenden. Beispielsweise &amp;lt;code&amp;gt;attr Lichtschalter_Wohnzimmer verbose 5&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Logmeldungen sollten je nach Art und Wichtigkeit für den Nutzer in unterschiedlichen Loglevels erzeugt werden. Es gibt insgesamt 5 Stufen in denen geloggt werden kann. Standardmäßig steht der systemweite Loglevel (&amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt;-Attribut &amp;lt;code&amp;gt;verbose&amp;lt;/code&amp;gt;) auf der Stufe 3. Die Bedeutung der jeweiligen Stufen ist in der {{Link2CmdRef|Lang=de|Anker=verbose}} beschrieben.&lt;br /&gt;
&lt;br /&gt;
Während der Entwicklung eines Moduls kann man für eigene Debug-Zwecke auch die Funktion [[DevelopmentModuleAPI#Debug|Debug()]] verwenden um schnell und einfach Debug-Ausgaben in das Log zu schreiben. Diese sollten in der endgültigen Fassung jedoch nicht mehr vorhanden sein. Sie dienen ausschließlich zum Debugging während der Entwicklung.&lt;br /&gt;
&lt;br /&gt;
Eine genaue Beschreibung der Log-Funktion gibt es [[DevelopmentModuleAPI#Logging|hier im Wiki]].&lt;br /&gt;
&lt;br /&gt;
== Zweistufiges Modell für Module ==&lt;br /&gt;
[[Datei:Zweistufiges Modulkonzept.jpg|mini|rechts|Schematische Darstellung am Beispiel CUL]]&lt;br /&gt;
Es gibt viele Geräte, welche die Kommunikation mit weiteren Geräten mit tlw. unterschiedlichen Protokollen ermöglichen. Das typischste Beispiel bietet hier der [[CUL]], welcher via Funk mit verschiedenen Protokollen weitere Geräte ansprechen kann (z.B. Aktoren, Sensoren, ...). Hier bildet ein Gerät eine Brücke durch die weitere Geräte in FHEM zugänglich gemacht werden können. Dabei werden über einen Kommunikationsweg (z.B. serielle Schnittstelle, TCP, ...) beliebig viele Geräte gesteuert. Typische Beispiele dazu sind:&lt;br /&gt;
&lt;br /&gt;
* [[CUL]]: stellt Geräte mit verschiedenen Kommunikationsprotokollen via Funk bereit (u.a. [[FS20]], [[HomeMatic]], [[Funk-Heizkörperregler_Kurz-Bedienungsanleitung_FHT|FHT]], [[MAX]], ...)&lt;br /&gt;
* [[HMLAN]]: stellt HomeMatic Geräte via Funk bereit&lt;br /&gt;
* [[MAX#MAXLAN|MAXLAN]]: stellt [[MAX|MAX!]] Geräte via Funk bereit&lt;br /&gt;
* [[PanStamp#panStick.2FShield|panStamp]]: stellt weitere panStamp Geräte via Funk bereit&lt;br /&gt;
&lt;br /&gt;
Dabei wird die Kommunikation in 2 Stufen unterteilt:&lt;br /&gt;
* physisches Modul - z.B. 00_CUL.pm - zuständig für die physikalische Kommunikation mit der Hardware. Empfangene Daten müssen einem logischen Modul zugeordnet werden.&lt;br /&gt;
* logische Modul(e) - z.B. 10_FS20.pm - interpretiert protokollspezifische Nachrichten. Sendet protokollspezifische Daten über das physische Modul an die Hardware.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;physisches Modul&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das physische Modul öffnet die Datenverbindung zum Gerät (z.B. CUL) und verarbeitet sämtliche Daten. Es kümmert sich um den Erhalt der Verbindung (bsp. durch Keep-Alives) und konfiguriert das Gerät so, dass eine Kommunikation mit allen weiteren Geräten möglich ist (bsp. Frequenz, Modulation, Kanal, etc.).&lt;br /&gt;
&lt;br /&gt;
Empfangene Nutzdaten werden als Zeichenkette über die Funktion [[DevelopmentModuleAPI#Dispatch|Dispatch()]] an logische Module weitergegeben.&lt;br /&gt;
&lt;br /&gt;
Das Modul stellt eine [[#Die_Match-Liste|Match-Liste]] bereit, anhand FHEM die Nachricht einem Modul zuordnen kann, sofern dieses noch nicht geladen sein sollte. Die Match-Liste enthält eine Liste von regulären Ausdrücken und ordnet diese einem Modul zu. Wenn eine Nachricht auf einen solchen regulären Ausdruck passt und das Modul noch nicht geladen ist, lädt FHEM dieses automatisch nach, zwecks Verarbeitung der Nachricht. &lt;br /&gt;
&lt;br /&gt;
Anhand einer bereitgestellten [[#Die_Client-Liste|Client-Liste]] (Auflistung von logischen Modulen) kann FHEM feststellen, welche logischen Module mit dem physischen Modul kommunizieren können. Nur die hier aufgelisteten, logischen Module werden beim Aufruf von [[DevelopmentModuleAPI#Dispatch|Dispatch()]] angesprochen.&lt;br /&gt;
&lt;br /&gt;
Das Modul stellt eine [[#X_Write|Write]]-Funktion zur Verfügung, über die logische Module Daten in beliebiger Form an die Hardware übertragen können. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;logisches Modul&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das logische Modul interpretiert die via Dispatch() übergebene Nachricht (Zeichenkette) durch eine bereitgestellte [[#X_Parse|Parse]]-Funktion und erzeugt entsprechende Readings/Events. Es stellt über &amp;lt;code&amp;gt;set&amp;lt;/code&amp;gt;-/&amp;lt;code&amp;gt;get&amp;lt;/code&amp;gt;-Kommandos Steuerungsmöglichkeiten dem Nutzer zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Es stellt FHEM einen [[#Der_Match-Ausdruck|Match-Ausdruck]] (regulärer Ausdruck) zur Verfügung anhand [[DevelopmentModuleAPI#Dispatch|Dispatch()]] ermitteln kann, ob die Nachricht durch das logische Modul verarbeitet werden kann. Nur Nachrichten, welche auf diesen Ausdruck passen, werden an das logische Modul weitergegeben (Aufruf [[#X_Parse|Parse]]-Funktion).&lt;br /&gt;
&lt;br /&gt;
=== Die Client-Liste ===&lt;br /&gt;
&lt;br /&gt;
Die Client-Liste ist eine Auflistung von Modulnamen (genauer: regulären Ausdrücken die auf Modulnamen passen) die in einem physischen Modul gesetzt ist. Damit wird definiert, mit welchen logischen Modulen das physikalische Modul  kommunizieren kann. &lt;br /&gt;
&lt;br /&gt;
Eine Client-Liste ist eine Zeichenkette, welche aus allen logischen Modulnamen besteht. Die einzelnen Namen werden durch einen Doppelpunkt getrennt. Anstatt kompletter Modulnamen können auch reguläre Ausdrücke verwendet werden, die auf mehrere Modulnamen passen (z.B. &amp;lt;code&amp;gt;CUL_.*&amp;lt;/code&amp;gt; um die logischen Module CUL_HM, CUL_MAX, etc. zu verwenden).&lt;br /&gt;
&lt;br /&gt;
Bsp.: Die Client-Liste von dem Modul CUL lautet daher wie folgt:&amp;lt;syntaxhighlight&amp;gt;&lt;br /&gt;
FS20:FHT.*:KS300:USF1000:BS:HMS:CUL_EM:CUL_WS:CUL_FHTTK:CUL_HOERMANN:ESA2000:CUL_IR:CUL_TX:Revolt:IT:UNIRoll:SOMFY:STACKABLE_CC:CUL_RFR:CUL_TCM97001:CUL_REDIRECT&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Alle hier aufgelisteten Module können über das Modul CUL Daten empfangen bzw. senden.&lt;br /&gt;
&lt;br /&gt;
Die Client-Liste hat generell folgende Funktion:&lt;br /&gt;
* Die Funktion [[DevelopmentModuleAPI#Dispatch|Dispatch()]] prüft nur Module, welche in der Client-Liste enthalten sind, ob diese die Nachricht verarbeiten können (Prüfung via [[#Der Match-Ausdruck|Match-Ausdruck]])&lt;br /&gt;
* Die Funktion [[DevelopmentModuleAPI#AssignIoPort|AssignIoPort()]] prüft anhand sämtlicher Client-Listen in FHEM, welches IO-Gerät für ein logisches Gerät nutzbar ist.&lt;br /&gt;
&lt;br /&gt;
Üblicherweise wird die Client-Liste in der [[#X_Initialize|Initialize]]-Funktion im Modul-Hash gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
	...&lt;br /&gt;
	$hash-&amp;gt;{Clients} = &amp;quot;FS20:KS300:FHT.*&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man kann die Client-Liste jedoch auch pro physikalisches Gerät setzen. Eine gesetzte Client-Liste in einem Gerät hat immer Vorrang vor der Liste im Modul-Hash. Eine gerätespezifische Client-Liste wird dann verwendet, wenn bspw. ein Gerät je nach Konfiguration nur bestimmte logische Module bedienen kann. Bspw. kann ein CUL je nach RF-Einstellungen FS20, uvm. oder nur HomeMatic bedienen. In einem solchen Fall wird die Client-Liste im Geräte-Hash gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $def ) = @_;&lt;br /&gt;
	...&lt;br /&gt;
	$hash-&amp;gt;{Clients} = &amp;quot;CUL_HM&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In vielen Modulen, welche nach dem zweistufigem Konzept arbeiten, beginnt und endet die Client-Liste mit einem Doppelpunkt. Dies ist ein historisches Überbleibsel, da der Prüfmechanismus die Client-Liste früher auf das Vorhandensein von &amp;lt;code&amp;gt;&#039;&#039;&#039;&amp;lt;u&amp;gt;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;:&amp;lt;/font&amp;gt;&amp;lt;/u&amp;gt;&#039;&#039;&#039;&amp;amp;lt;Modulname&amp;amp;gt;&#039;&#039;&#039;&amp;lt;u&amp;gt;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;:&amp;lt;/font&amp;gt;&amp;lt;/u&amp;gt;&#039;&#039;&#039;&amp;lt;/code&amp;gt; prüfte. Dies ist nun nicht mehr notwendig. Die einzelnen Modulnamen müssen lediglich durch einen Doppelpunkt getrennt werden.&lt;br /&gt;
&lt;br /&gt;
=== Die Match-Liste ===&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;u&amp;gt;&#039;&#039;&#039;ACHTUNG&#039;&#039;&#039;:&amp;lt;/u&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
Sämtliche regulären Ausdrücke in der Match-Liste werden &amp;quot;case insensitive&amp;quot; überprüft. Das bedeutet, dass Groß-/Kleinschreibung nicht berücksichtigt wird.&lt;br /&gt;
&lt;br /&gt;
Um dennoch in einem regulären Ausdruck auf Groß-/Kleinschreibung zu prüfen, kann man dieses mit dem Modifizierer &amp;lt;code&amp;gt;(?-i)&amp;lt;/code&amp;gt; wieder aktivieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
my %matchListFHEMduino = (&lt;br /&gt;
    ....&lt;br /&gt;
    &amp;quot;5:FHEMduino_PT2262&amp;quot;   =&amp;gt; &amp;quot;^(?-i)IR.*\$&amp;quot;,&lt;br /&gt;
    ....&lt;br /&gt;
    &amp;quot;13:IT&amp;quot;                =&amp;gt; &amp;quot;^(?-i)i......\$&amp;quot;,&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Siehe dazu Forumsbeitrag: {{Link2Forum|Topic=33422}}&lt;br /&gt;
}}&lt;br /&gt;
Die Match-Liste ordnet eine Nachrichtensyntax (regulärer Ausdruck) einem Modulnamen zu und wird in einem physikalischen Modul gesetzt. Sollte eine Nachricht vom physikalischen Gerät empfangen werden, die durch kein geladenes Modul verarbeitet werden kann ([[DevelopmentModuleAPI#Dispatch|Dispatch()]] prüft nur alle bisher geladenen Module aus der [[#Die Client-Liste|Client-Liste]]), so wird über die Match-Liste geprüft, welches Modul diese Nachricht verarbeiten kann. Dieses Modul wird anschließend geladen und die Nachricht durch dieses direkt durch Aufruf der [[#X_Parse|Parse]]-Funktion verarbeitet. In dieser Liste findet mittels regulärem Ausdruck eine Zuordnung der Nachrichtenstruktur zum verarbeitenden logischen Modul statt.&lt;br /&gt;
&lt;br /&gt;
Diese Liste wird ausschließlich in der [[DevelopmentModuleAPI#Dispatch|Dispatch()]]-Funktion verwendet. Sollte keine passendes Modul, welches bereits geladen ist, zur Verarbeitung einer Nachricht gefunden werden, so wird mithilfe der Match-Liste aufgrund der vorliegenden Nachricht das entsprechende Modul ermittelt. Dieses Modul wird dann direkt geladen und die Nachricht wird via [[#X_Parse|Parse]]-Funktion verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Die Match-Liste ist eine Zuordnung von einem Sortierpräfix + Modulname zu einem regulären Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;1:FS20&amp;quot;  =&amp;gt; &amp;quot;^81..(04|0c)..0101a001&amp;quot;,&lt;br /&gt;
    &amp;quot;2:KS300&amp;quot; =&amp;gt; &amp;quot;^810d04..4027a001&amp;quot;,&lt;br /&gt;
    &amp;quot;3:FHT&amp;quot;   =&amp;gt; &amp;quot;^81..(04|09|0d)..(0909a001|83098301|c409c401)..&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Sortierpräfix (&amp;lt;code&amp;gt;&amp;lt;u&amp;gt;1:&amp;lt;/u&amp;gt;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;FS20&amp;lt;/font&amp;gt;&amp;lt;/code&amp;gt;) dient als Sortierhilfe um so die Reihenfolge der Prüfung festzulegen. Bei der Prüfung wird die Match-Liste mittels sort() nach dem Schlüssel (Sortierpräfix + Modulname) sortiert und die regulären Ausdrücke werden dann nacheinander getestet. Daher sollten die präzisesten Ausdrücke immer zuerst getestet werden, sofern es weniger präzise Ausdrücke in der Match-Liste gibt. Dabei ist zu beachten, dass der Sortierpräfix nicht nach numerischen Regeln sortiert wird, sondern zeichenbasierend.&lt;br /&gt;
&lt;br /&gt;
Üblicherweise wird die Match-Liste in der [[#X_Initialize|Initialize]]-Funktion im Modul-Hash gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
   my ($hash) = @_;&lt;br /&gt;
&lt;br /&gt;
   ...&lt;br /&gt;
&lt;br /&gt;
   $hash-&amp;gt;{MatchList} = { &amp;quot;1:FS20&amp;quot;      =&amp;gt; &amp;quot;^81..(04|0c)..0101a001&amp;quot;,&lt;br /&gt;
                          &amp;quot;2:KS300&amp;quot;     =&amp;gt; &amp;quot;^810d04..4027a001&amp;quot;,&lt;br /&gt;
                          &amp;quot;3:FHT&amp;quot;       =&amp;gt; &amp;quot;^81..(04|09|0d)..(0909a001|83098301|c409c401)..&amp;quot; };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man kann die Match-Liste, ähnlich wie bei der Client-Liste, auch pro physikalisches Gerät setzen. Dabei hat auch hier die Match-Liste eines Gerätes immer Vorrang vor der Match-Liste aus dem Modul-Hash:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$)&lt;br /&gt;
{&lt;br /&gt;
   my ($hash, $def) = @_;&lt;br /&gt;
&lt;br /&gt;
   ...&lt;br /&gt;
&lt;br /&gt;
   $hash-&amp;gt;{MatchList} = { &amp;quot;1:CUL_HM&amp;quot; =&amp;gt; &amp;quot;^A....................&amp;quot; };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Der Match-Ausdruck ===&lt;br /&gt;
&lt;br /&gt;
Ein Match-Ausdruck wird in einem logischen Modul gesetzt und dient der Prüfung, ob eine Nachricht durch das eigene Modul via [[#X_Parse|Parse]]-Funktion verarbeitet werden kann. Es handelt sich hierbei um einen einzelnen regulären Ausdruck, den FHEM innerhalb der [[DevelopmentModuleAPI#Dispatch|Dispatch()]]-Funktion prüft. Nur wenn eine Nachricht via Dispatch() auf diesen Audruck matcht, wird die Parse-Funktion des eigenen Moduls aufgerufen um die Nachricht zu verarbeiten. &lt;br /&gt;
&lt;br /&gt;
Der Hintergrund, warum man den Aufruf mit einem solchen Ausdruck vorher abprüft, liegt in der Möglichkeit, dass ein physikalisches Modul mehrere unterschiedliche logische Module ansprechen kann. So kann FHEM jedes geladene Modul durch diesen Match-Ausdruck prüfen, ob es diese Nachricht verarbeiten kann. Erst, wenn alle geladenen Module, aufgrund einer Prüfung des Ausdrucks, die Nachricht nicht verarbeiten können, wird via [[#Die_Match-Liste|Match-Liste]] ermittelt, welches Modul geladen werden muss um die Nachricht zu verarbeiten. &lt;br /&gt;
&lt;br /&gt;
Der Match-Ausdruck wird in der [[#X_Initialize|Initialize]]-Funktion zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	# Dieses Modul verarbeitet FS20 Nachrichten&lt;br /&gt;
	$hash-&amp;gt;{Match} = &amp;quot;^81..(04|0c)..0101a001&amp;quot;; &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Die vollständige Implementierung ===&lt;br /&gt;
&lt;br /&gt;
Hier nun eine Zusammenfassung beim zweistufigen Modulkonzept in der jeweiligen Stufe implementiert werden muss, damit die Kommunikation funktioniert.&lt;br /&gt;
&lt;br /&gt;
==== physisches Modul ====&lt;br /&gt;
&lt;br /&gt;
Das physische Modul, welches als Kommunikationsbrücke zwischen der Hardware und logischen Modulen fungieren wird, sollte mindestens folgende Funktionen implementieren:&lt;br /&gt;
&lt;br /&gt;
* [[#X_Initialize|Initialize]]-Funktion - Zum Registrieren des Moduls in FHEM.&lt;br /&gt;
* [[#X_Define|Define]]-Funktion - Zum öffnen der Datenverbindung zur Hardware (IP-Adresse/serielle Schnittstelle/...).&lt;br /&gt;
* [[#X_Read|Read]]-Funktion - Zum Lesen von Daten, welche die Hardware übermittelt.&lt;br /&gt;
* [[#X_Read|Ready]]-Funktion - Zum Wiederaufbau der Verbindung bei Verbindungsabbruch, bzw. Prüfung auf lesbare Daten bei serieller Schnittstelle unter Windows.&lt;br /&gt;
* [[#X_Write|Write]]-Funktion - Zum Senden von Daten, welche logische Module via [[DevelopmentModuleAPI#IOWrite|IOWrite()]] an die Hardware übertragen möchten.&lt;br /&gt;
* [[#X_Undef|Undef]]-Funktion - Schließen der Verbindung zur Hardware beim Löschen via &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt;.&lt;br /&gt;
* [[#X_Shutdown|Shutdown]]-Funktion - Schließen der Verbindung zur Hardware beim Stopp von FHEM via &amp;lt;code&amp;gt;shutdown&amp;lt;/code&amp;gt;.&lt;br /&gt;
* [[#X_DelayedShutdown | DelayedShutdown]]-Funktion - Verzögertes beenden zum Schließen der Verbindung zur Hardware beim Stopp von FHEM via &amp;lt;code&amp;gt;shutdown&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Desweiteren müssen in der [[#X_Initialize|Initialize]]-Funktion folgende Daten bereitgestellt werden:&lt;br /&gt;
&lt;br /&gt;
* [[#Die_Client-Liste|Client-Liste]] - Auflistung aller logischen Module, die über dieses Modul kommunizieren können&lt;br /&gt;
* [[#Die_Match-Liste|Match-Liste]] - Zuordnung von Nachrichtensyntax zu Modul zwecks Autoload-Funktionalität.&lt;br /&gt;
&lt;br /&gt;
==== logisches Modul ====&lt;br /&gt;
&lt;br /&gt;
Das logische Modul, bildet ein einzelnes Gerät ab, über das mit einem physikalisches Modul kommuniziert werden kann. Es sollte mindestens folgende Funktionen implementieren:&lt;br /&gt;
&lt;br /&gt;
* [[#X_Initialize|Initialize]]-Funktion - Zum Registrieren des Moduls in FHEM.&lt;br /&gt;
* [[#X_Define|Define]]-Funktion - Speichern des Definition Pointers (siehe [[#X_Parse|Parse-Funktion]])&lt;br /&gt;
* [[#X_Parse|Parse]]-Funktion - Zum Lesen von Daten, welche die Hardware übermittelt.&lt;br /&gt;
* [[#X_Undef|Undef]]-Funktion - Löschen des Definition Pointers beim Löschen via &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Desweiteren müssen in der [[#X_Initialize|Initialize]]-Funktion folgende Daten bereitgestellt werden:&lt;br /&gt;
&lt;br /&gt;
* [[#Der_Match-Ausdruck|Match-Ausdruck]] - Prüfausdruck, ob eine Nachricht durch dieses Modul verarbeitet werden kann.&lt;br /&gt;
&lt;br /&gt;
=== Kommunikation von der Hardware bis zu den logischen Modulen ===&lt;br /&gt;
&lt;br /&gt;
Die Gerätedefinition des physischen Moduls öffnet eine Verbindung zur Hardware (z.B. via [[DevIo]]). Die [[#X_Read|Read]]-Funktion wird bei anstehenden Daten aus der Hauptschleife von fhem.pl aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Die Read-Funktion stellt dabei sicher, dass die Daten&lt;br /&gt;
* komplett (in der Regel über einen internen Puffer in &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;) und&lt;br /&gt;
* korrekt (z.B. via Prüfung mittels regulärem Ausdruck)&lt;br /&gt;
sind und ruft die globale Funktion [[DevelopmentModuleAPI#Dispatch|Dispatch()]] mit einer kompletten Nachricht auf.&lt;br /&gt;
&lt;br /&gt;
Die Funktion Dispatch() prüft alle geladenen Module aus der [[#Die_Client-Liste|Client-Liste]] des physikalischen Moduls nach möglichen logischen Modulen zur Verarbeitung. Alle zum Zeitpunkt geladenen Module, die in der Client-Liste aufgeführt sind, werden über den [[#Der_Match-Ausdruck|Match-Ausdruck]] geprüft, ob sie mit der Nachricht etwas anfangen können. Sollte bei einem logischen Modul der Match-Ausdruck passen, so wird die entsprechende [[#X_Parse|Parse]]-Funktion des logischen Moduls aufgerufen. Sofern keine passendes Modul gefunden wurde, um die Nachricht zu verarbeiten, wird in der [[#Die_Match-Liste|Match-Liste]] im Geräte- bzw. Modul-Hash der physischen Gerätedefinition nach dem passenden Modul gesucht. Sollte es darin ein Modul geben, was diese Art von Nachricht verarbeiten kann, so wird versucht dieses Modul zu laden um nun die Nachricht via Parse-Funktion zu verarbeiten. Es erfolgt in diesem Fall keine Vorprüfung durch den Match-Ausdruck.&lt;br /&gt;
&lt;br /&gt;
Durch Dispatch() wird nun die [[#X_Parse|Parse]]-Funktion des gefundenen logischen Moduls aufgerufen. Diese&lt;br /&gt;
* interpretiert die übergebene Nachricht,&lt;br /&gt;
* versucht eine existierende Gerätedefinition in FHEM zu finden (z.B. mittels Definition Pointer), für welche die Nachricht addressiert ist,&lt;br /&gt;
* setzt alle [[#Readings|Readings]] für die gefundene Gerätedefinition via [[DevelopmentModuleAPI#Readings_.2F_Events|readings*update]]()-Funktionen,&lt;br /&gt;
* gibt den Namen der logischen Definition zurück, welche die Nachricht verarbeitet hat.&lt;br /&gt;
&lt;br /&gt;
Sollte keine passende Gerätedefinition für die entsprechende Nachricht existieren (Adresse/ID/Kanal/...), wird der Gerätename &amp;quot;UNDEFINED&amp;quot; inkl. einem passenden &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Statement zurückgegeben, um die Definition durch [[autocreate]] erzeugen zu lassen.&lt;br /&gt;
&lt;br /&gt;
Es findet während der Verarbeitung einer Nachricht durch Dispatch()/Parse-Funktion keine sofortige Eventverarbeitung (via [[DevelopmentModuleAPI#Dispatch|DoTrigger()]]) statt, wenn die [[DevelopmentModuleAPI#Readings_.2F_Events|readings*update]]()-Funktionen verwendet werden.&lt;br /&gt;
(Im Gegensatz zum direkten Aufrufen der readings*update Funktionen ohne vorhergehendes Dispatch() )&lt;br /&gt;
&lt;br /&gt;
Die Funktion Dispatch() triggert das Event-Handling für das von der Parse-Funktion zurückgegebene logische Device selbstständig nach Abschluss der Parse-Funktion.&lt;br /&gt;
&lt;br /&gt;
Optional führt die Funktion Dispatch() eine Überprüfung auf Nachrichtenduplikate beim Einsatz von mehreren IO-Geräten durch. Dazu wird eine implementierte [[#X_Fingerprint|Fingerprint]]-Funktion im physischen oder logischen Modul benötigt. Sollte der Fingerprint einer Nachricht innerhalb einer bestimmten Zeit (globales Attribut &amp;lt;code&amp;gt;dupTimeout&amp;lt;/code&amp;gt;, standardmäßig 500ms) bereits empfangen worden sein, so wird die Nachricht verworfen. Dies ist insbesondere bei funkbasierter Hardware notwendig, wenn mehrere Empfänger die selbe Nachricht empfangen.&lt;br /&gt;
&lt;br /&gt;
=== Kommunikation von den logischen Modulen bis zur Hardware ===&lt;br /&gt;
&lt;br /&gt;
Um von einem logischen Modul eine Nachricht an die Hardware senden zu können, muss zunächst im logischen Gerät ein passenden IO-Gerät ausgewählt sein. Dazu muss die Funktion [[DevelopmentModuleAPI#AssignIoPort|AssignIoPort()]] ein entsprechendes IO-Gerät auswählen und in &amp;lt;code&amp;gt;$hash-&amp;gt;{IODev}&amp;lt;/code&amp;gt; setzen. Dieser Aufruf wird üblicherweise in der [[#X_Define|Define]]-Funktion des logischen Moduls ausgeführt. Erst, wenn ein IO-Gerät ausgewählt wurde, können Daten über das physikalische Gerät an die Hardware übermittelt werden.&lt;br /&gt;
&lt;br /&gt;
Zum Senden von Daten ruft das logische Modul die Funktion [[DevelopmentModuleAPI#IOWrite|IOWrite()]] samt Daten auf. Diese ruft für das entsprechende IO-Gerät die [[#X_Write|Write]]-Funktion auf und übergibt die Daten zum Schreiben an das physikalische Modul. Die Write-Funktion kümmert sich nun um die Übertragung der Daten an die Hardware. &lt;br /&gt;
&lt;br /&gt;
Keine direkten Zugriffe zwischen dem logischen und dem physischen Gerät gibt (d.h. keine direkten Aufrufe von Funktionen, kein direktes Überprüfen von &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;-Inhalten, ...), so können die Module hintereinander geschaltet werden (z.B. für Routerfunktionen wie bei der [[RFR_CUL|RFR]]-Funktionalität) oder mittels [[FHEM2FHEM]] im RAW-Modus zwei FHEM-Installationen verbunden werden und die logischen Geräte können dennoch kommunizieren.&lt;br /&gt;
&lt;br /&gt;
=== Automatisches Anlegen von logischen Gerätedefinitionen (autocreate) ===&lt;br /&gt;
&lt;br /&gt;
Das logische Modul kann im Rahmen der [[#X_Parse|Parse]]-Funktion eine neue Gerätedefinition anlegen, sofern eine passende Definition nicht existieren sollte. Die Parse-Funktion gibt generell den Namen der logischen Gerätedefinition zurück, für welche die Nachricht verarbeitet wurde. Sollte keine passende Definition gefunden werden, so muss die Parse-Funktion folgenden Rückgabewert liefern (zusammenhängende Zeichenkette):&lt;br /&gt;
&lt;br /&gt;
 UNDEFINED &#039;&#039;&amp;amp;lt;Namensvorschlag&amp;amp;gt;&#039;&#039; &#039;&#039;&amp;amp;lt;Modulname&amp;amp;gt;&#039;&#039; &#039;&#039;&amp;amp;lt;Define-Parameter...&amp;amp;gt;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sollte also bspw. im Rahmen der Parse-Funktion zu Modul X eine Nachricht nicht einer existierenden Gerätedefinition zugeordnet werden können, so muss ein Namensvorschlag erstellt werden der eine eindeutige Komponente wie bspw. eine Adresse/ID/Kanal-Nr enthält. In der Regel wird hier immer der Modulname zusammen mit der eindeutigen Komponente, durch einen Unterstrich getrennt, verwendet (Bsp: &amp;lt;code&amp;gt;X_4834&amp;lt;/code&amp;gt;). Der Modulname ist in der Regel immer der, des eigenen Moduls. In besonderen Fällen kann man hier auch einen abweichenden Modulnamen angeben. Dies wird bspw. bei den [[PanStamp#FHEM-Module.2FDevice_Definition_Files|SWAP-Modulen]] eingesetzt. Als Define-Parameter müssen alle notwendigen Parameter angegeben werden, die beim Aufruf des &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehls notwendig sind, damit eine neu angelegte Gerätedefinition Nachrichten zu dieser eindeutigen Adresse Daten verarbeitet. Dazu muss mind. die eindeutige Adresse mitgegeben werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel für FS20:&lt;br /&gt;
&lt;br /&gt;
 UNDEFINED FS20_0ae42f8 FS20 0ae42 f8&lt;br /&gt;
&lt;br /&gt;
Sobald [[DevelopmentModuleAPI#Dispatch|Dispatch()]] einen solchen Rückgabewert von einer [[#X_Parse|Parse]]-Funktion erhält, wird diese Zeichenkette so wie sie ist via [[DevelopmentModuleAPI#DoTrigger|DoTrigger()]] als Event für die Definition &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt; getriggert.&lt;br /&gt;
&lt;br /&gt;
Sofern der Nutzer das Modul [[autocreate]] verwendet (definiert hat), kümmert sich dieses nun um das Anlegen einer entsprechenden Gerätedefinition. Es lauscht dabei auf generierte Events der Definition &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt; via [[#X_Notify|Notify]]-Funktion. Der Nutzer kann dabei das Verhalten von autocreate durch entsprechende Parameter beeinflussen.&lt;br /&gt;
&lt;br /&gt;
Das Modul, für welches autocreate eine neue Definition anlegen möchte, kann das Verhalten durch entsprechende Parameter im Modul-Hash beeinflussen. Dabei gilt, dass gesetzte Attribute durch den Nutzer generell Vorrang haben. Die entsprechenden Parameter werden dabei im Rahmen der [[#X_Initialize|Initialize]]-Funktion im Modul-Hash gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
 &lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	$hash-&amp;gt;{AutoCreate} = {&amp;quot;X_.*&amp;quot;  =&amp;gt; { ATTR   =&amp;gt; &amp;quot;event-on-change-reading:.* event-min-interval:.*:300&amp;quot;,&lt;br /&gt;
	                                    FILTER =&amp;gt; &amp;quot;%NAME&amp;quot;,&lt;br /&gt;
	                                    GPLOT  =&amp;gt; &amp;quot;temp4hum4:Temp/Hum,&amp;quot;,&lt;br /&gt;
	                                    autocreateThreshold =&amp;gt; &amp;quot;2:140&amp;quot;&lt;br /&gt;
					  }&lt;br /&gt;
	                      };&lt;br /&gt;
			    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei wird unterhalb von &amp;lt;code&amp;gt;$hash-&amp;gt;{AutoCreate}&amp;lt;/code&amp;gt; eine Liste angelegt, wo einem regulären Ausdruck für einen anzulegenden Definitionsnamen entsprechende Optionen zugeordnet werden. Sobald durch autocreate eine Gerätedefintion angelegt wird, auf den ein hier gelisteter Ausdruck matcht, so werden die zugeordneten Optionen berücksichtigt.&lt;br /&gt;
&lt;br /&gt;
Hier eine Auflistung aller möglichen Optionen und ihrer Bedeutung:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Optionsname !! Beispiel !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;ATTR&amp;lt;/code&amp;gt;|| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; |  &amp;lt;code&amp;gt;&amp;quot;event-on-change-reading:.* event-min-interval:.*:300&amp;quot;&amp;lt;/code&amp;gt; || Eine Auflistung von Attributen, die nach dem Anlegen einer Definition zusätzlich gesetzt werden. Es handelt sich hierbei um eine Leerzeichen-separierte Liste von Doppelpunkt-getrennten Tupels mit Attributname und -wert.&lt;br /&gt;
&lt;br /&gt;
Für das dargestellte Beispiel bedeutet dies, dass nach dem Anlegen der Definition folgende FHEM-Befehle zusätzlich ausgeführt werden:&lt;br /&gt;
&lt;br /&gt;
 attr &#039;&#039;&amp;amp;lt;Name&amp;amp;gt;&#039;&#039; event-on-change-reading .*&lt;br /&gt;
 attr &#039;&#039;&amp;amp;lt;Name&amp;amp;gt;&#039;&#039; event-min-interval .*:300&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;FILTER&amp;lt;/code&amp;gt; || style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; |  &amp;lt;code&amp;gt;&amp;quot;%NAME&amp;quot;&amp;lt;/code&amp;gt;|| Sofern in der autocreate-Definiton das Attribut &amp;lt;code&amp;gt;filelog&amp;lt;/code&amp;gt; entsprechend durch den Nutzer gesetzt ist, wird eine zugehörige FileLog-Definition angelegt. Diese Option setzt den dabei benutzten Filter-Regexp, der beim Anlegen der FileLog-Definition gesetzt wird. &lt;br /&gt;
&lt;br /&gt;
Dabei werden folgende Platzhalter durch die entsprechenden Werte der neu angelegten Gerätedefinition ersetzt:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;%NAME&amp;lt;/code&amp;gt; - wird ersetzt durch den Definitionsnamen&lt;br /&gt;
* &amp;lt;code&amp;gt;%TYPE&amp;lt;/code&amp;gt; - wird ersetzt durch den Modulnamen&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; |  &amp;lt;code&amp;gt;GPLOT&amp;lt;/code&amp;gt; || style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&amp;quot;temp4hum4:Temp/Hum,&amp;quot;&amp;lt;/code&amp;gt; || Sofern eine FileLog-Definition angelegt wurde, kann man weiterführend dazu eine passende SVG-Definition erzeugen um Daten aus dem erzeugten FileLog zu visualisieren. Ein typischer Fall sind hierbei Temperatursensoren, wo es sinnvoll sein kann, einen passenden SVG-Plot mit Temperatur/Luftfeuchtigkeit direkt anzulegen.&lt;br /&gt;
&lt;br /&gt;
Es handelt sich hierbei um eine kommaseparierte Auflistung von gplot-Dateinamen und optionalen Label-Texten durch einen Doppelpunkt getrennt. Im genannten Beispiel entspricht &amp;lt;code&amp;gt;temp4hum4&amp;lt;/code&amp;gt; der zu verwendenden GnuPlot-Datei und &amp;lt;code&amp;gt;Temp/Hum&amp;lt;/code&amp;gt; dem zu verwendenden Label ([[SVG]] Attribut &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt;). Das Label wird auch durch FileLog verwendet als Link-Text zum entsprechenden SVG Plot. Alternativ kann auch nur die entsprechende GnuPlot-Datei anegeben werden ohne Label. Für jede angegebene GnuPlot-Datei wird anschließend eine entsprechende SVG-Definition erzeugt mit der vorher erzeugten FileLog-Definition als Datenquelle.&lt;br /&gt;
&lt;br /&gt;
Der gesamte Inhalt der &amp;lt;code&amp;gt;GPLOT&amp;lt;/code&amp;gt;-Option wird beim Anlegen einer FileLog-Definition dem Attribut &amp;lt;code&amp;gt;logtype&amp;lt;/code&amp;gt; als Wert plus dem Text &amp;lt;code&amp;gt;text&amp;lt;/code&amp;gt; zugewiesen. Daher muss der Inhalt der Option &amp;lt;code&amp;gt;GPLOT&amp;lt;/code&amp;gt; immer mit einem Komma enden. &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;autocreateThreshold&amp;lt;/code&amp;gt; || style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&amp;quot;2:10&amp;quot;&amp;lt;/code&amp;gt; || Definiert, wie viele Aufrufe (im Bsp: &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;) von autocreate innerhalb welcher Zeit (im Bsp: &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt; Sek.) stattfinden müssen, bevor die Gerätedefinition tatsächlich durch autocreate angelegt wird. Dadurch kann das ungewollte Anlegen von Geräten verhindert werden die tatsächlich nicht in Echt existieren. Aufgrund von Funkstörungen kann es durchaus zum ungewollten Anlegen einer Definition kommen. Diese Funktion lässt eine Definition erst zu wenn innerhalb einer vorgegeben Zeit eine Mindestzahl an Nachrichten eintrifft.&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl stellt dabei die Mindestanzahl an Nachrichten dar. Die Zweite Zahl stellt die Zeit in Sekunden dar, in der die Mindestanzahl an Nachrichten erreicht werden muss um eine entsprechende Gerätedefinition anzulegen. &lt;br /&gt;
&lt;br /&gt;
Sofern diese Option nicht gesetzt ist, wird standardmäßig &amp;lt;code&amp;gt;2:60&amp;lt;/code&amp;gt; verwendet.&lt;br /&gt;
&lt;br /&gt;
Diese Option kann durch den Anwender über das Attribut &amp;lt;code&amp;gt;autocreateThreshold&amp;lt;/code&amp;gt; übersteuert werden.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;noAutocreatedFilelog&amp;lt;/code&amp;gt;|| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; |  &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;|| Flag. Sofern gesetzt, wird keine FileLog- und ggf. SVG-Definition erzeugt. Selbst wenn der Nutzer durch entsprechende Attribute das Anlegen wünscht. Diese Option ist sinnvoll für Module bzw. Geräte die keine Readings erzeugen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Ergänzende Hinweise ==&lt;br /&gt;
Die Wahl der vorangestellten Nummer für den Dateinamen eines neuen Moduls hat keine Bedeutung mehr, es sei denn die Nummer ist 99. Module, die mit 99_ beginnen, werden von FHEM automatisch geladen. Module mit einer anderen Nummer nur wenn ein &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl dafür sorgt, dass das Modul geladen wird.&lt;br /&gt;
&lt;br /&gt;
Wenn ein Modul Initialisierungsdaten benötigt, sollten diese im Modul selbst enthalten sein. Eine zusätzliche Datei oder sogar ein Unterverzeichnis mit mehreren Dateien ist bei FHEM nicht üblich und sollte bei Modulen, die mit FHEM ausgeliefert werden nur in Rücksprache mit Rudolf König angelegt werden, da sie sonst bei einem Update nicht verteilt werden.&lt;br /&gt;
&lt;br /&gt;
== Weitere Informationen ==&lt;br /&gt;
Wenn man weitere Details wissen möchte, ist ein erster sinnvoller Schritt ein Blick in die Datei fhem.pl. Dort sieht man im Perl-Code wie die Module aufgerufen werden, was vorher passiert und was danach. Am Anfang der Datei (ca. ab Zeile 130) findet man beispielsweise eine Liste der globalen Variablen, die den Modulen zur Verfügung stehen sowie Details zu den wichtigen Hashes %modules und %defs. Wer mit Perl noch nicht so gut klar kommt, dem hilft eventuell ein Blick auf die Perldoc Website[http://perldoc.perl.org/] oder in das Perl-Buch seiner Wahl. Auch die FHEM {{Link2CmdRef}} sollte nicht unterschätzt werden. Es stehen oft mehr interessante Details auch für Modulentwickler darin als man zunächst vermuten könnte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Hello World&amp;quot; Beispiel ==&lt;br /&gt;
&lt;br /&gt;
98_Hello.pm&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
package main;&lt;br /&gt;
use strict;&lt;br /&gt;
use warnings;&lt;br /&gt;
&lt;br /&gt;
my %Hello_gets = (&lt;br /&gt;
	&amp;quot;whatyouwant&amp;quot;	=&amp;gt; &amp;quot;can&#039;t&amp;quot;,&lt;br /&gt;
	&amp;quot;whatyouneed&amp;quot;	=&amp;gt; &amp;quot;try sometimes&amp;quot;,&lt;br /&gt;
	&amp;quot;satisfaction&amp;quot;  =&amp;gt; &amp;quot;no&amp;quot;&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
sub Hello_Initialize($) {&lt;br /&gt;
    my ($hash) = @_;&lt;br /&gt;
&lt;br /&gt;
    $hash-&amp;gt;{DefFn}      = &#039;Hello_Define&#039;;&lt;br /&gt;
    $hash-&amp;gt;{UndefFn}    = &#039;Hello_Undef&#039;;&lt;br /&gt;
    $hash-&amp;gt;{SetFn}      = &#039;Hello_Set&#039;;&lt;br /&gt;
    $hash-&amp;gt;{GetFn}      = &#039;Hello_Get&#039;;&lt;br /&gt;
    $hash-&amp;gt;{AttrFn}     = &#039;Hello_Attr&#039;;&lt;br /&gt;
    $hash-&amp;gt;{ReadFn}     = &#039;Hello_Read&#039;;&lt;br /&gt;
&lt;br /&gt;
    $hash-&amp;gt;{AttrList} =&lt;br /&gt;
          &amp;quot;formal:yes,no &amp;quot;&lt;br /&gt;
        . $readingFnAttributes;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub Hello_Define($$) {&lt;br /&gt;
    my ($hash, $def) = @_;&lt;br /&gt;
    my @param = split(&#039;[ \t]+&#039;, $def);&lt;br /&gt;
    &lt;br /&gt;
    if(int(@param) &amp;lt; 3) {&lt;br /&gt;
        return &amp;quot;too few parameters: define &amp;lt;name&amp;gt; Hello &amp;lt;greet&amp;gt;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    my $hash-&amp;gt;{name}  = $param[0];&lt;br /&gt;
    my $hash-&amp;gt;{greet} = $param[2];&lt;br /&gt;
    &lt;br /&gt;
    return undef;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub Hello_Undef($$) {&lt;br /&gt;
    my ($hash, $arg) = @_; &lt;br /&gt;
    # nothing to do&lt;br /&gt;
    return undef;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub Hello_Get($@) {&lt;br /&gt;
	my ($hash, @param) = @_;&lt;br /&gt;
	&lt;br /&gt;
	return &#039;&amp;quot;get Hello&amp;quot; needs at least one argument&#039; if (int(@param) &amp;lt; 2);&lt;br /&gt;
	&lt;br /&gt;
	my $name = shift @param;&lt;br /&gt;
	my $opt = shift @param;&lt;br /&gt;
	if(!$Hello_gets{$opt}) {&lt;br /&gt;
		my @cList = keys %Hello_gets;&lt;br /&gt;
		return &amp;quot;Unknown argument $opt, choose one of &amp;quot; . join(&amp;quot; &amp;quot;, @cList);&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	if($attr{$name}{formal} eq &#039;yes&#039;) {&lt;br /&gt;
	    return $Hello_gets{$opt}.&#039;, sir&#039;;&lt;br /&gt;
    }&lt;br /&gt;
	return $Hello_gets{$opt};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub Hello_Set($@) {&lt;br /&gt;
	my ($hash, @param) = @_;&lt;br /&gt;
	&lt;br /&gt;
	return &#039;&amp;quot;set Hello&amp;quot; needs at least one argument&#039; if (int(@param) &amp;lt; 2);&lt;br /&gt;
	&lt;br /&gt;
	my $name = shift @param;&lt;br /&gt;
	my $opt = shift @param;&lt;br /&gt;
	my $value = join(&amp;quot;&amp;quot;, @param);&lt;br /&gt;
	&lt;br /&gt;
	if(!defined($Hello_gets{$opt})) {&lt;br /&gt;
		my @cList = keys %Hello_gets;&lt;br /&gt;
		return &amp;quot;Unknown argument $opt, choose one of &amp;quot; . join(&amp;quot; &amp;quot;, @cList);&lt;br /&gt;
	}&lt;br /&gt;
    $hash-&amp;gt;{STATE} = $Hello_gets{$opt} = $value;&lt;br /&gt;
    &lt;br /&gt;
	return &amp;quot;$opt set to $value. Try to get it.&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub Hello_Attr(@) {&lt;br /&gt;
	my ($cmd,$name,$attr_name,$attr_value) = @_;&lt;br /&gt;
	if($cmd eq &amp;quot;set&amp;quot;) {&lt;br /&gt;
        if($attr_name eq &amp;quot;formal&amp;quot;) {&lt;br /&gt;
			if($attr_value !~ /^yes|no$/) {&lt;br /&gt;
			    my $err = &amp;quot;Invalid argument $attr_value to $attr_name. Must be yes or no.&amp;quot;;&lt;br /&gt;
			    Log 3, &amp;quot;Hello: &amp;quot;.$err;&lt;br /&gt;
			    return $err;&lt;br /&gt;
			}&lt;br /&gt;
		} else {&lt;br /&gt;
		    return &amp;quot;Unknown attr $attr_name&amp;quot;;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	return undef;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
1;&lt;br /&gt;
&lt;br /&gt;
=pod&lt;br /&gt;
=begin html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;a name=&amp;quot;Hello&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Hello&amp;lt;/h3&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
    &amp;lt;i&amp;gt;Hello&amp;lt;/i&amp;gt; implements the classical &amp;quot;Hello World&amp;quot; as a starting point for module development. &lt;br /&gt;
    You may want to copy 98_Hello.pm to start implementing a module of your very own. See &lt;br /&gt;
    &amp;lt;a href=&amp;quot;http://wiki.fhem.de/wiki/DevelopmentModuleIntro&amp;quot;&amp;gt;DevelopmentModuleIntro&amp;lt;/a&amp;gt; for an &lt;br /&gt;
    in-depth instruction to your first module.&lt;br /&gt;
    &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
    &amp;lt;a name=&amp;quot;Hellodefine&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
    &amp;lt;b&amp;gt;Define&amp;lt;/b&amp;gt;&lt;br /&gt;
    &amp;lt;ul&amp;gt;&lt;br /&gt;
        &amp;lt;code&amp;gt;define &amp;amp;lt;name&amp;amp;gt; Hello &amp;amp;lt;greet&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        Example: &amp;lt;code&amp;gt;define HELLO Hello TurnUrRadioOn&amp;lt;/code&amp;gt;&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        The &amp;quot;greet&amp;quot; parameter has no further meaning, it just demonstrates&lt;br /&gt;
        how to set a so called &amp;quot;Internal&amp;quot; value. See &amp;lt;a href=&amp;quot;http://fhem.de/commandref.html#define&amp;quot;&amp;gt;commandref#define&amp;lt;/a&amp;gt; &lt;br /&gt;
        for more info about the define command.&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;br&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;a name=&amp;quot;Helloset&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
    &amp;lt;b&amp;gt;Set&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
    &amp;lt;ul&amp;gt;&lt;br /&gt;
        &amp;lt;code&amp;gt;set &amp;amp;lt;name&amp;amp;gt; &amp;amp;lt;option&amp;amp;gt; &amp;amp;lt;value&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        You can &amp;lt;i&amp;gt;set&amp;lt;/i&amp;gt; any value to any of the following options. They&#039;re just there to &lt;br /&gt;
        &amp;lt;i&amp;gt;get&amp;lt;/i&amp;gt; them. See &amp;lt;a href=&amp;quot;http://fhem.de/commandref.html#set&amp;quot;&amp;gt;commandref#set&amp;lt;/a&amp;gt; &lt;br /&gt;
        for more info about the set command.&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        Options:&lt;br /&gt;
        &amp;lt;ul&amp;gt;&lt;br /&gt;
              &amp;lt;li&amp;gt;&amp;lt;i&amp;gt;satisfaction&amp;lt;/i&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
                  Defaults to &amp;quot;no&amp;quot;&amp;lt;/li&amp;gt;&lt;br /&gt;
              &amp;lt;li&amp;gt;&amp;lt;i&amp;gt;whatyouwant&amp;lt;/i&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
                  Defaults to &amp;quot;can&#039;t&amp;quot;&amp;lt;/li&amp;gt;&lt;br /&gt;
              &amp;lt;li&amp;gt;&amp;lt;i&amp;gt;whatyouneed&amp;lt;/i&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
                  Defaults to &amp;quot;try sometimes&amp;quot;&amp;lt;/li&amp;gt;&lt;br /&gt;
        &amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;a name=&amp;quot;Helloget&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
    &amp;lt;b&amp;gt;Get&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
    &amp;lt;ul&amp;gt;&lt;br /&gt;
        &amp;lt;code&amp;gt;get &amp;amp;lt;name&amp;amp;gt; &amp;amp;lt;option&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        You can &amp;lt;i&amp;gt;get&amp;lt;/i&amp;gt; the value of any of the options described in &lt;br /&gt;
        &amp;lt;a href=&amp;quot;#Helloset&amp;quot;&amp;gt;paragraph &amp;quot;Set&amp;quot; above&amp;lt;/a&amp;gt;. See &lt;br /&gt;
        &amp;lt;a href=&amp;quot;http://fhem.de/commandref.html#get&amp;quot;&amp;gt;commandref#get&amp;lt;/a&amp;gt; for more info about &lt;br /&gt;
        the get command.&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;br&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;a name=&amp;quot;Helloattr&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
    &amp;lt;b&amp;gt;Attributes&amp;lt;/b&amp;gt;&lt;br /&gt;
    &amp;lt;ul&amp;gt;&lt;br /&gt;
        &amp;lt;code&amp;gt;attr &amp;amp;lt;name&amp;amp;gt; &amp;amp;lt;attribute&amp;amp;gt; &amp;amp;lt;value&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        See &amp;lt;a href=&amp;quot;http://fhem.de/commandref.html#attr&amp;quot;&amp;gt;commandref#attr&amp;lt;/a&amp;gt; for more info about &lt;br /&gt;
        the attr command.&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        Attributes:&lt;br /&gt;
        &amp;lt;ul&amp;gt;&lt;br /&gt;
            &amp;lt;li&amp;gt;&amp;lt;i&amp;gt;formal&amp;lt;/i&amp;gt; no|yes&amp;lt;br&amp;gt;&lt;br /&gt;
                When you set formal to &amp;quot;yes&amp;quot;, all output of &amp;lt;i&amp;gt;get&amp;lt;/i&amp;gt; will be in a&lt;br /&gt;
                more formal language. Default is &amp;quot;no&amp;quot;.&lt;br /&gt;
            &amp;lt;/li&amp;gt;&lt;br /&gt;
        &amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=end html&lt;br /&gt;
&lt;br /&gt;
=cut&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der HTML-Code zwischen den Tags &amp;lt;code&amp;gt;=pod&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;=cut&amp;lt;/code&amp;gt; dient zur Generierung der commandref.html. Der HTML-Inhalt wird automatisch beim Verteilen des Moduls im Rahmen des Update-Mechanismus aus jedem Modul extrahiert und daraus die Commandref in verschiedenen Sprachen erstellt. Eine detaillierte Beschreibung wie ein Commandref-Abschnitt in einem Modul definiert wird, siehe: [[Guidelines zur Dokumentation]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Development]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=DevelopmentModuleIntro&amp;diff=33085</id>
		<title>DevelopmentModuleIntro</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=DevelopmentModuleIntro&amp;diff=33085"/>
		<updated>2020-04-22T07:02:27Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Die Client-Liste */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Hinweis|Dieser Text ist in Arbeit und muss noch an einigen Stellen ergänzt werden. }}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Um neue Geräte, Dienste, o.ä. in FHEM verfügbar zu machen, kann man ein eigenes Modul in Perl schreiben. Ein Modul wird in FHEM automatisch geladen, wenn ein entsprechendes Device in FHEM definiert wird. Das Modul ermöglicht eine spezifische Kommunikation mit einem physikalischen Gerät, stellt Ergebnisse (&amp;quot;Readings&amp;quot;) und Events innerhalb von FHEM zur Verfügung und erlaubt es, das Gerät mit &amp;quot;Set&amp;quot;-/&amp;quot;Get&amp;quot;-Befehlen zu beeinflussen. Dieser Artikel soll den Einstieg in die Entwicklung eigener Module erleichtern.&lt;br /&gt;
&lt;br /&gt;
Mit dem FHEM-Befehl &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt; werden Devices in FHEM basierend auf einem Modul definiert. Dieser Befehl sorgt dafür, dass ein neues Modul bei Bedarf geladen und initialisiert wird. Ein gutes Beispiel ist hierbei die zentrale Konfigurationsdatei &amp;quot;fhem.cfg&amp;quot; in der sämtliche Devices in Form von &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Statements gespeichert sind.&lt;br /&gt;
&lt;br /&gt;
Damit das funktioniert müssen der Name des Moduls und der Name der [[#X_Initialize|Initialisierungsfunktion]]  identisch sein. Das folgende Beispiel soll dies verdeutlichen:&lt;br /&gt;
&lt;br /&gt;
Ein Jeelink USB-Stick könnte beispielsweise mit dem Befehl &amp;lt;code&amp;gt;define JeeLink1 &#039;&#039;JeeLink&#039;&#039; /dev/ttyUSB0@57600&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
In fhem.pl wird der &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl verarbeitet und geprüft, ob ein Modul mit dem Namen &amp;quot;JeeLink&amp;quot; schon geladen ist. Falls nicht, wird ein Modul mit Namen XY_JeeLink.pm im Modulverzeichnis (z.B. /opt/fhem/FHEM) gesucht und, falls vorhanden, anschließend geladen. &lt;br /&gt;
Danach wird die Funktion &amp;lt;code&amp;gt;&#039;&#039;JeeLink&#039;&#039;_Initialize()&amp;lt;/code&amp;gt; aufgerufen um das Modul in FHEM zu registrieren. Eine Moduldatei muss dazu eine Funktion &amp;lt;code&amp;gt;&#039;&#039;&amp;amp;lt;Modulname&amp;amp;gt;&#039;&#039;_Initialize()&amp;lt;/code&amp;gt; enthalten. Durch den Aufruf dieser Funktion wird FHEM mitgeteilt, welche Funktionalitäten dieses Modul unterstützt und durch welche Perl-Funktionen im Modul selbst diese ausimplementiert werden.&lt;br /&gt;
&lt;br /&gt;
In der Initialisierungsfunktion des Moduls werden die Namen aller weiteren Perl-Funktionen des Moduls, die von fhem.pl aus aufgerufen werden, bekannt gemacht. Dazu wird für jedes Modul ein eigener Hash (genauer &amp;quot;Modul-Hash&amp;quot;) mit entsprechenden Werten gefüllt, der in fhem.pl für jedes Modul entsprechend abgelegt wird. Dadurch weiß FHEM wie dieses Modul anzusprechen ist.&lt;br /&gt;
&lt;br /&gt;
== Grundlegender Aufbau eines Moduls ==&lt;br /&gt;
&lt;br /&gt;
=== Dateiname ===&lt;br /&gt;
&lt;br /&gt;
Ein FHEM-Modul wird als Perl-Modul mit der Dateiendung *.pm abgespeichert. Der Dateiname folgt dabei folgendem Schema:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;&#039;&#039;[&#039;&#039;&#039;Schlüsselnummer&#039;&#039;&#039;]&#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;_&amp;lt;/font&amp;gt;&#039;&#039;[&#039;&#039;&#039;Modulname&#039;&#039;&#039;]&#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;.pm&amp;lt;/font&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Schlüsselnummer&#039;&#039;&#039; - Eine zweistellige Zahl zwischen 00 - 99. Die Schlüsselnummer hat aktuell keine technische Relevanz mehr. In früheren FHEM-Versionen ist sie relevant für [[#Zweistufiges_Modell_f.C3.BCr_Module|zweistufige Module]] (Reihenfolge für [[DevelopmentModuleAPI#Dispatch|Dispatch()]] um logische Module zu prüfen). Die allgemeine Empfehlung ist hierbei eine Schlüsselnummer eines Moduls zu verwenden, welches eine ähnliche Funktionalität bietet. Die Schlüsselnummer 99 hat hierbei eine besondere Bedeutung, da alle Module mit dieser Schlüsselnummer beim Start von FHEM automatisch geladen werden, selbst, wenn sie in der Konfiguration nicht verwendet werden. Daher wird für myUtils 99 als Schlüsselnummer verwendet (99_myUtils.pm). Module mit der Schlüsselnummer 99 werden im SVN nicht akzeptiert (siehe [[SVN Nutzungsregeln]])&lt;br /&gt;
* &#039;&#039;&#039;Modulname&#039;&#039;&#039; - Der Name des Moduls wie er in FHEM bei dem Anlegen einer Gerätedefinition zu verwenden ist. Der Modulname sollte nur aus den folgenden möglichen Zeichen bestehen: Groß-/Kleinbuchstaben, Zahlen sowie Unterstrich (_)&lt;br /&gt;
&lt;br /&gt;
=== Inhaltlicher Aufbau ===&lt;br /&gt;
&lt;br /&gt;
Ein Modul ist inhaltlich in folgende Abschnitte unterteilt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
#  72_MYMODULE.pm &lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
package main;&lt;br /&gt;
&lt;br /&gt;
# Laden evtl. abhängiger Perl- bzw. FHEM-Hilfsmodule&lt;br /&gt;
use HttpUtils;&lt;br /&gt;
use [...]&lt;br /&gt;
&lt;br /&gt;
# FHEM Modulfunktionen&lt;br /&gt;
&lt;br /&gt;
sub MYMODULE_Initialize() {&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub MYMODULE_Define() {&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
# Eval-Rückgabewert für erfolgreiches&lt;br /&gt;
# Laden des Moduls&lt;br /&gt;
1;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Beginn der Commandref&lt;br /&gt;
&lt;br /&gt;
=pod&lt;br /&gt;
=item [helper|device|command]&lt;br /&gt;
=item summary Kurzbeschreibung in Englisch was MYMODULE steuert/unterstützt&lt;br /&gt;
=item summary_DE Kurzbeschreibung in Deutsch was MYMODULE steuert/unterstützt&lt;br /&gt;
&lt;br /&gt;
=begin html&lt;br /&gt;
 Englische Commandref in HTML&lt;br /&gt;
=end html&lt;br /&gt;
&lt;br /&gt;
=begin html_DE&lt;br /&gt;
 Deutsche Commandref in HTML&lt;br /&gt;
=end html&lt;br /&gt;
&lt;br /&gt;
# Ende der Commandref&lt;br /&gt;
=cut&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man kann hierbei von folgender Reihenfolge sprechen:&lt;br /&gt;
&lt;br /&gt;
# Perl-Code, welcher das Modul implementiert&lt;br /&gt;
# Die Zeile &amp;lt;code&amp;gt;1;&amp;lt;/code&amp;gt; nachdem der Perl-Code abgeschlossen ist. Dies dient FHEM der Erkennung, dass das Modul erfolgreich und vollständig geladen wurde. Sollte diese Zeile nicht enthalten sein, wird FHEM beim Laden des Moduls die Fehlermeldung &amp;lt;code&amp;gt;Error:Modul 72_MYMODULE deactivated&amp;lt;/code&amp;gt; in das Logfile schreiben.&lt;br /&gt;
# Commandref zur Dokumentation des Moduls. Diese Dokumentation soll dem User die möglichen Befehle/Attribute/Readings/Events vermitteln. Weitere Informationen und Hinweise findet man in den [[Guidelines zur Dokumentation]].&lt;br /&gt;
&lt;br /&gt;
== Der Hash einer Geräteinstanz ==&lt;br /&gt;
Eine Besonderheit in Perl sind [http://de.wikipedia.org/wiki/Assoziatives_Array#Perl assoziative Arrays], (nicht ganz richtig als &amp;quot;Hash&amp;quot; bezeichnet) in denen die Adressierung nicht über eine Zählvariable erfolgt, sondern über einen beliebigen String. Die internen Abläufe bei der Adressierung führen dazu, dass die Speicherung in und der Abruf aus Hashes relativ langsam ist.&lt;br /&gt;
&lt;br /&gt;
Der zentrale Speicherort für Informationen einer Geräteinstanz bei FHEM ist ein solcher Hash, der seinerseits in fhem.pl von einem globalen Hash referenziert wird. &lt;br /&gt;
&lt;br /&gt;
In fhem.pl werden alle Gerätedefinitionen in dem globalen Hash &amp;lt;code&amp;gt;%defs&amp;lt;/code&amp;gt; abgelegt. Der Inhalt von &amp;lt;code&amp;gt;$defs{&#039;&#039;&amp;amp;lt;Name&amp;amp;gt;&#039;&#039;}&amp;lt;/code&amp;gt; in fhem.pl verweist dabei auf den Hash der Geräteinstanz in Form einer Hashreferenz. Diesen Verweis (also nur die Adresse) bekommen die Funktionen eines Moduls übergeben (i.d.R. als &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; bezeichnet), welche direkt von fhem.pl aufgerufen werden. In dem Hash stehen beispielsweise die internen Werte des Geräts, die im Frontend als &amp;quot;Internals&amp;quot; angezeigt werden, sowie die Readings des Geräts. &lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
*&amp;lt;code&amp;gt;$hash-&amp;gt;{NAME}&amp;lt;/code&amp;gt; enthält den Namen der Geräteinstanz, &lt;br /&gt;
*&amp;lt;code&amp;gt;$hash-&amp;gt;{TYPE}&amp;lt;/code&amp;gt; enthält die Typbezeichnung des Geräts (Modulname)&lt;br /&gt;
&lt;br /&gt;
==Ausführung von Modulen==&lt;br /&gt;
FHEM arbeitet intern nicht parallel, sondern arbeitet alle Aufgaben seriell nacheinander kontinuierlich ab. Daher wäre es ungünstig, wenn Module Daten von einem physikalischen Gerät abfragen wollen und dabei innerhalb der selben Funktion auf die Antwort des Geräts warten. In dieser Zeit, in der FHEM auf die Antwort des Gerätes warten muss, wäre der Rest von FHEM blockiert. Da immer nur eine Aufgabe zur selben Zeit bearbeitet wird, müssen alle weiteren Aufgaben solange warten. Eine Datenkommunikation innerhalb eines Moduls sollte daher immer ohne Blockierung erfolgen. Dadurch kann FHEM die Wartezeit effizient für andere Aufgaben nutzen um bspw. anstehende Daten für andere Module zu verarbeiten. Es gibt in FHEM entsprechende Mechanismen, welche eine &amp;quot;Non-Blocking&amp;quot;-Kommunikation über verschiedene Wege (z.B. seriell, HTTP, TCP, ...) ermöglichen.&lt;br /&gt;
&lt;br /&gt;
Dafür werden in FHEM zwei zentrale Listen gepflegt, in der die Filedeskriptoren der geöffneten Kommunikatonsverbindungen gespeichert sind. Auf Linux- bzw. Unix-basierten Plattformen wird der select-Befehl des Betriebssystems verwendet um Filedeskriptoren auf lesbare Daten zu überprüfen. In FHEM gibt es dazu eine Liste (&amp;lt;code&amp;gt;%selectlist&amp;lt;/code&amp;gt;), in der die Filedeskriptoren sämtlicher Geräte (z.B. serielle Verbindung, TCP-Verbindung, etc.) gespeichert sind. &lt;br /&gt;
&lt;br /&gt;
In der zentralen Schleife (Main-Loop) von fhem.pl wird mit &amp;lt;code&amp;gt;select()&amp;lt;/code&amp;gt; überwacht, ob über eine der geöffneten Schnittstellen Daten zum Lesen anstehen. Wenn dies der Fall ist, dann wird die Lesefunktion ([[#X_Read|X_Read]]) des zuständigen Moduls aufgerufen, damit es die Daten entgegennimmt und verarbeitet. Anschließend wird die Schleife weiter ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Auf Windows-Systemen funktioniert dies anders. Hier können USB/Seriell-Geräte nicht per &amp;lt;code&amp;gt;select()&amp;lt;/code&amp;gt; überwacht werden. In FHEM unter Windows werden daher diese Schnittstellen kontinuierlich abgefragt ob Daten bereitstehen. Dafür müssen Module zusätzlich zur Lesefunktion eine Abfragefunktion ([[#X_Ready|X_Ready]]) implementieren, welche prüft, ob Daten zum Lesen anstehen. Auch auf Linux/Unix-Plattformen hat diese Funktion eine Aufgabe. Falls nämlich eine Schnittstelle ausfällt, beziehungsweise ein CUL oder USB-zu-Seriell Adapter ausgesteckt wird, dann wird über diese Funktion regelmäßig geprüft ob die Schnittstelle wieder verfügbar wird.&lt;br /&gt;
&lt;br /&gt;
Innerhalb der eigentlichen Lesefunktion (X_Read) werden dann die Daten vom zugehörigen Gerät gelesen, das nötige Protokoll implementiert um die Daten zu interpretieren und Werte in Readings geschrieben.&lt;br /&gt;
&lt;br /&gt;
Auch wenn von einem Anwender über einen Get-Befehl Daten aktiv von einem Gerät angefordert werden, sollte nicht blockierend gewartet werden. Eine asynchrone Ausgabe, sobald das Ergebnis vorliegt, ist über [[DevelopmentModuleAPI#asyncOutput|asyncOutput()]] möglich. Siehe {{Link2Forum|Topic=43771|Message=357870|LinkText=Beschreibung}} und {{Link2Forum|Topic=43771|Message=360935|LinkText=Beispiel}}. Weitere Anwendungsbeispiele finden sich im  {{Link2Forum|Topic=43052|Message=353477|LinkText=PLEX Modul}} und im überarbeiteten und nicht-blockierenden {{Link2Forum|Topic=42771|Message=348498|LinkText=SYSSTAT Modul}}.&lt;br /&gt;
&lt;br /&gt;
== Wichtige globale Variablen aus fhem.pl ==&lt;br /&gt;
&lt;br /&gt;
FHEM arbeitet mit einer Vielzahl an internen Variablen. Die nun folgenden aufgelisteten Variablen sind die wichtigsten, welche man im Rahmen der Modulprogrammierung kennen sollte:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Variable !! Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; || Dient der Erkennung für fhem.pl sowie den Modulen, ob FHEM den Initialisierungsvorgang abgeschlossen hat. Beim Starten von FHEM ist &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; gleich &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;. Erst, wenn das Einlesen der Konfiguration, sowie des State-Files (Readings) abgeschlossen ist, wird &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; auf &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; gesetzt.&lt;br /&gt;
Das gleiche Verfahren wird auch bei dem Befehl &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt; angewandt. Während &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt; ausgeführt wird (Konfiguration löschen, neu einlesen), ist &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; gleich &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dies ist insbesondere in der [[#X_Define|Define]]-Funktion eines Moduls relevant. Durch eine Prüfung auf &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; kann man erkennen, ob eine Definition von Hand (&amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; = 1) oder im Rahmen der Initialisierung (FHEM Start / Rereadcfg =&amp;gt; &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; = 0) erfolgte. Während der Initialisierung stehen bspw. die gesetzten Attribute der Definition noch nicht zur Verfügung und können daher nicht ausgewertet werden (siehe . &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt; || In &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt; werden sämtliche gesetzten Attribute aller Geräte gespeichert. Diese Datenstruktur wird generell durch den &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt;-Befehl verwaltet. Hierbei wird einem Gerätenamen eine Mehrzahl an Attributnamen mit einem Wert zugeordnet. Attribut-Inhalte können über die Funktion [[DevelopmentModuleAPI#AttrVal|AttrVal()]] ausgelesen werden.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%cmds&amp;lt;/code&amp;gt; || In &amp;lt;code&amp;gt;%cmds&amp;lt;/code&amp;gt; wird jedem in FHEM existierendem Befehl die entsprechende Funktion zugewiesen, welche diesen Befehl umsetzt. Module können durch das Eintragen eines Befehlsnamen samt Funktion in &amp;lt;code&amp;gt;%cmds&amp;lt;/code&amp;gt; über die [[#X_Initialize|Initialize]]-Funktion eines Moduls einen (oder mehrere) eigene Befehle in FHEM registrieren.&lt;br /&gt;
&lt;br /&gt;
Die Struktur ist dabei wiefolgt:&lt;br /&gt;
&lt;br /&gt;
  $cmds{&#039;&#039;&amp;amp;lt;Befehlsname&amp;amp;gt;&#039;&#039;} = {  Fn  =&amp;gt; &amp;quot;&#039;&#039;&amp;amp;lt;Funktionsname&amp;amp;gt;&#039;&#039;&amp;quot;,&lt;br /&gt;
                            Hlp =&amp;gt; &amp;quot;&#039;&#039;&amp;amp;lt;Aufrufsyntax&amp;amp;gt;&#039;&#039;&amp;quot;};&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%data&amp;lt;/code&amp;gt;|| Der eigentliche Zweck von &amp;lt;code&amp;gt;%data&amp;lt;/code&amp;gt; ist dem Nutzer eine Möglichkeit zum Speichern von temporären Daten im globalen Kontext zu ermöglichen. Einige Module verwenden &amp;lt;code&amp;gt;%data&amp;lt;/code&amp;gt; jedoch auch um modul- &amp;amp; geräteübergreifend Daten auszutauschen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%defs&amp;lt;/code&amp;gt;|| In &amp;lt;code&amp;gt;%defs&amp;lt;/code&amp;gt; werden sämtliche Gerätedefinitionen, bzw. die Hash-Referenzen auf diese, gespeichert. Hier ist jedem Gerätenamen eine Hash-Referenz zugeordnet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%modules&amp;lt;/code&amp;gt;|| In &amp;lt;code&amp;gt;%modules&amp;lt;/code&amp;gt; sind alle geladenen Module gelistet mit ihren entsprechenden Initialisierungsdaten (Funktionsnamen, Attribut-Listen, spezielle Einstellungen, ...). Hier wird für jeden Modulname der Modul-Hash aus der [[#X_Initialize|Initialize]]-Funktion gespeichert. &lt;br /&gt;
Desweiteren legen viele Module, welche nach dem [[DevelopmentModuleIntro#Zweistufiges_Modell_f.C3.BCr_Module|zweistufigen Modulkonzept]] hier eine Rückwärtszuordnung von Geräteadressen zu Geräte-Hash an.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt;|| In &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt; sind alle zu prüfenden Verbindungen mit ihrer entsprechendem Geräte-Hash gelistet. FHEM prüft alle hier gelisteten Geräte regelmäßig über eine Aufruf der entsprechenden [[#X_Ready|Ready]]-Funktion.&lt;br /&gt;
&lt;br /&gt;
Bei einer Nutzung von dem Hilfsmodul [[DevIo|DevIo.pm]] zum Aufbau einer Kommunikationsverbindung, kümmert sich DevIo selbständig um den entsprechenden Eintrag in &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%selectlist&amp;lt;/code&amp;gt;|| In &amp;lt;code&amp;gt;%selectlist&amp;lt;/code&amp;gt; sind alle geöffneten Verbindungen mit ihrer entsprechendem Geräte-Hash gelistet. FHEM prüft alle hier gelisteten Geräte, ob der geöffnete Filedeskriptor unter &amp;lt;code&amp;gt;$hash-&amp;gt;{FD}&amp;lt;/code&amp;gt; Daten zum Lesen bereitgestellt hat. Ist dass der Fall, wird die entsprechende [[#X_Read|Read]]-Funktion aufgerufen, um anstehende Daten durch das Modul zu verarbeiten.&lt;br /&gt;
Bei einer Nutzung von dem Hilfsmodul [[DevIo|DevIo.pm]] zum Aufbau einer Kommunikationsverbindung, kümmert sich DevIo selbständig um den entsprechenden Eintrag in &amp;lt;code&amp;gt;%selectlist&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Es gibt durchaus viele weitere globale Variablen, die jedoch für sehr spezielle Anwendungsfälle und z.T. nur einzelne Module gedacht sind und daher hier nicht aufgeführt werden.&lt;br /&gt;
&lt;br /&gt;
== Internals ==&lt;br /&gt;
Daten, die ein Modul im Geräte-Hash speichert nennt man Internals. Sie werden als Unterstruktur des Hashes der jeweiligen Geräteinstanz gespeichert, beispielswiese &amp;lt;code&amp;gt;$hash-&amp;gt;{NAME}&amp;lt;/code&amp;gt; für den Gerätenamen, welcher beim Define-Befehl übergeben wurde und als Internal gespeichert wird. Diese Daten spielen für FHEM eine sehr wichtige Rolle, da sämtliche gerätespezifischen Daten als Internal im Gerätehash gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Falls Werte wie z.B. ein Intervall nicht über den Define-Befehl gesetzt werden sollen und im Betrieb einfach änderbar sein sollten, ist eine alternative Möglichkeit die Speicherung in so genannten Attributen. Dann würde man den Define-Befehl so implementieren, dass er kein Intervall übergeben bekommt und statt dessen das Interval als Attribut über den Befehl &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt; gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Generell werden alle Werte, welche direkt in der ersten Ebene von &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; (Gerätehash) gespeichert werden auf der Detail-Seite einer Definition in der FHEMWEB Oberfläche angezeigt. Es gibt jedoch Ausnahmen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$hash-&amp;gt;{helper}{URL}&amp;lt;/code&amp;gt; - Alle Elemente, welche als Unterelement wieder einen Hash besitzen werden nicht in FHEMWEB dargestellt. Typischerweise speichern Module Daten unter &amp;lt;code&amp;gt;$hash-&amp;gt;{helper}&amp;lt;/code&amp;gt; interne Daten zwischen, die für den User nicht relevant sind, sondern nur der internen Verarbeitung dienen.&lt;br /&gt;
* &amp;lt;code&amp;gt;$hash-&amp;gt;{&#039;&#039;&#039;.&#039;&#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;ELEMENT&amp;lt;/font&amp;gt;}&amp;lt;/code&amp;gt; - Alle Knoten, welche mit einem Punkt beginnen werden in der FHEMWEB Oberfläche nicht angezeigt. Man kann diese Daten jedoch beim Aufruf des [[List|list-Kommandos]] einsehen.&lt;br /&gt;
&lt;br /&gt;
Es gibt bereits vorbelegte Internals welche in FHEM dazu dienen definitionsbezogene Informationen wie bspw. Namen und Readings zu speichern. Dies sind im besonderen:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;min-width: 13em;&amp;quot; | Internal !!  Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{NAME}&amp;lt;/code&amp;gt;  || Der Definitionsname, mit dem das Gerät angelegt wurde.  &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{READINGS}&amp;lt;/code&amp;gt;  || Enthält alle aktuell vorhandenen Readings. Daten unterhalb dieses Knotens sollte man nicht direkt manipulieren. Um Readings zu Erzeugen gibt es entsprechende [[DevelopmentModuleAPI#Readings_.2F_Events|Reading-Funktionen]].&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{NR}&amp;lt;/code&amp;gt;  || Die Positions-Nr. der Definition innerhalb der Konfiguration. Diese dient dazu die Konfiguration in der gleichen Reihenfolge zu speichern, wie die einzelnen Geräte angelegt wurden.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{TYPE}&amp;lt;/code&amp;gt;  || Der Modulname, mit welchem die Definition angelegt wurde.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{DEF}&amp;lt;/code&amp;gt;  || Sämtliche Argumente, welche beim &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl nach dem Modulnamen übergeben wurden.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{CFGFN}&amp;lt;/code&amp;gt;  || Der Dateiname der Konfigurationsdatei in der diese Definition enthalten ist (sofern nicht in fhem.cfg). Dieser Wert ist nur gefüllt, wenn man mit mehreren Konfigurationsdateien arbeitet, welche dann in fhem.cfg via include-Befehl eingebunden werden.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{NTFY_ORDER}&amp;lt;/code&amp;gt;  || Sofern das Modul Events via [[DevelopmentModuleIntro#X_Notify|Notify-Funktion]] verarbeitet enthält jede Definition eine Notify-Order als Zeichenkette bestehend aus dem Notify Order Prefix und dem Definitionsnamen. Details zur Funktionsweise gibt es in der Beschreibung zur [[DevelopmentModuleIntro#X_Notify|Notify-Funktion]] im Abschnitt &amp;quot;Reihenfolge für den Aufruf der Notify-Funktion beeinflussen&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{NOTIFYDEV}&amp;lt;/code&amp;gt;  || Sofern das Modul Events via NotifyFn verarbeitet kann man damit die Definitionen, von denen man Events erhalten will begrenzen. Details zur Funktionsweise gibt es in der Beschreibung zur [[DevelopmentModuleIntro#X_Notify|Notify-Funktion]] im Abschnitt &amp;quot;Begrenzung der Aufrufe auf bestimmte Geräte&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{IODev}&amp;lt;/code&amp;gt;  || Hier wird das zugeordnete IO-Gerät durch [[DevelopmentModuleAPI#AssignIoPort|AssignIoPort()]] gespeichert, welches für den Datentransport und -empfang dieses logischen Gerätes zuständig ist. Dieser Wert existiert nur bei Modulen die nach dem [[DevelopmentModuleIntro#Zweistufiges_Modell_f.C3.BCr_Module|zweistufigen Modulkonzept]] arbeiten. &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{CHANGED}&amp;lt;/code&amp;gt;  || Hier werden alle Events kurzzeitig gesammelt, welche für die Eventverarbeitung anstehen. Insbesondere die [[DevelopmentModuleAPI#Readings_.2F_Events|Reading-Funktionen]] speichern hier alle Events zwischen um sie nach Abschluss via [[DevelopmentModuleAPI#DoTrigger|DoTrigger()]] zu verarbeiten. &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{FD}&amp;lt;/code&amp;gt;  || Wenn die Definition eine Netzwerkverbindung oder serielle Schnittstelle geöffnet hat (z.B. via [[DevIo]]), so wird der entsprechende File-Deskriptor in diesem Internal gespeichert. Damit kann FHEM alle geöffneten Filedeskriptoren der entsprechenden Definition zuordnen um bei ankommenden Daten die Definition via [[DevelopmentModuleIntro#X_Read|Read-Funktion]] damit zu versorgen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{EXCEPT_FD}&amp;lt;/code&amp;gt;  || Ähnlich wie &amp;lt;code&amp;gt;$hash-&amp;gt;{FD}&amp;lt;/code&amp;gt;. Sofern die Definition in &amp;lt;code&amp;gt;[[#Wichtige_globale_Variablen_aus_fhem.pl|%selectlist]]&amp;lt;/code&amp;gt; eingetragen ist und ein Fildeskriptor in diesem Internal gesetzt ist, wird bei einer auftretenden Exception bzw. Interrupt die [[DevelopmentModuleIntro#X_Except|Except]]-Funktion des entsprechenden Moduls aufgerufen um darauf zu reagieren.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Generell sollte man die meisten der hier genannten systemweiten Internals nicht modifizieren, da ansonsten die korrekte Funktionsweise von FHEM nicht mehr garantiert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Readings ==&lt;br /&gt;
Daten, welche von einem Gerät gelesen werden und in FHEM in einer für Menschen verständlichen Form zur Verfügung gestellt werden können, werden Readings genannt. Sie geben den Status des Gerätes wieder und erzeugen Events innerhalb von FHEM auf die andere Geräte reagieren können. Sie werden als Unterstruktur des Hashes der jeweiligen Geräteinstanz gespeichert, beispielsweise &lt;br /&gt;
*&amp;lt;code&amp;gt;$hash-&amp;gt;{READINGS}{temperature}{VAL}&amp;lt;/code&amp;gt; für die Temperatur eines Fühlers&lt;br /&gt;
*&amp;lt;code&amp;gt;$hash-&amp;gt;{READINGS}{temperature}{TIME}&amp;lt;/code&amp;gt; für den Zeitstempel der Messung&lt;br /&gt;
&lt;br /&gt;
Für den lesenden Zugriff auf Readings steht die Funktion &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#ReadingsVal|ReadingsVal()]]&amp;lt;/code&amp;gt; zur Verfügung. Ein direkter Zugriff auf die Datenstruktur sollte nicht vorgenommen werden.&lt;br /&gt;
&lt;br /&gt;
Readings werden im Statefile von FHEM automatisch auf der Festplatte zwischengespeichert, damit sie nach einem Neustart sofort wieder zur Verfügung stehen. Dadurch ist der letzte Status eines Gerätes vor einem Neustart nachvollziehbar.&lt;br /&gt;
&lt;br /&gt;
Readings, die mit einem Punkt im Namen beginnen, haben eine funktionale Besonderheit. Sie werden im FHEMWEB nicht angezeigt und können somit als &amp;quot;Permanentspeicher&amp;quot; für kleinere Daten innerhalb des Moduls genutzt werden. Um größere Datenmengen permanent zu speichern sollte man jedoch die Funktion &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#setKeyValue|setKeyValue()]]&amp;lt;/code&amp;gt; verwenden.&lt;br /&gt;
&lt;br /&gt;
Zum Setzen von Readings sollen &lt;br /&gt;
*bei Gruppen von Readings der Funktionsblock &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsBeginUpdate|readingsBeginUpdate()]]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsBulkUpdate|readingsBulkUpdate()]]&amp;lt;/code&amp;gt; (mehrfach wiederholt), &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsEndUpdate|readingsEndUpdate()]]&amp;lt;/code&amp;gt;&lt;br /&gt;
*bei einzelnen Updates die Funktion &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsSingleUpdate|readingsSingleUpdate()]]&amp;lt;/code&amp;gt; &lt;br /&gt;
aufgerufen werden. Dabei kann man auch angeben, ob dabei ein Event ausgelöst werden soll oder nicht. Events erzeugen, je nach Hardwareperformance, spürbare Last auf dem System (siehe [[DevelopmentModuleIntro#X_Notify|NotifyFn]]), das Ändern von Readings ohne dass dabei Events erzeugt werden jedoch nicht.&lt;br /&gt;
&lt;br /&gt;
Eine Sequenz zum Setzen von Readings könnte folgendermaßen aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
readingsBeginUpdate($hash);&lt;br /&gt;
readingsBulkUpdate($hash, $readingName1, $wert1 );&lt;br /&gt;
readingsBulkUpdate($hash, $readingName2, $wert2 );&lt;br /&gt;
readingsEndUpdate($hash, 1);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um Readings zu löschen, wird für die Modulprogrammierung die Funktion &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsDelete|readingsDelete()]]&amp;lt;/code&amp;gt; empfohlen. Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
readingsDelete($hash, $readingsname) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{Hinweis|&#039;&#039;&#039;Hintergrundinfo dazu aus dem Forum:&#039;&#039;&#039; {{Link2Forum|Topic=83069|Message=753066}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CommandDeleteReading()&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;deletereading&amp;lt;/code&amp;gt; ist eher fuer den Endbenutzer und seine userReadings gedacht, und macht bei den Modulen die unnoetige Schleife ueber [[DevelopmentModuleAPI#devspec2array|devspec2array()]]. Wenn der Modulautor beim Aufruf auch &amp;lt;code&amp;gt;$cl&amp;lt;/code&amp;gt; weitergibt, und der Anwender meint, dieses Geraet auf blacklist setzen zu muessen, dann kann das Modul sein eigenes Reading nicht entfernen, und das ist kontraproduktiv.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
FHEM verfügt über einen Event-Mechanismus um Änderungen verschiedenster Art an einzelne oder alle Definitionen mitzuteilen. Jedes Modul (und damit alle Definitionen dieses Moduls) können auf Events von FHEM selber (Definition &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt;) oder von anderen Definitionen reagieren und dadurch selber aktiv werden. Ein Event wird innerhalb von FHEM als Zeichenkette behandelt.&lt;br /&gt;
&lt;br /&gt;
Events sind grundsätzlich immer definitionsbezogen. Das bedeutet, dass ein Event immer in Verbindung mit einem Definitionsnamen erzeugt wird. Jede Definition, welche ein Event verarbeitet, erhält den Definitions-Hash (&amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;) der auslösenden Definition.&lt;br /&gt;
&lt;br /&gt;
Events werden typischerweise bei der Erstellung von Readings implizit für jedes einzelne Reading erzeugt. Es gibt jedoch auch Events die nichts mit Readings zu tun haben um anderweitige Änderungen bekannt zu geben.&lt;br /&gt;
&lt;br /&gt;
Eigene Events können in FHEM mit der Funktion [[DevelopmentModuleAPI#DoTrigger|DoTrigger()]] erzeugt werden. Um auf Events in einem Modul reagieren zu können, muss eine [[#X_Notify|Notify]]-Funktion implementiert sein. Sobald ein oder mehrere Events für eine Definition getriggert werden, prüft FHEM, welche Definitionen über Events der auslösenden Definition informiert werden möchten. Diese werden dann nacheinander in einer bestimmten Reihenfolge durch Aufruf der [[#X_Notify|Notify]]-Funktion über anstehende Events in Kenntnis gesetzt. Es obliegt dann dem jeweiligen Modul, wie es auf die Events reagiert.&lt;br /&gt;
&lt;br /&gt;
=== globale Events ===&lt;br /&gt;
&lt;br /&gt;
Als &amp;quot;globale Events&amp;quot; werden alle Events bezeichnet, die durch die Definition &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt; erzeugt werden. Es handelt sich hierbei um Events die Strukturänderungen in der Konfiguration, als auch systemweite Ereignisse zu FHEM selbst signalisieren.&lt;br /&gt;
&lt;br /&gt;
Hier eine kurze Zusammenfassung, welche Events durch &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt; getriggert werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Allgemeine Events:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event-Text !! Beschreibung.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;INITIALIZED&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Der Start von FHEM ist abgeschlossen. Sämtliche Definitionen und Attribute wurden aus der Konfiguration (fhem.cfg oder configDB) eingelesen, sowie sämtliche Readings sind aus dem State-File eingelesen und stehen nun voll umfänglich zur Verfügung.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;REREADCFG&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Die Konfiguration wurde erneut eingelesen. Dies bedeutet, es wurden alle Definitionen/Attribute/Readings aus FHEM entfernt und durch Einlesen der Konfiguration neu angelegt. (FHEM-Befehl: &amp;quot;rereadcfg&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;SAVE&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Die laufende Konfiguration soll gespeichert werden (in fhem.cfg oder configDB). Dieses Event wird &#039;&#039;&#039;VOR&#039;&#039;&#039; dem Speichern der Konfiguration getriggert. Sobald der Trigger verarbeitet wurde, beginnt das Speichern der Konfiguration. (FHEM-Befehl: &amp;quot;save&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;SHUTDOWN&amp;lt;/code&amp;gt;&#039;&#039;&#039; || FHEM wird sich beenden. (FHEM-Befehl: &amp;quot;shutdown&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt; DELAYEDSHUTDOWN &amp;lt;/code&amp;gt;&#039;&#039;&#039; || FHEM wird sich beenden. (FHEM-Befehl: &amp;quot;shutdown&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;UPDATE&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Es wurde ein Update erfolgreich installiert. (FHEM-Befehl: &amp;quot;update&amp;quot;)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Definitionsbezogene Events:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event-Text !! Beschreibung.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;DEFINED &#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Es wurde eine neue Definition mit Namen &amp;lt;code&amp;gt;&#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; angelegt. (FHEM-Befehl: &amp;quot;define&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;DELETED &#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Die Definition mit dem Namen &amp;lt;code&amp;gt;&#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; wurde gelöscht. (FHEM-Befehl: &amp;quot;delete&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;RENAMED &#039;&#039;&amp;lt;Alt&amp;gt;&#039;&#039; &#039;&#039;&amp;lt;Neu&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Die Definition mit dem Namen &amp;lt;code&amp;gt;&#039;&#039;&amp;lt;Alt&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; wurde in den Namen &amp;lt;code&amp;gt;&#039;&#039;&amp;lt;Neu&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; umbenannt. (FHEM-Befehl: &amp;quot;rename&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;MODIFIED &#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Die Definition mit dem Namen &amp;lt;code&amp;gt;&#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; wurde modifiziert. (FHEM-Befehl: &amp;quot;modify&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;UNDEFINED &#039;&#039;&amp;lt;Name&amp;gt; &amp;lt;Modul&amp;gt; &amp;lt;Define-Parameter&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Es wurde eine Nachricht von einem physikalischen Modul (siehe [[#Zweistufiges Modell für Module|zweistufiges Modulkonzept]]) erhalten, für die keine passende logische Definition in FHEM existiert. Details dazu, siehe dazu Abschnitt [[#Automatisches Anlegen von logischen Gerätedefinitionen (autocreate)|Automatisches Anlegen von logischen Gerätedefinitionen (autocreate)]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Begrenzung von Events ===&lt;br /&gt;
&lt;br /&gt;
Ein Modul, welches Events verarbeitet, kann die Eventverarbeitung auf bestimmte Definitionen begrenzen. Dadurch werden nur Events an das Modul gemeldet (via [[#X_Notify|X_Notify()]]), welche von einer oder mehreren bestimmten Definitionen getriggert wurden. Dadurch werden unnötige Events nicht an das Modul gemeldet und schont somit Ressourcen.&lt;br /&gt;
&lt;br /&gt;
Standardmäßig werden sämtliche Events ohne Begrenzung an ein Modul gemeldet, welches eine [[#X_Notify|Notify]]-Funktion implementiert hat und somit Events verarbeiten kann. Details zur Begrenzung von Events findet man in der Beschreibung zur Modulfunktion [[#X_Notify|X_Notify()]].&lt;br /&gt;
&lt;br /&gt;
=== Reihenfolge der Eventverarbeitung ===&lt;br /&gt;
&lt;br /&gt;
Ein getriggertes Event wird nacheinander gegen jede Definition geprüft, deren Modul eine [[#X_Notify|Notify]]-Funktion implementiert hat. Dies bedeutet, jede Definition wird nacheinander durch Aufruf der [[#X_Notify|Notify]]-Funktion mit dem Definitionshash der auslösenden Definition aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Unter bestimmten Umständen kann es erforderlich sein, in diese Reihenfolge einzugreifen. Beispielsweise wenn das eigene Modul und deren Definitionen das Event als letztes oder erstes verarbeiten müssen. Ein Beispiel bietet hierbei das Modul [[dewpoint]], welches Events vor allen anderen Modulen verarbeiten muss.&lt;br /&gt;
&lt;br /&gt;
Details, wie man die Reihenfolge der Eventverarbeitung steuern kann, findet man in der Beschreibung zur Modulfunktion [[#X_Notify|X_Notify()]].&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Damit der Nutzer das Verhalten einer einzelnen Gerätedefinition zur Laufzeit individuell anpassen kann, gibt es in FHEM für jede Definition sogenannte Attribute, welche mit dem Befehl &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt; gesetzt werden können.&lt;br /&gt;
Diese stehen dann dem Modul unmittelbar zur Verfügung um das Verhalten während der Ausführung zu beeinflussen. Attribute werden zusammen mit dem &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl der jeweiligen Definition beim Speichern der aktuellen Konfiguration von FHEM in die Konfigurationsdatei geschrieben. Beim Neustart werden die entsprechenden Befehle ausgeführt um alle Definition inkl. Attribute wieder anzulegen. Zur Laufzeit werden Attribute in dem globalen Hash &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt; mit dem Definitionsnamen als Index (&amp;lt;code&amp;gt;$attr{$name} = $value&amp;lt;/code&amp;gt;) gespeichert. Ein Attribut mit dem Namen &amp;lt;code&amp;gt;header&amp;lt;/code&amp;gt; würde beispielsweise mit &amp;lt;code&amp;gt;$attr{$name}{header}&amp;lt;/code&amp;gt; adressiert. Generell sollte &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt; nicht durch direkten Zugriff manipuliert/benutzt werden.&lt;br /&gt;
&lt;br /&gt;
Zum Auslesen von Attributen sollte die Funktion [[DevelopmentModuleAPI#AttrVal|AttrVal()]] verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Welche Attribute ein Modul unterstützt muss in der Funktion &amp;lt;code&amp;gt;[[#X_Initialize|X_Initialize]]&amp;lt;/code&amp;gt; durch Setzen von &amp;lt;code&amp;gt;$hash-&amp;gt;{AttrList}&amp;lt;/code&amp;gt; bekannt gemacht werden (siehe unten).&lt;br /&gt;
&lt;br /&gt;
Wenn beim Setzen von Attributen in einer Gerätedefinition entsprechende Werte geprüft werden sollen oder zusätzliche Funktionalitäten implementiert werden müssen, dann muss dies in der Funktion &amp;lt;code&amp;gt;[[#X_Attr|X_Attr]]&amp;lt;/code&amp;gt; (siehe unten) implementiert werden. Hier kann man bspw. einen Syntaxcheck für Attribut-Werte implementieren um ungültige Werte zurückzuweisen.&lt;br /&gt;
&lt;br /&gt;
== Modulfunktionen ==&lt;br /&gt;
&lt;br /&gt;
Damit fhem.pl ein Modul nutzen kann, muss dieses entsprechende Funktionen mit einer vorgegebenen Aufrufsyntax implementieren. Durch die Bekanntgabe dieser modulspezifischen Funktionen können Daten zwischen fhem.pl und einem Modul entsprechend ausgetauscht werden. Es gibt verschiedene Arten von Funktionen die ein Modul anbieten muss bzw. kann, je nach Funktionsumfang.&lt;br /&gt;
&lt;br /&gt;
=== Die wichtigsten Funktionen in einem Modul ===&lt;br /&gt;
&lt;br /&gt;
Folgende Funktion muss ein Modul mit dem beispielhaften Namen &amp;quot;X&amp;quot; mindestens bereitstellen:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;text-align:left&amp;quot; | Funktionsname !! style=&amp;quot;text-align:left&amp;quot; | Kurzbeschreibung&lt;br /&gt;
|-&lt;br /&gt;
|  [[#X_Initialize|X_Initialize]] || Initialisiert das Modul und gibt den Namen zusätzlicher Modulfunktionen bekannt, sowie modulspezifische Einstellungen. Wird direkt nach dem erfolgreichen Laden des Moduls durch fhem.pl aufgerufen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die folgenden Funktionen sind die wichtigsten Funktionen, welche je nach Anwendungsfall zu implementieren sind. Es handelt sich hierbei um die wichtigsten Vertreter, welche in den meisten Modulen Verwendung finden. Nicht alle Funktionen machen jedoch in jedem Modul Sinn. Generell sollte auch hier bei jeder Funktion der Modulname vorangestellt werden um ein einheitliches Namensschema zu gewährleisten. Hier die wichtigsten Modulfunktionen:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;text-align:left&amp;quot; | Funktionsname !! style=&amp;quot;text-align:left&amp;quot; class=&amp;quot;unsortable&amp;quot; | Kurzbeschreibung&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Define|X_Define]] || Wird im Rahmen des &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehls aufgerufen.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Undef|X_Undef]] || Wird im Rahmen des &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt;-Befehls, sowie &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt;-Befehl aufgerufen. Dient zum Abbau von offenen Verbindungen, Timern, etc.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Delete|X_Delete]] || Wird im Rahmen des beim &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt;-Befehls aufgerufen wenn das Gerät endgültig gelöscht wird um weiterführende Aktionen vor dem Löschen durchzuführen.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Get|X_Get]] || Wird im Rahmen des &amp;lt;code&amp;gt;get&amp;lt;/code&amp;gt;-Befehls aufgerufen um Daten vom Gerät abzufragen&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Set|X_Set]]  || Wird im Rahmen des &amp;lt;code&amp;gt;set&amp;lt;/code&amp;gt;-Befehls aufgerufen um Daten an das Gerät zu senden.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Attr|X_Attr]]  || Wird im Rahmen des &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt;-Befehls aufgerufen um Attributwerte zu prüfen)&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Read|X_Read]]  || Wird durch FHEM aufgerufen, wenn ein gelisteter Filedeskriptor in &amp;lt;code&amp;gt;[[#Wichtige_globale_Variablen_aus_fhem.pl|%selectlist]]&amp;lt;/code&amp;gt; Daten zum Lesen bereitstellt.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Ready|X_Ready]]  || Wird unter Windows durch FHEM aufgerufen um zyklisch einen seriellen Filedeskriptor auf lesbare Daten zu prüfen. Unter Linux dient diese Funktion dem Wiederaufbau verlorener Verbindungen.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Notify|X_Notify]]  || Verarbeitet Events von anderen Geräten innerhalb von FHEM&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Rename|X_Rename]] || Wird aufgerufen, wenn ein Gerät umbenannt wird.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Shutdown|X_Shutdown]] || Wird beim Herunterfahren von FHEM ausgeführt.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_DelayedShutdown | X_DelayedShutdown]] || Wird beim Herunterfahren von FHEM ausgeführt.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Diese Funktionen werden in diesem Abschnitt genauer beschrieben.&lt;br /&gt;
&lt;br /&gt;
==== X_Initialize ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; im Namen muss dabei auf den Namen des Moduls bzw. des definierten Gerätetyps geändert werden. Im Modul mit der Datei &amp;lt;code&amp;gt;36_JeeLink.pm&amp;lt;/code&amp;gt; beispielsweise ist der Name der Funktion &amp;lt;code&amp;gt;JeeLink_Initialize&amp;lt;/code&amp;gt;. Die Funktion wird von fhem.pl nach dem Laden des Moduls aufgerufen und bekommt eine leere Hashreferenz für den Initialisierungsvorgang übergeben. &lt;br /&gt;
&lt;br /&gt;
Dieser Hash muss nun von X_Initialize mit allen modulrelevanten Funktionsnamen gefüllt werden. Anschließend wird dieser Hash durch fhem.pl im globalen Hash &amp;lt;code&amp;gt;%modules&amp;lt;/code&amp;gt; gespeichert. &amp;lt;code&amp;gt;$modules{ModulName}&amp;lt;/code&amp;gt; wäre dabei der Hash für das Modul mit dem Namen &amp;lt;code&amp;gt;ModulName&amp;lt;/code&amp;gt;. Es handelt sich also nicht um den oben beschriebenen Hash der Geräteinstanzen sondern einen Hash, der für jedes Modul existiert und modulspezifische Daten wie bspw. die implementierten Modulfunktionen enthält. Die Initialize-Funktion setzt diese Funktionsnamen, in den Hash des Moduls wie folgt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
$hash-&amp;gt;{DefFn}                = &amp;quot;X_Define&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{UndefFn}              = &amp;quot;X_Undef&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{DeleteFn}             = &amp;quot;X_Delete&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{SetFn}                = &amp;quot;X_Set&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{GetFn}                = &amp;quot;X_Get&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{AttrFn}               = &amp;quot;X_Attr&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{ReadFn}               = &amp;quot;X_Read&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{ReadyFn}              = &amp;quot;X_Ready&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{NotifyFn}             = &amp;quot;X_Notify&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{RenameFn}             = &amp;quot;X_Rename&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{ShutdownFn}           = &amp;quot;X_Shutdown&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{DelayedShutdownFn}    = &amp;quot;X_ DelayedShutdown&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um eine entsprechende Funktion in FHEM bekannt zu machen muss dazu der Funktionsname, wie er im Modul als &amp;lt;code&amp;gt;sub &amp;amp;lt;&#039;&#039;Funktionsname&#039;&#039;&amp;amp;gt;() { ... }&amp;lt;/code&amp;gt; definiert ist, als Zeichenkette in &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; gesetzt werden. Dabei sollten die entsprechenden Funktionsnamen immer den Modulnamen (in diesem Beispiel &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;) als Präfix verwenden.&lt;br /&gt;
Auf diese Weise können sämtliche modulspezifisch implementierten Funktionen wie &amp;lt;code&amp;gt;X_Read&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;X_Parse&amp;lt;/code&amp;gt; etc. durch Zuweisung an &amp;lt;code&amp;gt;$hash-&amp;gt;{ReadFn}&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;$hash-&amp;gt;{ParseFn}&amp;lt;/code&amp;gt; usw. bekannt gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Darüber hinaus sollten die vom Modul unterstützten Attribute definiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
$hash-&amp;gt;{AttrList} =&lt;br /&gt;
  &amp;quot;do_not_notify:1,0 &amp;quot; . &lt;br /&gt;
  &amp;quot;header &amp;quot; .&lt;br /&gt;
  $readingFnAttributes;  &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Auflistung aller unterstützten modulspezifischen Attribute erfolgt in Form einer durch Leerzeichen getrennten Liste in &amp;lt;code&amp;gt;$hash-&amp;gt;{AttrList}&amp;lt;/code&amp;gt;. Es gibt in FHEM globale Attribute, die in allen Gerätedefinitionen verfügbar sind und nur modulspezifische Attribute die jedes Modul via &amp;lt;code&amp;gt;$hash-&amp;gt;{AttrList}&amp;lt;/code&amp;gt; über die eigene Initialize-Funktion setzt.  In fhem.pl werden dann die entsprechenden Attributwerte beim Aufruf eines &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt;-Befehls in die globale Datenstruktur &amp;lt;code&amp;gt;$attr{$name}&amp;lt;/code&amp;gt;, z.B. &amp;lt;code&amp;gt;$attr{$name}{header}&amp;lt;/code&amp;gt; für das Attribut &amp;lt;code&amp;gt;header&amp;lt;/code&amp;gt; gespeichert. Falls im Modul weitere Aktionen oder Prüfungen beim Setzen eines Attributs nötig sind, dann kann wie im Beispiel oben die [[#X_Attr|Attr]]-Funktion implementiert und in der Initialize-Funktion bekannt gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Die Variable &amp;lt;code&amp;gt;$readingFnAttributes&amp;lt;/code&amp;gt;, die im obigen Beispiel an die Liste der unterstützten Attribute angefügt wird, definiert Attributnamen, die dann zusätzlich gemacht werden, wenn das Modul zum Setzen von Readings die Funktionen &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsBeginUpdate|readingsBeginUpdate()]]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsBulkUpdate|readingsBulkUpdate()]]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsEndUpdate|readingsEndUpdate()]]&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsSingleUpdate|readingsSingleUpdate()]]&amp;lt;/code&amp;gt; verwendet. In diesen Funktionen werden Attribute wie &amp;lt;code&amp;gt;event-min-interval&amp;lt;/code&amp;gt; oder auch &amp;lt;code&amp;gt;event-on-change-reading&amp;lt;/code&amp;gt; ausgewertet. Für Details hierzu siehe commandref zu {{Link2CmdRef|Anker=readingFnAttributes|Label=readingFnAttributes}}.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von parseParams()&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion &amp;lt;code&amp;gt; [[DevelopmentModuleAPI#parseParams|parseParams()]]&amp;lt;/code&amp;gt; unterstützt Modul-Autoren beim Parsen von Übergabeparametern, welche bei &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;get&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;set&amp;lt;/code&amp;gt; Kommandos an die entsprechenden Modulfunktionen übergeben werden. Dadurch lassen sich auf einfache Weise insbesondere komplexe Parameter (wie bspw. Perl-Ausdrücke) sehr einfach parsen.&lt;br /&gt;
&lt;br /&gt;
Diese Zusatzfunktion kann man in der Initialize-Funktion einfach über folgenden Parameter für [[#X_Define|Define]]-, [[#X_Get|Get]]- und [[#X_Set|Set]]-Funktion modulweit aktivieren:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;$hash-&amp;gt;{parseParams} = 1;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Sobald es gesetzt ist wird automatisch durch fhem.pl &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#parseParams|parseParams()]]&amp;lt;/code&amp;gt; aufgerufen und die an die [[#X_Define|Define]]-, [[#X_Get|Get]]- und [[#X_Set|Set]]-Funktion übergebenen Parameter ändern sich wie weiter unten in den jeweiligen Funktionen beschrieben.&lt;br /&gt;
&lt;br /&gt;
==== X_Define ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $def ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Define-Funktion eines Moduls wird von FHEM aufgerufen wenn der Define-Befehl für ein Geräte ausgeführt wird und das Modul bereits geladen und mit der Initialize-Funktion initialisiert ist. Sie ist typischerweise dazu da, die übergebenen Parameter zu prüfen und an geeigneter Stelle zu speichern sowie einen Kommunikationsweg zum Gerät zu öffnen (z.B. TCP-Verbindung, USB-Schnittstelle o.ä.) oder einen [[#Pollen_von_Geräten|Status-Timer]] zu starten.&lt;br /&gt;
Sie beginnt typischerweise mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $def ) = @_;&lt;br /&gt;
	my @a = split( &amp;quot;[ \t][ \t]*&amp;quot;, $def );&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als Übergabeparameter bekommt die Define-Funktion den Hash der Geräteinstanz sowie den die im &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl übergebenen Parameter. Welche bzw. wie viele Parameter &lt;br /&gt;
akzeptiert werden und welcher Syntax diese entsprechen müssen ist Sache dieser Funktion. Im obigen Beispiel wird die Argumentzeile &amp;lt;code&amp;gt;$def&amp;lt;/code&amp;gt; in ein Array aufgeteilt (durch Leerzeichen/Tabulator getrennt) und so können die vom Modul bzw. der Define-Funktion erwarteten Werte über das Array der Reihe nach verarbeitet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
my $name   = $a[0];&lt;br /&gt;
my $module = $a[1];&lt;br /&gt;
my $url    = $a[2];&lt;br /&gt;
my $inter  = 300;&lt;br /&gt;
&lt;br /&gt;
if(int(@a) == 4) { &lt;br /&gt;
	$inter = $a[3]; &lt;br /&gt;
	if ($inter &amp;lt; 5) {&lt;br /&gt;
		return &amp;quot;interval too small, please use something &amp;gt; 5s, default is 300 seconds&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit die übergebenen Werte auch anderen Funktionen zur Verfügung stehen und an die jeweilige Geräteinstanz gebunden sind, werden die Werte typischerweise als Internals im Hash der Geräteinstanz gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
$hash-&amp;gt;{url} 		= $url;&lt;br /&gt;
$hash-&amp;gt;{Interval}	= $inter;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald alle Parameter korrekt verarbeitet wurden, wird in der Regel die erste Verbindung zum Gerät aufgebaut. Je nach Art des Geräts kann das eine permanente Datenverbindung sein (z.B. serielle Schnittstelle oder TCP-Verbindung) oder das Starten eines regelmäßigen Timers, der zyklisch den Status z.B. via [[HttpUtils|HTTP]] ausliest.&lt;br /&gt;
&lt;br /&gt;
Sollten im Rahmen der Define-Funktion Syntax-Probleme der Übergabeparameter festgestellt werden oder es kann bspw. keine Verbindung aufgebaut werden, so ist als Funktionsrückgabewert eine entsprechende Fehlermeldung zurückzugeben. Nur wenn alle Übergabeparameter akzeptiert werden, darf &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurückgegeben werden. Sobald eine Define-Funktion eine Fehlermeldung zurückmeldet, wird der define-Befehl durch FHEM zurückgewiesen und der User erhält die Fehlermeldung, welche die Define-Funktion produziert hat, als Ausgabe zurück.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Verfügbarkeit von Attributen&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Während die Define-Funktion ausgeführt wird, sollte man nicht davon ausgehen, dass alle vom Nutzer konfigurierten Attribute via [[DevelopmentModuleAPI#AttrVal|AttrVal()]] verfügbar sind. Attribute stehen in der Define-Funktion nur dann zur Verfügung, wenn FHEM sich nicht in der Initialisierungsphase befindet (globale Variable &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; ist wahr; der Nutzer hat die Gerätedefinition modifiziert). Daher sollte man weiterführende Funktion, welche auf gesetzte Attribute angewiesen sind, nur dann in der Define-Funktion starten, wenn &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; zutrifft.&lt;br /&gt;
&lt;br /&gt;
Andernfalls sollte man den Aufruf in der Notify-Funktion durchführen sobald &amp;lt;code&amp;gt;global:INITIALIZED&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;global:REREADCFG&amp;lt;/code&amp;gt; getriggert wurde:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $def ) = @_;&lt;br /&gt;
 &lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	$hash-&amp;gt;{NOTIFYDEV} = &amp;quot;global&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	X_FunctionWhoNeedsAttr($hash) if($init_done);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub X_Notify($$)&lt;br /&gt;
{&lt;br /&gt;
	my ($own_hash, $dev_hash) = @_;&lt;br /&gt;
	my $ownName = $own_hash-&amp;gt;{NAME}; # own name / hash&lt;br /&gt;
 &lt;br /&gt;
	return &amp;quot;&amp;quot; if(IsDisabled($ownName)); # Return without any further action if the module is disabled&lt;br /&gt;
 &lt;br /&gt;
	my $devName = $dev_hash-&amp;gt;{NAME}; # Device that created the events&lt;br /&gt;
	my $events = deviceEvents($dev_hash, 1);&lt;br /&gt;
&lt;br /&gt;
	if($devName eq &amp;quot;global&amp;quot; &amp;amp;&amp;amp; grep(m/^INITIALIZED|REREADCFG$/, @{$events}))&lt;br /&gt;
	{&lt;br /&gt;
		 X_FunctionWhoNeedsAttr($hash);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dadurch wird die Modulfunktion X_FunctionWhoNeedsAttr() nach dem Start erst aufgerufen, wenn alle Attribute aus der Konfiguration geladen wurden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von parseParams()&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Aufteilen und Parsen von &amp;lt;code&amp;gt;$def&amp;lt;/code&amp;gt; lässt sich die Funktion [[DevelopmentModuleAPI#parseParams|parseParams()]] verwenden um die einzelnen Argumente einfach zu parsen. Wenn in [[#X_Initialize|X_Initialize()]] &amp;lt;code&amp;gt;$hash-&amp;gt;{parseParams} = 1;&amp;lt;/code&amp;gt; gesetzt wurde dann wird parseParams() automatisch aufgerufen und X_Define() ändert sich wie folgt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $a, $h ) = @_;&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die genauen Möglichkeiten von parseParams() sind in dem entsprechenden [[DevelopmentModuleAPI#parseParams|Artikel]] dokumentiert.&lt;br /&gt;
&lt;br /&gt;
==== X_Undef ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Undef ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Die Undef-Funktion wird aufgerufen wenn ein Gerät mit &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; gelöscht wird oder bei der Abarbeitung des Befehls &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt;, der ebenfalls alle Geräte löscht und danach das Konfigurationsfile neu einliest. Entsprechend müssen in der Funktion typische Aufräumarbeiten durchgeführt werden wie das saubere Schließen von Verbindungen oder das Entfernen von internen Timern, sofern diese im Modul zum Pollen verwendet wurden (siehe Abschnitt [[#Pollen_von_Geräten|Pollen von Geräten]]). &lt;br /&gt;
&lt;br /&gt;
Zugewiesene Variablen im Hash der Geräteinstanz, Internals oder Readings müssen hier nicht gelöscht werden. In fhem.pl werden die entsprechenden Strukturen beim Löschen der Geräteinstanz ohnehin vollständig gelöscht.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Undef($$)    &lt;br /&gt;
{                     &lt;br /&gt;
	my ( $hash, $name) = @_;       &lt;br /&gt;
	DevIo_CloseDev($hash);         &lt;br /&gt;
	RemoveInternalTimer($hash);    &lt;br /&gt;
	return undef;                  &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollten im Rahmen der Undef-Funktion Probleme festgestellt werden, die ein Löschen nicht zulassen, so ist als Funktionsrückgabewert eine entsprechende Fehlermeldung zurückzugeben. Nur wenn die Undef-Funktion erfolgreich durchgeführt wurde, darf &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurückgegeben werden. Nur dann wird eine Gerätedefinition von FHEM auch tatsächlich gelöscht bzw. neu angelegt. Sollte die Undef-Funktion jedoch eine Fehlermeldung zurückgeben, wird der entsprechende Vorgang (&amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt;) für dieses Gerät abgebrochen. Es bleibt dann unverändert in FHEM bestehen.&lt;br /&gt;
&lt;br /&gt;
==== X_Delete ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Delete ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Delete-Funktion ist das Gegenstück zur Funktion [[#X_Define|X_Define]] und wird aufgerufen wenn ein Gerät mit dem Befehl &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; gelöscht wird. &lt;br /&gt;
&lt;br /&gt;
Wenn ein Gerät in FHEM gelöscht wird, wird zuerst die Funktion [[#X_Undef|X_Undef]] aufgerufen um offene Verbindungen zu schließen, anschließend wird die Funktion X_Delete aufgerufen. Diese dient eher zum Aufräumen von dauerhaften Daten, welche durch das Modul evtl. für dieses Gerät spezifisch erstellt worden sind. Es geht hier also eher darum, alle Spuren sowohl im laufenden FHEM-Prozess, als auch dauerhafte Daten bspw. im physikalischen Gerät zu löschen die mit dieser Gerätedefinition zu tun haben.&lt;br /&gt;
&lt;br /&gt;
Dies kann z.B. folgendes sein:&lt;br /&gt;
&lt;br /&gt;
* Löschen von Dateien im Dateisystem die während der Nutzung dieses Geräts angelegt worden sind.&lt;br /&gt;
* Lösen von evtl. Pairings mit dem physikalischen Gerät &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Delete($$)    &lt;br /&gt;
{                     &lt;br /&gt;
	my ( $hash, $name ) = @_;       &lt;br /&gt;
&lt;br /&gt;
	# Löschen von Geräte-assoziiertem Temp-File&lt;br /&gt;
	unlink($attr{global}{modpath}.&amp;quot;/FHEM/FhemUtils/$name.tmp&amp;quot;;)&lt;br /&gt;
&lt;br /&gt;
	return undef;&lt;br /&gt;
}    &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollten im Rahmen der Delete-Funktion Probleme festgestellt werden, die ein Löschen nicht zulassen, so ist als Funktionsrückgabewert eine entsprechende Fehlermeldung zurückzugeben. Nur die Delete-Funktion erfolgreich durchgeführt wurde, darf &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurückgegeben werden. Nur dann wird eine Gerätedefinition von FHEM auch tatsächlich gelöscht. Sollte die Delete-Funktion eine Fehlermeldung zurückgeben, wird der Löschvorgang abgebrochen und das Gerät bleibt weiter in FHEM bestehen.&lt;br /&gt;
&lt;br /&gt;
==== X_Get ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Get ($$@)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name, $opt, @args ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $result;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Die Get-Funktion wird aufgerufen wenn der FHEM-Befehl &amp;lt;code&amp;gt;get&amp;lt;/code&amp;gt; für eine Definition dieses Moduls ausgeführt wird. Mit &amp;lt;code&amp;gt;get&amp;lt;/code&amp;gt; werden typischerweise Werte von einem Gerät abgefragt. In vielen Modulen wird auf diese Weise auch der Zugriff auf generierte Readings ermöglicht. Der Get-Funktion wird dabei der Definitions-Hash &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;, der Definitionsname &amp;lt;code&amp;gt;$name&amp;lt;/code&amp;gt;, sowie die Aufrufparameter &amp;lt;code&amp;gt;$opt&amp;lt;/code&amp;gt; plus optional weiterer Parameter &amp;lt;code&amp;gt;@args&amp;lt;/code&amp;gt; übergeben. Als Rückgabewert &amp;lt;code&amp;gt;$result&amp;lt;/code&amp;gt; wird das Ergebnis des entsprechenden Befehls in Form einer Zeichenkette zurückgegeben. Der Rückgabewert &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; hat hierbei keine besondere Bedeutung und wird behandelt wie eine leere Zeichenkette &amp;lt;code&amp;gt;&amp;quot;&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Get($$@)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name, $opt, @args ) = @_;&lt;br /&gt;
&lt;br /&gt;
	return &amp;quot;\&amp;quot;get $name\&amp;quot; needs at least one argument&amp;quot; unless(defined($opt));&lt;br /&gt;
&lt;br /&gt;
	if($opt eq &amp;quot;status&amp;quot;) &lt;br /&gt;
	{&lt;br /&gt;
	   ...&lt;br /&gt;
	}&lt;br /&gt;
	elsif($opt eq &amp;quot;power&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
	   ...&lt;br /&gt;
	}&lt;br /&gt;
	...&lt;br /&gt;
	else&lt;br /&gt;
	{&lt;br /&gt;
		return &amp;quot;Unknown argument $opt, choose one of status power [...]&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn eine unbekannte Option an die Get-Funktion übergeben wird, so muss als Rückgabewert der Funktion eine bestimmte Syntax eingehalten werden um FHEM mitzuteilen, welche Optionen für einen Get-Befehl aktuell unterstützt werden. Dies gilt insbesondere für den Aufruf &amp;lt;code&amp;gt;get &amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;&#039;&#039;&amp;lt;NAME&amp;gt;&#039;&#039;&amp;lt;/font&amp;gt; &amp;lt;u&amp;gt;&#039;&#039;&#039;?&#039;&#039;&#039;&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt;, welche durch verschiedene Module (z.B. FHEMWEB) benutzt wird, um eine Liste aller unterstützten Befehle für eine Definition zu ermitteln. Die Rückgabe muss dabei folgender Syntax entsprechen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&#039;&#039;&#039;unknown&#039;&#039;&#039; argument &#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;[Parameter]&amp;lt;/font&amp;gt;&#039;&#039; &#039;&#039;&#039;choose one of&#039;&#039;&#039; &#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;[Liste möglicher Optionen]&amp;lt;/font&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei sind die fett gedruckten Teile der Rückmeldung besonders wichtig. Sind diese nicht vorhanden, können Module wie FHEMWEB nicht die möglichen Get-Kommandos für das entsprechende Gerät ermitteln. Es muss am Anfang der Meldung das Stichwort &amp;quot;unknown&amp;quot; vorkommen gefolgt von einer frei definierbaren Fehlermeldung (i.d.R der übergebene Parameter, welcher ungültig ist). Anschließend folgt &amp;quot;choose one of&amp;quot; mit einer anschließenden Liste möglicher Optionen getrennt durch ein Leerzeichen. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;return &amp;quot;unknown argument $opt choose one of status temperature humidity&amp;quot;;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden als mögliche Optionen für einen Get-Befehl folgende Parameter angegeben:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;temperature&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;humidity&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies würde in folgenden, mögliche Get-Befehle für einen User resultieren:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;get &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; status&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;get &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; temperature&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;get &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; humidity&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im weiteren Verlauf der Get-Funktion könnte man dann mit dem physischen Gerät kommunizieren und den gefragten Wert direkt abfragen und diesen als Return-Wert der Get-Funktion zurückgeben. Vielfach werden aber auch die vorhandenen Readings zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von parseParams()&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in [[#X_Initialize|X_Initialize()]] &amp;lt;code&amp;gt;$hash-&amp;gt;{parseParams} = 1;&amp;lt;/code&amp;gt; gesetzt wurde dann wird [[DevelopmentModuleAPI#parseParams|parseParams()]] automatisch aufgerufen und X_Get() ändert sich wie folgt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Get($$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $a, $h ) = @_;&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die genauen Möglichkeiten von parseParams() sind in dem entsprechenden [[DevelopmentModuleAPI#parseParams|Artikel]] dokumentiert.&lt;br /&gt;
&lt;br /&gt;
==== X_Set ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Set ($$@)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name, $cmd, @args ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	return $error;&lt;br /&gt;
	return ($error, $skip_trigger);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Set-Funktion ist das Gegenteil zur [[#X_Get|Get]]-Funktion. Sie ist dafür gedacht, Daten zum physischen Gerät zu schicken, bzw. entsprechende Aktionen im Gerät selber auszulösen. Ein Set-Befehl dient daher der direkten Steuerung des physikalischen Gerätes in dem es bspw. Zustände verändert (wie &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt;). Der Set-Funktion wird dabei der Definitions-Hash &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;, der Definitionsname &amp;lt;code&amp;gt;$name&amp;lt;/code&amp;gt;, sowie die Aufrufparameter &amp;lt;code&amp;gt;$cmd&amp;lt;/code&amp;gt; und optional weitere Argumente &amp;lt;code&amp;gt;@args&amp;lt;/code&amp;gt; übergeben. Als Rückgabewert &amp;lt;code&amp;gt;$error&amp;lt;/code&amp;gt; kann eine Fehlermeldung in Form Zeichenkette zurückgegeben werden. Der Rückgabewert &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; bedeutet hierbei, dass der Set-Befehl erfolgreich durchgeführt wurde. Eine Set-Funktion gibt daher nur im Fehlerfall eine Rückmeldung mit einer entsprechenden Fehlermeldung. Der Wert &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; wird als &amp;quot;erfolgreich&amp;quot; interpretiert. &lt;br /&gt;
&lt;br /&gt;
Standardmäßig wird jeder Set-Befehl, welcher erfolgreich ausgeführt wurde (&amp;lt;code&amp;gt;$error&amp;lt;/code&amp;gt; ist &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt;), als Event getriggert um dies bspw. in einem FileLog festzuhalten. Dieses Verhalten kann optional unterbunden werden indem der optionale zweite Rückgabewert &amp;lt;code&amp;gt;$skip_trigger&amp;lt;/code&amp;gt; auf &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; gesetzt wird. Damit wird das Generieren eines Events für das erfolgreich ausgeführte Set-Kommando unterbunden. Falls nicht gesetzt, wird ein Event erzeugt (&amp;lt;code&amp;gt;$cmd&amp;lt;/code&amp;gt; mit sämtlichen &amp;lt;code&amp;gt;@args&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Rückmeldungen (Fehler) von set-Befehlen sämtlicher Module, die im Rahmen der Ausführung eines getriggerten [[Notify]] auftreten, werden im FHEM Logfile festgehalten.&lt;br /&gt;
&lt;br /&gt;
Falls nur interne Daten, die ausschließlich für das Modul relevant sind, gesetzt werden müssen, so sollte statt Set die [[#X_Attr|Attr]]-Funktion verwendet werden. Attribute werden bei Save-Config auch in der Fhem.cfg gesichert. Set-Befehle nicht, da sie nur zu Steuerungszwecken im laufenden Betrieb von FHEM dienen.&lt;br /&gt;
 &lt;br /&gt;
Eine Set-Funktion ist ähnlich aufgebaut wie die Get-Funktion, sie bekommt jedoch in der Regel weitere zusätzliche Parameter (&amp;lt;code&amp;gt;@args&amp;lt;/code&amp;gt;) übergeben um Zustände zu setzen/ändern. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Set($@)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name, $cmd, @args ) = @_;&lt;br /&gt;
&lt;br /&gt;
	return &amp;quot;\&amp;quot;set $name\&amp;quot; needs at least one argument&amp;quot; unless(defined($cmd));&lt;br /&gt;
&lt;br /&gt;
	if($cmd eq &amp;quot;status&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
	   if($args[0] eq &amp;quot;up&amp;quot;)&lt;br /&gt;
	   {&lt;br /&gt;
	      ...&lt;br /&gt;
	   }&lt;br /&gt;
	   elsif($args[0] eq &amp;quot;down&amp;quot;)&lt;br /&gt;
	   {&lt;br /&gt;
	      ...&lt;br /&gt;
	   }&lt;br /&gt;
	   else&lt;br /&gt;
	   {&lt;br /&gt;
	      return &amp;quot;Unknown value $args[0] for $cmd, choose one of status power&amp;quot;;&lt;br /&gt;
	   }   &lt;br /&gt;
	}&lt;br /&gt;
	elsif($cmd eq &amp;quot;power&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
	   if($args[0] eq &amp;quot;on&amp;quot;)&lt;br /&gt;
	   {&lt;br /&gt;
	      ...&lt;br /&gt;
	   }&lt;br /&gt;
	   elsif($args[0] eq &amp;quot;off&amp;quot;)&lt;br /&gt;
	   {&lt;br /&gt;
	      ...&lt;br /&gt;
	   }  &lt;br /&gt;
	   else&lt;br /&gt;
	   {&lt;br /&gt;
	      return &amp;quot;Unknown value $args[0] for $cmd, choose one of status power&amp;quot;;&lt;br /&gt;
	   }       &lt;br /&gt;
	}&lt;br /&gt;
	...&lt;br /&gt;
	else&lt;br /&gt;
	{&lt;br /&gt;
		return &amp;quot;Unknown argument $cmd, choose one of status power&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn eine unbekannte Option an die Set-Funktion übergeben wird, so muss als Rückgabewert der Funktion eine bestimmte Syntax eingehalten werden um FHEM mitzuteilen, welche Optionen für einen Set-Befehl aktuell unterstützt werden. Dies gilt insbesondere für den Aufruf &amp;lt;code&amp;gt;set &amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;&#039;&#039;&amp;lt;NAME&amp;gt;&#039;&#039;&amp;lt;/font&amp;gt; &amp;lt;u&amp;gt;&#039;&#039;&#039;?&#039;&#039;&#039;&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt;, welcher durch verschiedene Module (z.B. FHEMWEB) benutzt wird, um eine Liste aller unterstützten Befehle für eine Definition zu ermitteln. Die Rückgabe muss dabei folgender Syntax entsprechen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&#039;&#039;&#039;unknown&#039;&#039;&#039; argument &#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;[Parameter]&amp;lt;/font&amp;gt;&#039;&#039; &#039;&#039;&#039;choose one of&#039;&#039;&#039; &#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;[Liste möglicher Optionen]&amp;lt;/font&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei sind die fett gedruckten Teile der Rückmeldung besonders wichtig. Sind diese nicht vorhanden, können Module wie FHEMWEB nicht die möglichen Set-Kommandos für das entsprechende Gerät ermitteln. Es muss am Anfang der Meldung das Stichwort &amp;quot;unknown&amp;quot; vorkommen gefolgt von einer frei definierbaren Fehlermeldung (i.d.R der übergebene Parameter, welcher ungültig ist). Anschließend folgt &amp;quot;choose one of&amp;quot; mit einer anschließenden Liste möglicher Optionen getrennt durch ein Leerzeichen. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;return &amp;quot;unknown argument $cmd choose one of status power&amp;quot;;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden als mögliche Optionen für einen Set-Befehl folgende Parameter angegeben:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;power&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies würde in folgenden, mögliche Set-Befehle für einen User resultieren:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;set &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; status&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;set &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; power&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von SetExtensions.pm&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn man dem Nutzer zusätzlich zu den Set-Befehlen &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; auch weiterführende Befehle wie &amp;lt;code&amp;gt;on-for-timer&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;on-till&amp;lt;/code&amp;gt;, usw. anbieten möchte, obwohl die zu steuernde Hardware solche Kommandos nicht unterstützt, kann man dies über das Hilfsmodul SetExtensions.pm realisieren.&lt;br /&gt;
&lt;br /&gt;
Das Hilfsmodul SetExtensions.pm bietet weiterführende Set-Kommandos basierend auf den Befehlen &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; an. Dabei werden durch interne Timer bzw. eigens angelegten [[at]]-Definitionen diese Befehle durch FHEM selber umgesetzt. Je nach ausgeführtem Befehl wird der &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;- bzw. &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt;-Befehl dann durch FHEM zum richtigen Zeitpunkt ausgeführt. Vorausgesetzt das Modul unterstützt in der Set-Funktion die Befehle &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt;, so werden durch den Einsatz von SetExtensions.pm folgende Befehle zusätzlich unterstützt:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Set-Kommando !! Beispiel !! Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-for-timer &#039;&#039;&amp;amp;lt;Dauer&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-for-timer 120&amp;lt;/code&amp;gt; || Schaltet das Gerät sofort mit dem &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;-Befehl ein und nach der angegebenen Dauer in Sekunden via &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; wieder aus.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-for-timer &#039;&#039;&amp;amp;lt;Dauer&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-for-timer 120&amp;lt;/code&amp;gt; || Schaltet das Gerät sofort mit dem &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt;-Befehl aus und nach der angegebenen Dauer in Sekunden via &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; wieder ein.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-till &#039;&#039;&amp;amp;lt;Zeitpunkt&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-till 16:30&amp;lt;/code&amp;gt; || Schaltet das Gerät sofort mit dem &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;-Befehl ein und zum angegebenen Zeitpunkt via &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; wieder aus.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-till &#039;&#039;&amp;amp;lt;Zeitpunkt&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-till 16:30&amp;lt;/code&amp;gt; || Schaltet das Gerät sofort mit dem &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt;-Befehl aus und zum angegebenen Zeitpunkt via &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; wieder ein.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-till-overnight &#039;&#039;&amp;amp;lt;Zeitpunkt&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-till-overnight 01:00&amp;lt;/code&amp;gt; || Ähnlich wie &amp;lt;code&amp;gt;on-till&amp;lt;/code&amp;gt;. Der übergebene Zeitpunkt wird aber nicht geprüft, ob er für den heutigen Tag bereits überschritten wurde. Dadurch kann man Abends einen Zeitpunkt setzen, der erst am nächsten Tag zutrifft.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-till-overnight &#039;&#039;&amp;amp;lt;Zeitpunkt&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-till-overnight 01:00&amp;lt;/code&amp;gt; || Ähnlich wie &amp;lt;code&amp;gt;off-till&amp;lt;/code&amp;gt;. Der übergebene Zeitpunkt wird aber nicht geprüft, ob er für den heutigen Tag bereits überschritten wurde. Dadurch kann man Abends einen Zeitpunkt setzen, der erst am nächsten Tag zutrifft.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;blink &#039;&#039;&amp;amp;lt;Anzahl&amp;amp;gt; &amp;amp;lt;Interval&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;blink 3 1&amp;lt;/code&amp;gt; || Schaltet das Gerät via &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; für &amp;lt;code&amp;gt;&#039;&#039;&amp;amp;lt;Interval&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; Sekunden ein und anschließend via &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; wieder aus. Nach &amp;lt;code&amp;gt;&#039;&#039;&amp;amp;lt;Interval&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; Sekunden wird das ganze wiederholt, solange bis die angegebene Anzahl erreicht ist.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;intervals &#039;&#039;&amp;amp;lt;Start&amp;amp;gt;-&amp;amp;lt;Ende&amp;amp;gt;&#039;&#039; &#039;&#039;&amp;amp;lt;Start&amp;amp;gt;-&amp;amp;lt;Ende&amp;amp;gt;&#039;&#039; ...&amp;lt;/code&amp;gt; || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;intervals 07:00-08:00 16:30-18:00&amp;lt;/code&amp;gt; || Schaltet das Gerät innerhalb der übergebenen Zeiträumen via &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; ein. Sobald die aktuelle Zeit ausserhalb dieser Zeiträume liegt, wird das Gerät via &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; wieder ausgeschaltet. Es können dabei beliebig viele Zeiträume angegeben werden.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;toggle&amp;lt;/code&amp;gt; || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;toggle&amp;lt;/code&amp;gt;  || Sofern der aktuelle Status &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; ist, wird das Gerät via &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; ausgeschaltet. Andernfalls wird es via &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; eingeschaltet.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Eine kurze Beschreibung zu den möglichen Befehlen durch SetExtensions.pm gibt es auch in der commandref zum {{Link2CmdRef|Anker=set|Label=set-Befehl}}.&lt;br /&gt;
&lt;br /&gt;
Um SetExtensions.pm in der Set-Funktion nutzen zu können müssen folgende Aktionen durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Laden von SetExtensions.pm via &amp;lt;code&amp;gt;use SetExtensions;&amp;lt;/code&amp;gt; am Anfang des Moduls&lt;br /&gt;
# Aufruf und Rückgabe der Funktion [[DevelopmentModuleAPI#SetExtensions|SetExtensions()]] sofern die Set-Funktion mit dem übergebenen Befehl nichts anfangen kann.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
use SetExtensions;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
sub X_Set($@)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name, $cmd, @args ) = @_;&lt;br /&gt;
	my $cmdList = &amp;quot;on off&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	return &amp;quot;\&amp;quot;set $name\&amp;quot; needs at least one argument&amp;quot; unless(defined($cmd));&lt;br /&gt;
&lt;br /&gt;
	if($cmd eq &amp;quot;on&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
		# Gerät einschalten...&lt;br /&gt;
	}&lt;br /&gt;
	elsif($cmd eq &amp;quot;off&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
		# Gerät ausschalten...&lt;br /&gt;
	}&lt;br /&gt;
	...&lt;br /&gt;
	else # wenn der übergebene Befehl nicht durch X_Set() verarbeitet werden kann, Weitergabe an SetExtensions()&lt;br /&gt;
	{&lt;br /&gt;
		return SetExtensions($hash, $cmdList, $name, $cmd, @args);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte der übergebene Set-Befehl auch für SetExtensions unbekannt sein (bspw. &amp;lt;code&amp;gt;set &#039;&#039;&amp;amp;lt;Name&amp;amp;gt;&#039;&#039; ?&amp;lt;/code&amp;gt;), so generiert SetExtensions() eine entsprechende Usage-Meldung, welche innerhalb der Set-Funktion an FHEM zurückgegeben werden muss.&lt;br /&gt;
&lt;br /&gt;
Eine ausführliche Beschreibung zu der Funktion SetExtensions() gibt es in der  [[DevelopmentModuleAPI#SetExtensions|API-Referenz]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von parseParams()&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in [[#X_Initialize|X_Initialize()]] &amp;lt;code&amp;gt;$hash-&amp;gt;{parseParams} = 1;&amp;lt;/code&amp;gt; gesetzt wurde dann wird [[DevelopmentModuleAPI#parseParams|parseParams()]] automatisch aufgerufen und X_Set() ändert sich wie folgt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Set($$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $a, $h ) = @_;&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die genauen Möglichkeiten von parseParams() sind in dem entsprechenden [[DevelopmentModuleAPI#parseParams|Artikel]] dokumentiert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von FHEMWEB-Widgets&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das GUI-Modul [[FHEMWEB]] kann für die einzelnen Set-Optionen, die das Modul versteht, automatisch Eingabehilfen wie Drop-Down Boxen oder Slider erzeugen. In der Detailansicht der GUI kann der Anwender dann die jeweiligen Werte komfortabel auswählen. Dafür muss die Set-Funktion, wenn sie mit der Option &amp;lt;code&amp;gt;?&amp;lt;/code&amp;gt; aufgerufen wird, nicht nur einen Text mit  &amp;lt;code&amp;gt;&amp;quot;Unknown ... choose one of ...&amp;quot;&amp;lt;/code&amp;gt; zurückgeben sondern den einzelnen Set-Optionen in diesem Rückgabetext nach einem Doppelpunkt entsprechende Zusatzinformationen anhängen.&lt;br /&gt;
Meist prüft man in den Modulen gar nicht auf die Option &amp;lt;code&amp;gt;?&amp;lt;/code&amp;gt; sondern gibt generell bei unbekannten Optionen diesen Text zurück. Das Modul FHEMWEB ermittelt die Syntax eines Gerätes jedoch immer mit dem Befehl:&lt;br /&gt;
 set &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; ?&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
	return &amp;quot;Unknown argument $cmd, choose one of status:up,down power:on,off on:noArg off:noArg&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit Kommata getrennte Werte ergeben eine Drop-Down Liste, mit der der User die Werte auswählen kann&lt;br /&gt;
&amp;lt;pre&amp;gt;timer:30,120,300&lt;br /&gt;
mode:verbose,ultra,relaxed&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wird kein Doppelpunkt zum Kommando angegeben, so wird eine Eingabezeile angezeigt, die die freie Eingabe eines Wertes erlaubt.&lt;br /&gt;
&lt;br /&gt;
Man kann jedoch die Eingabe-/Auswahlmöglichkeiten durch Widgets vereinfachen. Dazu gibt man hinter dem Doppelpunkt einen Widgetnamen und widgetspezifische Parameter an. Es existieren mehrere solcher Widgets in FHEMWEB. Die gebräuchlichsten sind:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Zusatz !! Beispiel !! Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;noArg&#039;&#039;&#039; || &amp;lt;code&amp;gt;reset:noArg&amp;lt;/code&amp;gt;|| Es werden keine weiteren Argumente mehr benötigt. In so einem Fall wird bei der Auswahl keine Textbox oder ähnliches angezeigt, da keine weiteren Argumente für diesen Befehl notwendig sind.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;slider&#039;&#039;&#039;,&amp;lt;min&amp;gt;,&amp;lt;step&amp;gt;,&amp;lt;max&amp;gt; || &amp;lt;code&amp;gt;dim:slider,0,1,100&amp;lt;/code&amp;gt;|| Es wird ein Schieberegler angezeigt um den Parameter auszuwählen. Dabei werden als Zusatzparameter Minimum, Schrittweite und Maximum angegeben.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;colorpicker&#039;&#039;&#039; || &amp;lt;code&amp;gt;rgb:colorpicker,RGB&amp;lt;/code&amp;gt;|| Es wird ein Colorpicker angezeigt, der dem Anwender die Auswahl einer Farbe ermöglicht. Die genaue Parametersyntax kann man dem Artikel zum  [[Color#Colorpicker|Colorpicker]] entnehmen.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;multiple&#039;&#039;&#039; || &amp;lt;code&amp;gt;group:multiple,Telefon,Multimedia,Licht,Heizung&amp;lt;/code&amp;gt; || Es erscheint ein Auswahldialog, wo man verschiedene Werte durch klicken auswählen kann. Optional kann man in einem Freitext eigene Werte ergänzen. dieser Dialog wird bspw. bei der Raum-Auswahl (Attribut &amp;quot;room&amp;quot;) oder der Gruppen-Auswahl (Attribut &amp;quot;group&amp;quot;) in FHEMWEB genutzt. &lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;sortable&#039;&#039;&#039; || &amp;lt;code&amp;gt;command:sortable,monday,tuesday,...&amp;lt;/code&amp;gt; || Es erscheint ein Auswahldialog, wo man verschiedene Werte auswählen und sortieren kann. Man kann dabei Werte durch Klicken auswählen und durch Drag&#039;n&#039;Drop sortieren.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Es gibt noch weitere solcher Widgets. Eine genaue Auflistung dazu findet sich in der {{Link2CmdRef|Anker=widgetOverride}} unter widgetOverride zu FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweise&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Damit in einer Eingabe bereits der aktuelle Wert vorbelegt bzw. in einer Auswahlliste der aktuelle Wert vorselektiert ist, muss es im Modul bzw. Gerät ein Reading mit dem gleichen Namen wie die Set-Option geben. Der Wert des gleichnamigen Readings wird dann als Vorbelegung / Vorselektion verwendet. &lt;br /&gt;
* Der User kann sich in der Raumübersicht nach wie vor via [[WebCmd|webCmd]] eine entsprechende Steuerung anlegen.&lt;br /&gt;
&lt;br /&gt;
==== X_Attr ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Attr($$$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $cmd, $name, $attrName, $attrValue  ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Attr-Funktion dient der Prüfung von Attributen, welche über den &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt;-Befehl gesetzt werden können. Sobald versucht wird, ein Attribut für ein Gerät zu setzen, wird vorher die Attr-Funktion des entsprechenden Moduls aufgerufen um zu prüfen, ob das Attribut aus Sicht des Moduls korrekt ist.&lt;br /&gt;
Liegt ein Problem mit dem Attribut bzw. dem Wert vor, so muss die Funktion eine aussagekräftige Fehlermeldung zurückgeben, welche dem User angezeigt wird.&lt;br /&gt;
Sofern das übergebene Attribut samt Inhalt korrekt ist, gibt die Attr-Funktion den Wert &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurück. Erst dann wird das Attribut in der globalen Datenstruktur &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt; gespeichert und ist somit erst aktiv.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Attr($$$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $cmd, $name, $attrName, $attrValue ) = @_;&lt;br /&gt;
    &lt;br /&gt;
  	# $cmd  - Vorgangsart - kann die Werte &amp;quot;del&amp;quot; (löschen) oder &amp;quot;set&amp;quot; (setzen) annehmen&lt;br /&gt;
	# $name - Gerätename&lt;br /&gt;
	# $attrName/$attrValue sind Attribut-Name und Attribut-Wert&lt;br /&gt;
    &lt;br /&gt;
	if ($cmd eq &amp;quot;set&amp;quot;) {&lt;br /&gt;
		if ($aName eq &amp;quot;Regex&amp;quot;) {&lt;br /&gt;
			eval { qr/$aVal/ };&lt;br /&gt;
			if ($@) {&lt;br /&gt;
				Log3 $name, 3, &amp;quot;X ($name) - Invalid regex in attr $name $aName $aVal: $@&amp;quot;;&lt;br /&gt;
				return &amp;quot;Invalid Regex $aVal: $@&amp;quot;;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	return undef;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zusätzlich ist es möglich auch übergebene Attributwerte zu verändern bzw. zu korrigieren, indem man im Parameterarray &amp;lt;code&amp;gt;@_&amp;lt;/code&amp;gt; den ursprünglichen Wert anpasst. Dies erfolgt im Beispiel über die Modifikation des Wertes mit Index 3 (entspricht dem 4. Element) im Parameterarray, also &amp;lt;code&amp;gt;$_[3]&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Da das Attribut zum Zeitpunkt des Aufrufs der Attr-Funktion noch nicht gespeichert ist, wird der neue Wert zu diesem Zeitpunkt noch nicht via [[DevelopmentModuleAPI#AttrVal|AttrVal()]] zurückgegeben. Erst, wenn die Attr-Funktion mit &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; beendet ist, wird der neue Wert in FHEM gespeichert und steht dann via AttrVal() zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Die Attr-Funktion bekommt nicht den Hash der Geräteinstanz übergeben, da sie normalerweise keine Werte dort speichern muss, sondern lediglich das Attribut auf Korrektheit prüfen muss.&lt;br /&gt;
Im obigen Beispiel wird für ein Attribut mit Namen &amp;quot;Regex&amp;quot; geprüft ob der reguläre Ausdruck fehlerhaft ist. Sofern dieser OK ist, wird &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurückgegeben und fhem.pl speichert den Wert des Attributs in &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Attributnamen mit Platzhaltern&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls man Attribute in der [[#X_Initialize|Initialize]]-Funktion mit Platzhaltern definiert (Wildcard-Attribute) wie z.B.:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
    $hash-&amp;gt;{AttrList} =&lt;br /&gt;
      &amp;quot;reading[0-9]*Name &amp;quot; .&lt;br /&gt;
    # usw.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
dann können Anwender Attribute wie reading01Name, reading02Name etc. setzen. Leider funktioniert das bisher nicht durch Klicken in der Web-Oberfläche, da FHEMWEB nicht alle denkbaren Ausprägungen in einem Dropdown anbieten kann. Der Benutzer muss solche Attribute manuell über den &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt;-Befehl eingeben.&lt;br /&gt;
&lt;br /&gt;
Man kann jedoch in der Attr-Funktion neu gesetzte Ausprägungen von Wildcard-Attributen an die gerätespezifische userattr-Variable anfügen. Dann können bereits gesetzte Attribute in FHEMWEB durch Klicken ausgewählt und geändert werden.&lt;br /&gt;
Dazu reicht ein Aufruf der Funktion [[DevelopmentModuleAPI#addToDevAttrList|addToDevAttrList()]]: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
    addToDevAttrList($name, $aName);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Read ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Read ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Die X_Read-Funktion wird aufgerufen, wenn ein dem Gerät zugeordneter Filedeskriptor (serielle Schnittstelle, TCP-Verbindung, ...) Daten zum Lesen bereitgestellt hat. Die Daten müssen nun eingelesen und interpretiert werden.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird über eine serielle Schnittstelle (beziehungsweise über einen USB-To-Serial-Konverter) von einem angeschlossenen Gerät gelesen. Dazu werden die bisher verfügbaren Daten mit der Funktion [[DevIo#DevIo_SimpleRead()|DevIo_SimpleRead()]] gelesen. Da die Übertragung möglicherweise noch nicht vollständig ist, kann es sein, dass kurz darauf die X_Read-Funktion wieder aufgerufen wird und ein weiterer Teil oder der Rest der Daten gelesen werden kann.&lt;br /&gt;
Die Funktion muss daher prüfen ob schon alle erwarteten Daten angekommen sind und gegebenenfalls die bisher gelesenen Daten in einem eigenen Puffer (idealerweise in &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;) zwischenspeichern (siehe auch [[DevIo#Hinweis bei der Datenverarbeitung (Buffering)|DevIo]]). Im Beispiel ist dies &amp;lt;code&amp;gt;$hash-&amp;gt;{helper}{BUFFER}&amp;lt;/code&amp;gt; an den die aktuell gelesenen Daten angehängt werden, bis die folgende Prüfung ein für das jeweilige Protokoll vollständige Frame erkennt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Read($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
	my $name = $hash-&amp;gt;{NAME};&lt;br /&gt;
	&lt;br /&gt;
	# einlesen der bereitstehenden Daten&lt;br /&gt;
	my $buf = DevIo_SimpleRead($hash);		&lt;br /&gt;
	return &amp;quot;&amp;quot; if ( !defined($buf) );&lt;br /&gt;
	Log3 $name, 5, &amp;quot;X ($name) - received data: &amp;quot;.$buf;    &lt;br /&gt;
&lt;br /&gt;
	# Daten in Hex konvertieren und an den Puffer anhängen&lt;br /&gt;
	$hash-&amp;gt;{helper}{BUFFER} .= unpack (&#039;H*&#039;, $buf);	&lt;br /&gt;
	Log3 $name, 5, &amp;quot;X ($name) - current buffer content: &amp;quot;.$hash-&amp;gt;{helper}{BUFFER};&lt;br /&gt;
&lt;br /&gt;
	# prüfen, ob im Buffer ein vollständiger Frame zur Verarbeitung vorhanden ist.&lt;br /&gt;
	if ($hash-&amp;gt;{helper}{BUFFER} =~ &amp;quot;ff1002(.{4})(.*)1003(.{4})ff(.*)&amp;quot;) {&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die zu lesenden Nutzdaten können dann je nach Protokoll des Geräts beispielsweise an einer festgelegten Stelle im Frame (dann in &amp;lt;code&amp;gt;$hash-&amp;gt;{helper}{BUFFER}&amp;lt;/code&amp;gt;) stehen oder aus dem Kontext mit einem Regex-Match extrahiert werden und via [[DevelopmentModuleAPI#Readings_.2F_Events|Reading-Funktionen]] in Readings gespeichert werden (siehe unten).&lt;br /&gt;
&lt;br /&gt;
Der Rückgabewert der Read-Funktion wird nicht geprüft und hat daher keinerlei Bedeutung.&lt;br /&gt;
&lt;br /&gt;
==== X_Ready ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Ready ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
    &lt;br /&gt;
	return $success;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wird im Main-Loop aufgerufen falls das Modul in der globalen Liste &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt; existiert. Diese Funktion hat, je nachdem auf welchem OS FHEM ausgeführt wird, unterschiedliche Aufgaben:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;UNIX-artiges Betriebssystem:&#039;&#039;&#039; prüfen, ob eine Verbindung nach einem Verbindungsabbruch wieder aufgebaut werden kann. Sobald der Verbindungsaufbau erfolgreich war, muss die Funktion einen erfolgreichen Wahrheitswert zurückliefern (z.B. &amp;quot;1&amp;quot;) und den eigenen Eintrag entsprechend aus &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt; löschen.&lt;br /&gt;
* &#039;&#039;&#039;Windows-Betriebssystem:&#039;&#039;&#039; prüfen, ob lesbare Daten für ein serielles Device (via COM1, COM2, ...) vorliegen. Sofern lesbare Daten vorliegen, muss Funktion einen erfolgreichen Wahrheitswert zurückliefern (z.B. &amp;quot;1&amp;quot;). Zusätzlich dazu muss die Funktion, wie bei UNIX-artigen Betriebssystem, ebenfalls bei einem Verbindungsabbruch einen neuen Verbindungsversuch initiieren. Der Eintrag in &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt; bleibt solange erhalten, bis die Verbindung seitens FHEM beendet wird.&lt;br /&gt;
&lt;br /&gt;
Der Windows-spezifische Teil zur Datenprüfung ist dabei nur zu implementieren, wenn das Modul über eine serielle Verbindung kommuniziert.&lt;br /&gt;
&lt;br /&gt;
Bei der Nutzung des Moduls [[DevIo]] wird dem Modulentwickler der Umgang mit &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt; abgenommen, da DevIo sich selbst um die entsprechenden Einträge kümmert und diese selbstständig wieder entfernt.&lt;br /&gt;
&lt;br /&gt;
In der Regel sieht eine Ready-Funktion immer gleich aus.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Ready($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
      &lt;br /&gt;
	# Versuch eines Verbindungsaufbaus, sofern die Verbindung beendet ist.&lt;br /&gt;
	return DevIo_OpenDev($hash, 1, undef ) if ( $hash-&amp;gt;{STATE} eq &amp;quot;disconnected&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
	# This is relevant for Windows/USB only&lt;br /&gt;
	if(defined($hash-&amp;gt;{USBDev})) {&lt;br /&gt;
		my $po = $hash-&amp;gt;{USBDev};&lt;br /&gt;
		my ( $BlockingFlags, $InBytes, $OutBytes, $ErrorFlags ) = $po-&amp;gt;status;&lt;br /&gt;
		return ( $InBytes &amp;gt; 0 );&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Notify ====&lt;br /&gt;
&lt;br /&gt;
Die X_Notify-Funktion wird aus der Funktion [[DevelopmentModuleAPI#DoTrigger|DoTrigger()]] in fhem.pl heraus aufgerufen sobald ein Modul Events erzeugt hat. Damit kann ein Modul auf Events anderer Module reagieren. Typische Beispiele sind dabei das [[FileLog]]-Modul oder das [[notify]]-Modul.&lt;br /&gt;
&lt;br /&gt;
Die Notify-Funktion bekommt dafür zwei Hash-Referenzen übergeben: den Hash des eigenen Geräts und den Hash des Geräts, das die Events erzeugt hat. &lt;br /&gt;
Über den Hash des eigenen Geräts kann die Notify-Funktion beispielsweise auf die Internals oder Attribute des eigenen Geräts zugreifen.&lt;br /&gt;
Über den Hash des Gerätes und der [[DevelopmentModuleAPI#deviceEvents|deviceEvents()]]-Funktion kann man auf die generierten Events zugreifen. Über den zweiten Parameter dieser Routine lässt sich bestimmen ob für das Reading &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; ein &#039;normales&#039; Event (d.h. in der form &amp;lt;code&amp;gt;state: &amp;lt;wert&amp;gt;&amp;lt;/code&amp;gt;) erzeugen soll (Wert: 1) oder ob z.b. aus Gründen der Rückwärtskompatibilität ein Event ohne &amp;lt;code&amp;gt;state: &amp;lt;/code&amp;gt; erzeugt werden soll. Falls dem Anwender die Wahl des verwendeten Formats überlassen werden soll ist hierzu das {{Link2CmdRef|Anker=addStateEvent|Lang=de|Label=addStateEvent-Attribut}} vorzusehen.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff auf &amp;lt;code&amp;gt;$hash-&amp;gt;{CHANGED}&amp;lt;/code&amp;gt; ist nicht mehr zu empfehlen.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Notify($$)&lt;br /&gt;
{&lt;br /&gt;
  my ($own_hash, $dev_hash) = @_;&lt;br /&gt;
  my $ownName = $own_hash-&amp;gt;{NAME}; # own name / hash&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot; if(IsDisabled($ownName)); # Return without any further action if the module is disabled&lt;br /&gt;
&lt;br /&gt;
  my $devName = $dev_hash-&amp;gt;{NAME}; # Device that created the events&lt;br /&gt;
&lt;br /&gt;
  my $events = deviceEvents($dev_hash,1);&lt;br /&gt;
  return if( !$events );&lt;br /&gt;
&lt;br /&gt;
  foreach my $event (@{$events}) {&lt;br /&gt;
    $event = &amp;quot;&amp;quot; if(!defined($event));&lt;br /&gt;
&lt;br /&gt;
    # Examples:&lt;br /&gt;
    # $event = &amp;quot;readingname: value&amp;quot; &lt;br /&gt;
    # or&lt;br /&gt;
    # $event = &amp;quot;INITIALIZED&amp;quot; (for $devName equal &amp;quot;global&amp;quot;)&lt;br /&gt;
    #&lt;br /&gt;
    # processing $event with further code&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Begrenzung der Aufrufe auf bestimmte Geräte&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da die Notify-Funktion für jedes definierte Gerät mit all seinen Events aufgerufen wird, muss sie in einer Schleife jedesmal prüfen und entscheiden, ob es mit dem jeweiligen Event etwas anfangen kann. Ein Gerät, das die Notify-Funktion implementiert, sieht dafür typischerweise einen regulären Ausdruck vor, welcher für die Filterung verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Wenn man nur gezielt von bestimmten Definitionen Events erhalten will, kann man diese auch in Form einer {{Link2CmdRef|Lang=de|Anker=devspec|Label=devspec}} in &amp;lt;code&amp;gt;$hash-&amp;gt;{NOTIFYDEV}&amp;lt;/code&amp;gt; angeben. Bspw. kann man in der Define-Funktion diesen Wert setzen. Dadurch wird die Notify-Funktion nur aufgerufen wenn eine der Definitionen, auf welche die devspec passt, ein Event erzeugt hat. Ein typischer Fall ist die Begrenzung von Events auf &amp;quot;global&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
in der Define-Funktion:&lt;br /&gt;
&lt;br /&gt;
$hash-&amp;gt;{NOTIFYDEV} = &amp;quot;global&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{NOTIFYDEV} = &amp;quot;global,Definition_.*&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{NOTIFYDEV} = &amp;quot;global,Definition_A,Definition_B&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{NOTIFYDEV} = &amp;quot;global,TYPE=CUL_HM&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies schont insbesondere bei grossen Installationen Ressourcen, da die Notify-Funktion nicht sämtliche Events, sondern nur noch Events der gewünschten Definitionen erhält. Dadurch erfolgen deutlich weniger Aufrufe der Notify-Funktion, was Systemressourcen schont.&lt;br /&gt;
&lt;br /&gt;
Sofern in der [[#X_Define|Define-Funktion]] eine Regexp als Argument übergeben wird, die ähnlich wie beim Modul [[notify]] auf Events wie &amp;lt;code&amp;gt;&amp;amp;lt;Definitionsname&amp;amp;gt;&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;&amp;amp;lt;Definitionsname&amp;amp;gt;:&amp;amp;lt;Event&amp;amp;gt;&amp;lt;/code&amp;gt; reagiert, so sollte man in der Define-Funktion die Funktion [[DevelopmentModuleAPI#notifyRegexpChanged|notifyRegexpChanged()]] verwenden. Diese versucht einen passenden Eintrag für &amp;lt;code&amp;gt;$hash-&amp;gt;{NOTIFYDEV}&amp;lt;/code&amp;gt; basierend auf der übergebenen Regexp zu setzen, sofern dies möglich ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Reihenfolge für den Aufruf der Notify-Funktion beeinflussen&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald ein Event ausgelöst wurde, stellt sich FHEM eine Liste aller relevanten Geräte-Hashes zusammen, welche via Notify-Funktion prüfen müssen, ob das Event relevant ist. Dabei wird die Liste nach &amp;lt;code&amp;gt;$hash-&amp;gt;{NTFY_ORDER}&amp;lt;/code&amp;gt; sortiert. Diese enthält ein Order-Präfix in Form einer Ganzzahl, sowie den Namen der Definition (Bsp: &amp;lt;code&amp;gt;&#039;&#039;&#039;50&#039;&#039;&#039;-Lampe_Wohnzimmer&amp;lt;/code&amp;gt;). Dadurch kann man jedoch nicht sicherstellen, dass Events von bestimmten Modulen zuerst verarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn das eigene Modul bei der Eventverarbeitung gegenüber den anderen Modulen eine bestimmte Reihenfolge einhalten muss, kann man in der [[#X_Initialize|Initialize]]-Funktion durch Setzen von &amp;lt;code&amp;gt;$hash-&amp;gt;{NotifyOrderPrefix}&amp;lt;/code&amp;gt; diese Reihenfolge beeinflussen. Standardmäßig werden Module immer mit einem Order-Präfix von &amp;quot;50-&amp;quot; in FHEM registriert. Durch die Veränderung dieses Präfixes kann man das eigene Modul in der Reihenfolge gegenüber anderen Modulen bei der Eventverarbeitung beeinflussen. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	$hash-&amp;gt;{NotifyOrderPrefix} = &amp;quot;45-&amp;quot;  # Alle Definitionen des Moduls X werden bei der Eventverarbeitung zuerst geprüft&lt;br /&gt;
	&lt;br /&gt;
	# oder...&lt;br /&gt;
	&lt;br /&gt;
	$hash-&amp;gt;{NotifyOrderPrefix} = &amp;quot;55-&amp;quot;  # Alle Definitionen des Moduls X werden bei der Eventverarbeitung als letztes geprüft&lt;br /&gt;
	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Da dieses Präfix bei eventverarbeitenden Definitionen in &amp;lt;code&amp;gt;$hash-&amp;gt;{NTFY_ORDER}&amp;lt;/code&amp;gt; dem Definitionsnamen vorangestellt wird bewirkt es bei einer normalen aufsteigenden Sortierung nach &amp;lt;code&amp;gt;$hash-&amp;gt;{NTFY_ORDER}&amp;lt;/code&amp;gt; eine veränderte Reihenfolge. Alle Module die in der Initialize-Funktion nicht &amp;lt;code&amp;gt;$hash-&amp;gt;{NotifyOrderPrefix}&amp;lt;/code&amp;gt; explizit setzen, werden mit &amp;quot;50-&amp;quot; als Standardwert vorbelegt.&lt;br /&gt;
&lt;br /&gt;
==== X_Rename ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Rename($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $new_name, $old_name) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Rename-Funktion wird ausgeführt, nachdem ein Gerät umbenannt wurde. Auf diese Weise kann ein Modul auf eine Namensänderung reagieren, wenn das Gerät &amp;lt;code&amp;gt;$old_name&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;$new_name&amp;lt;/code&amp;gt; umbenannt wurde. Ein typischer Fall ist das Umsetzen der Namensänderungen bei Daten die mittels [[DevelopmentModuleAPI#setKeyValue|setKeyValue()]] gespeichert wurden. Hierbei müssen die Daten, welche unter dem alten Namen gespeichert sind, auf den neuen Namen geändert werden.&lt;br /&gt;
&lt;br /&gt;
Der Rename-Funktion wird lediglich der alte, sowie der neue Gerätename übergeben. Der Rückgabewert wird nicht ausgewertet.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Rename($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $new_name, $old_name ) = @_;&lt;br /&gt;
&lt;br /&gt;
	my $old_index = &amp;quot;Module_X_&amp;quot;.$old_name.&amp;quot;_data&amp;quot;;&lt;br /&gt;
	my $new_index = &amp;quot;Module_X_&amp;quot;.$new_name.&amp;quot;_data&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	my ($err, $data) = getKeyValue($old_index);&lt;br /&gt;
	return undef unless(defined($old_pwd));&lt;br /&gt;
&lt;br /&gt;
	setKeyValue($new_index, $data);&lt;br /&gt;
	setKeyValue($old_index, undef);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_DelayedShutdown ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_DelayedShutdown($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	return $delay_needed;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Mit der X_DelayedShutdown Funktion kann eine Definition das Stoppen von FHEM verzögern um asynchron hinter sich aufzuräumen. Dies kann z.B. der ordnungsgemäße Verbindungsabbau mit dem physikalischen Gerät sein (z.B. Session beenden, Logout, etc.), welcher mehrfache Requests/Responses benötigt. Als Übergabeparameter wird der Geräte-Hash &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; bereitgestellt. Je nach Rückgabewert &amp;lt;code&amp;gt;$delay_needed&amp;lt;/code&amp;gt; wird der Stopp von FHEM verzögert. Ist ein verzögerter Stopp von FHEM notwendig, darf der Rückgabewert in diesem Fall nicht &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; sein.&lt;br /&gt;
&lt;br /&gt;
Im Unterschied zur [[#X_Shutdown|Shutdown]]-Funktion steht vor einem bevorstehenden Stopp von FHEM für einen User-konfigurierbaren Zeitraum (global-Attribut: &amp;lt;code&amp;gt;maxShutdownDelay&amp;lt;/code&amp;gt; / Standard: 10 Sekunden) weiterhin die asynchrone FHEM Infrastruktur ([[DevIo]]/[[#X_Read|Read]]-Funktion und [[DevelopmentModuleAPI#InternalTimer|InternalTimer]]) zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Sobald alle nötigen Maßnahmen erledigt sind, muss der Abschluss mit [[DevelopmentModuleAPI#CancelDelayedShutdown|CancelDelayedShutdown(&amp;lt;code&amp;gt;$name&amp;lt;/code&amp;gt;)]] an FHEM zurückgemeldet werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_DelayedShutdown($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
&lt;br /&gt;
	# Aufräumen starten&lt;br /&gt;
	&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Shutdown ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Shutdown ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Mit der X_Shutdown Funktion kann ein Modul Aktionen durchführen bevor FHEM gestoppt wird. Dies kann z.B. der ordnungsgemäße Verbindungsabbau mit dem physikalischen Gerät sein (z.B. Session beenden, Logout, etc.). Nach der Ausführung der Shutdown-Fuktion wird FHEM sofort beendet. Falls vor dem Herunterfahren von FHEM asynchrone Kommunikation (via [[DevIo]]/[[#X_Read|X_Read]]) notwendig ist um eine vorhandene Verbindung sauber zu beenden, sollte man [[#X_DelayedShutdownFn|X_DelayedShutdownFn]] verwenden.&lt;br /&gt;
&lt;br /&gt;
Als Übergabeparameter wird der Geräte-Hash bereitgestellt. Der Rückgabewert einer Shutdown-Funktion wird nicht ausgewertet und ist daher irrelevant.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Shutdown($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
&lt;br /&gt;
	# Verbindung schließen&lt;br /&gt;
	DevIo_CloseDev($hash);&lt;br /&gt;
	return undef;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Funktionen für zweistufiges Modulkonzept ===&lt;br /&gt;
&lt;br /&gt;
Für das [[#Zweistufiges_Modell_für_Module|zweistufige Modulkonzept]] gibt es weiterhin:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;text-align:left&amp;quot; | Funktionsname !! style=&amp;quot;text-align:left&amp;quot; class=&amp;quot;unsortable&amp;quot; | Kurzbeschreibung&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Parse|X_Parse]] || Zustellen von Daten via [[DevelopmentModuleAPI#Dispatch|Dispatch()]] vom physischen Modul zum logischen Modul zwecks der Verarbeitung.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Write|X_Write]]|| Zustellen von Daten via [[DevelopmentModuleAPI#Dispatch|IOWrite()]] vom logischen zum physischen Modul um diese an die Hardware weiterzureichen.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Fingerprint|X_Fingerprint]] || Rückgabe eines &amp;quot;Fingerabdrucks&amp;quot; einer Nachricht. Dient der Erkennung von Duplikaten im Rahmen von [[DevelopmentModuleAPI#Dispatch|Dispatch()]]. Kann im physischen, als auch logischen Modul benutzt werden.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Für das zweistufige Modulkonzept muss in einem logischen Modul eine [[#X_Parse|Parse]]-Funktion im Modul-Hash registriert werden. In einem physikalischen Modul muss eine [[#X_Write|Write]]-Funktion registriert sein. Diese dienen dem Datenaustausch in beide Richtungen und werden von dem jeweils anderen Modul indirekt aufgerufen.&lt;br /&gt;
&lt;br /&gt;
In der [[#X_Initialize|Initialize]]-Funktion werden diese wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
$hash-&amp;gt;{ParseFn}       = &amp;quot;X_Parse&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{WriteFn}       = &amp;quot;X_Write&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{FingerprintFn} = &amp;quot;X_Fingerprint&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktionen werden in diesem Abschnitt genauer beschrieben.&lt;br /&gt;
&lt;br /&gt;
==== X_Parse ====&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;u&amp;gt;&#039;&#039;&#039;ACHTUNG&#039;&#039;&#039;:&amp;lt;/u&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
Dieser Abschnitt geht davon aus, dass das Modul mit dem Namen &amp;quot;X&amp;quot; ein &#039;&#039;&#039;logisches Modul&#039;&#039;&#039; im Sinne des zweistufigen Modulkonzepts ist, also Daten mit einem übergeordneten, physikalischen Modul austauscht.}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Parse ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $io_hash, $message) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	return $found;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion X_Parse wird aufgerufen, sobald von dem IO-Gerät &amp;lt;code&amp;gt;$io_hash&amp;lt;/code&amp;gt; eine Nachricht &amp;lt;code&amp;gt;$message&amp;lt;/code&amp;gt; via [[DevelopmentModuleAPI#Dispatch|Dispatch()]] zur Verarbeitung angefragt wird. Die Parse-Funktion muss dann prüfen, zu welcher Gerätedefinition diese Nachricht gehört und diese entsprechend verarbeiten.&lt;br /&gt;
&lt;br /&gt;
Üblicherweise enthält eine Nachricht immer eine Komponente durch welche sich die Nachricht einem Gerät zuordnen lässt (z.B. Adresse, ID-Nummer, ...). Eine solche Identifikation sollte man im Rahmen der [[#X_Define|Define]]-Funktion im logischen Modul an geeigneter Stelle speichern, um in der Parse-Funktion eine einfache Zuordnung von Adresse/ID einer Nachricht zur entsprechenden Gerätedefinition zu haben. Dazu wird in der Regel im Modul-Hash im modulspezifischen Bereich eine Liste &amp;lt;code&amp;gt;defptr&amp;lt;/code&amp;gt; (Definition Pointer) geführt, welche jede eindeutige Adresse/ID dem entsprechenden Geräte-Hash zuordnet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sub X_Define ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $def) = @_;&lt;br /&gt;
	my @a = split(&amp;quot;[ \t][ \t]*&amp;quot;, $def);&lt;br /&gt;
	my $name = $a[0];&lt;br /&gt;
&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	# erstes Argument ist die eindeutige Geräteadresse&lt;br /&gt;
	my $address = $a[1];&lt;br /&gt;
&lt;br /&gt;
	# Adresse rückwärts dem Hash zuordnen (für ParseFn)&lt;br /&gt;
	$modules{X}{defptr}{$address} = $hash;&lt;br /&gt;
&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auf Basis dieses Definition Pointers kann die Parse-Funktion nun sehr einfach prüfen, ob für die empfangene Nachricht bereits eine entsprechende Gerätedefinition existiert. Sofern diese existiert, kann die Nachricht entsprechend verarbeitet werden. Sollte jedoch keine passende Gerätedefinition zu der empfangenen Nachricht existieren, so muss die Parse-Funktion den Gerätenamen &amp;quot;UNDEFINED&amp;quot; zusammen mit den Argumenten für einen &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl zurückgeben, welcher ein passendes Gerät in FHEM anlegen würde (durch [[autocreate]]).&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sub X_Parse ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $io_hash, $message) = @_;&lt;br /&gt;
	&lt;br /&gt;
	# Die Stellen 10-15 enthalten die eindeutige Identifikation des Geräts&lt;br /&gt;
	my $address = substr($message, 10, 5); &lt;br /&gt;
&lt;br /&gt;
	# wenn bereits eine Gerätedefinition existiert (via Definition Pointer aus Define-Funktion)&lt;br /&gt;
	if(my $hash = $modules{X}{defptr}{$address}) &lt;br /&gt;
	{&lt;br /&gt;
		...  # Nachricht für $hash verarbeiten&lt;br /&gt;
		&lt;br /&gt;
		# Rückgabe des Gerätenamens, für welches die Nachricht bestimmt ist.&lt;br /&gt;
		return $hash-&amp;gt;{NAME}; &lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
	{&lt;br /&gt;
		# Keine Gerätedefinition verfügbar&lt;br /&gt;
		# Daher Vorschlag define-Befehl: &amp;lt;NAME&amp;gt; &amp;lt;MODULNAME&amp;gt; &amp;lt;ADDRESSE&amp;gt;&lt;br /&gt;
		return &amp;quot;UNDEFINED X_&amp;quot;.$address.&amp;quot; X $address&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Write ====&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;u&amp;gt;&#039;&#039;&#039;ACHTUNG&#039;&#039;&#039;:&amp;lt;/u&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
Dieser Abschnitt geht davon aus, dass das Modul mit dem Namen &amp;quot;X&amp;quot; ein &#039;&#039;&#039;physisches Modul&#039;&#039;&#039; im Sinne des zweistufigen Modulkonzepts ist, also Daten mit untergeordneten logischen Modulen austauscht. }}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Write ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, @arguments) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	return $return;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Write-Funktion wird durch die Funktion [[DevelopmentModuleAPI#IOWrite|IOWrite()]] aufgerufen, sobald eine logische Gerätedefinition Daten per IO-Gerät an die Hardware übertragen möchte. Dazu kümmert sich die Write-Funktion um die Übertragung der Nachricht in geeigneter Form an die verbundene Hardware. Als Argumente wird der Hash des physischen Gerätes übertragen, sowie alle weiteren Argumente, die das logische Modul beim Aufruf von IOWrite() mitgegeben hat. Im Normalfall ist das ein Skalar mit der zu sendenden Nachricht in Textform. Es kann aber auch sein, dass weitere Daten zum Versand notwendig sind (evtl. Schlüssel, Session-Key, ...). Daher ist die Parametersyntax einer zu schreibenden Nachricht via IOWrite-/Write-Funktion zwischen logischem und physikalischem Modul abzustimmen.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Write ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $message, $address) = @_;&lt;br /&gt;
	&lt;br /&gt;
	DevIo_SimpleWrite($hash, $address.$message, 2);&lt;br /&gt;
&lt;br /&gt;
	return undef;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Fingerprint ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Fingerprint($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $io_name, $msg ) = @_;&lt;br /&gt;
 &lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return ( $io_name, $fingerprint );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Fingerprint-Funktion dient der Erkennung von Duplikaten empfangener Nachrichten. Diese Funktion kann dabei sowohl im physischen, als auch im logischen Modul implementiert sein - je nachdem auf welcher Ebene man für eine Nachricht einen Fingerprint bilden kann. &lt;br /&gt;
&lt;br /&gt;
Als Parameter wird der Name des IO-Geräts &amp;lt;code&amp;gt;$io_name&amp;lt;/code&amp;gt; übergeben, sowie die Nachricht &amp;lt;code&amp;gt;$msg&amp;lt;/code&amp;gt;, welche empfangen wurde. Nun muss aus dieser Nachricht ein eindeutiger Fingerprint gebildet werden. Dies bedeutet, dass alle variablen Inhalte, die aufgrund des Empfangs dieser Nachricht über unterschiedliche IO-Geräte enthalten sein können, entfernt werden müssen. Dies können bspw. Empfangsadressen von IO-Geräten sein oder Session-ID&#039;s die in der Nachricht enthalten sind. Alle Fingerprints sämtlicher Nachrichten, die innerhalb der letzten 500 Millisekunden (konfigurierbar via &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt; Attribut &amp;lt;code&amp;gt;dupTimeout&amp;lt;/code&amp;gt;) empfangen wurden, werden gegen diesen generierten Fingerprint getestet. Sollte innerhalb dieser Zeit bereits eine Nachricht mit diesem Fingerprint verarbeitet worden sein, so wird sie als Duplikat erkannt und nicht weiter verarbeitet. In diesem Fall gibt [[DevelopmentModuleAPI#Dispatch|Dispatch()]] den Namen der Gerätedefinition zurück, welche eine Nachricht mit dem selben Fingerprint bereits verarbeitet hat. Es erfolgt dann kein Aufruf der [[#X_Parse|Parse]]-Funktion.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Fingerprint($$)&lt;br /&gt;
{&lt;br /&gt;
  my ( $io_name, $msg ) = @_;&lt;br /&gt;
&lt;br /&gt;
  substr( $msg, 2, 2, &amp;quot;--&amp;quot; ); # entferne Empfangsadresse&lt;br /&gt;
  substr( $msg, 4, 1, &amp;quot;-&amp;quot; );  # entferne Hop-Count&lt;br /&gt;
&lt;br /&gt;
  return ( $io_name, $msg );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es wird zuerst, sofern implementiert, die Fingerprint-Funktion des physischen Moduls aufgerufen. Sollte sich hierdurch kein Duplikat erkennen lassen, wird die Fingerprint-Funktion jedes möglichen geladenen logischen Moduls aufgerufen, sofern implementiert. &lt;br /&gt;
&lt;br /&gt;
Sollte sowohl im physischen, als auch im logischen Modul keine Fingerprint-Funktion implementiert sein, so wird keinerlei Duplikatserkennung durchgeführt.&lt;br /&gt;
&lt;br /&gt;
=== FHEMWEB-spezifische Funktionen ===&lt;br /&gt;
&lt;br /&gt;
FHEMWEB bietet Modul-Autoren die Möglichkeit an durch spezielle Funktionsaufrufe in Modulen, eigene HTML-Inhalte zu verwenden. Dadurch können in Verbindung mit zusätzlichem JavaScript komplexe Dialoge/Inhalte/Steuermöglichkeiten dargestellt werden. &lt;br /&gt;
&lt;br /&gt;
Eine genaue Auflistung aller FHEMWEB-spezifischen Funktionsaufrufe gibt es in dem separaten Artikel [[DevelopmentFHEMWEB]]&lt;br /&gt;
&lt;br /&gt;
=== sonstige Funktionen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden weitere Funktionen behandelt die zum Teil aus FHEM, aber auch aus anderen Modulen aufgerufen werden. Sie sind dabei nur in speziellen Anwendungsfällen relevant. Hier eine Auflistung aller sonstigen Modulfunktionen:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Funktionsname !! class=&amp;quot;unsortable&amp;quot; | Kurzbeschreibung&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_DbLog_split|X_DbLog_split]] || Wird durch das Modul 93_DbLog.pm aufgerufen. Dient dem korrekten Split eines moduleigenen Events in Name/Wert/Einheit für die Nutzung einer Datenbank.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Except|X_Except]]|| Wird aufgerufen, sobald ein ein geöffneter Filedescriptor in [[#Wichtige_globale_Variablen_aus_fhem.pl|&amp;lt;code&amp;gt;%selectlist&amp;lt;/code&amp;gt;]], der unter &amp;lt;code&amp;gt;$hash-&amp;gt;{EXCEPT_FD}&amp;lt;/code&amp;gt; im Geräte-Hash gesetzt ist, einen Interrupt bzw. Exception auslöst.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Copy|X_Copy]]|| Wird durch das Modul 98_copy.pm aufgerufen im Rahmen des &amp;lt;code&amp;gt;copy&amp;lt;/code&amp;gt;-Befehls sobald ein Gerät kopiert wurde.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_State|X_State]]|| Wird aufgerufen im Rahmen des &amp;lt;code&amp;gt;setstate&amp;lt;/code&amp;gt;-Befehls bevor der Status einer Gerätedefinition bzw. eines zugehörigen Readings gesetzt wird.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_AsyncOutput|X_AsyncOutput]]|| Nur relevant für Module die via [[TcpServerUtils]] eine Client-Verbindung zu FHEM ermöglichen (z.B. FHEMWEB und telnet). Ermöglicht die asynchrone Ausgabe von Daten via [[DevelopmentModuleAPI#asyncOutput|asyncOutput()]] an einen einzelnen verbundenen Client.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_ActivateInform|X_ActivateInform]]|| Nur relevant für Module die via [[TcpServerUtils]] eine Client-Verbindung zu FHEM ermöglichen (z.B. FHEMWEB und telnet). Ermöglicht das Aktivieren des inform-Mechanismus zum Senden von Events für einen einzelnen verbundenen Client.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Authorize|X_Authorize]]|| Wird aufgerufen im Rahmen von [[DevelopmentModuleAPI#Authorized|Authorized()]] um eine gewünschte Vorgangs-Art zu autorisieren.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Authenticate|X_Authenticate]]||  Wird aufgerufen im Rahmen von [[DevelopmentModuleAPI#Authenticate|Authenticate()]] um eine Authentifizierung zu prüfen und ggf. zu genehmigen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In der [[#X_Initialize|Initialize]]-Funktion werden diese wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
$hash-&amp;gt;{DbLog_splitFn} = &amp;quot;X_DbLog_split&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{ExceptFn} = &amp;quot;X_Except&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{CopyFn} = &amp;quot;X_Copy&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{AsyncOutputFn} = &amp;quot;X_AsyncOutput&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{ActivateInformFn} = &amp;quot;X_ActivateInform&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{StateFn} = &amp;quot;X_State&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{AuthorizeFn} = &amp;quot;X_Authorize&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{AuthenticateFn} = &amp;quot;X_Authenticate&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Funktionen werden in diesem Abschnitt genauer beschrieben.&lt;br /&gt;
==== X_DbLog_split ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_DbLog_split ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $event, $device_name ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
    &lt;br /&gt;
	return  ( $reading, $value, $unit );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die DbLog_split-Funktion wird durch das Modul [[DbLog]] aufgerufen, sofern der Nutzer DbLog benutzt. Sofern diese Funktion implementiert ist, kann der Modul-Autor das Auftrennen von Events in den Reading-Namen, -Wert und der Einheit selbst steuern. Andernfalls nimmt DbLog diese Auftrennung selber mittels Trennung durch Leerzeichen sowie vordefinierten Regeln zu verschiedenen Modulen vor. Je nachdem, welche Readings man in seinem Modul implementiert, passt diese standardmäßige Trennung jedoch nicht immer.&lt;br /&gt;
&lt;br /&gt;
Der Funktion werden folgende Eingangsparameter übergeben:&lt;br /&gt;
# Das generierte Event (Bsp: &amp;lt;code&amp;gt;temperature: 20.5 °C&amp;lt;/code&amp;gt;)&lt;br /&gt;
# Der Name des Geräts, welche das Event erzeugt hat (Bsp: &amp;lt;code&amp;gt;Temperatursensor_Wohnzimmer&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
Es ist nicht möglich in der DbLog_split-Funktion auf die verarbeitende DbLog-Definition zu referenzieren.&lt;br /&gt;
&lt;br /&gt;
Als Rückgabewerte muss die Funktion folgende Werte bereitstellen:&lt;br /&gt;
# Name des Readings (Bsp: &amp;lt;code&amp;gt;temperature&amp;lt;/code&amp;gt;)&lt;br /&gt;
# Wert des Readings (Bsp: &amp;lt;code&amp;gt;20.5&amp;lt;/code&amp;gt;)&lt;br /&gt;
# Einheit des Readings (Bsp: &amp;lt;code&amp;gt;°C&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_DbLog_splitFn($$)&lt;br /&gt;
{&lt;br /&gt;
	my ($event, $device) = @_;&lt;br /&gt;
	my ($reading, $value, $unit);&lt;br /&gt;
        my $devhash = $defs{$device}&lt;br /&gt;
&lt;br /&gt;
	if($event =~ m/temperature/) {&lt;br /&gt;
	   $reading = &#039;temperature&#039;;&lt;br /&gt;
	   $value = substr($event,12,4);&lt;br /&gt;
	   $unit = &#039;°C&#039;;&lt;br /&gt;
	}   &lt;br /&gt;
        &lt;br /&gt;
        return ($reading, $value, $unit);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Except ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Except ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die X_Except-Funktion wird durch fhem.pl aufgerufen, wenn die Gerätedefinition &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;[[#Wichtige_globale_Variablen_aus_fhem.pl|%selectlist]]&amp;lt;/code&amp;gt; aufgeführt ist und der Filedeskriptor in &amp;lt;code&amp;gt;$hash-&amp;gt;{EXCEPT_FD}&amp;lt;/code&amp;gt; eine Exception bzw. Interrupt auslöst. &lt;br /&gt;
&lt;br /&gt;
Der Rückgabewert wird nicht ausgewertet und ist daher irrelevant.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
use IO::File;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
sub X_Except ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	# Filehandle aus Filedescriptor erstellen&lt;br /&gt;
	my $filehandle = IO::File-&amp;gt;new_from_fd($hash-&amp;gt;{EXCEPT_FD}, &#039;r&#039;);&lt;br /&gt;
	seek($filehandle,0,0);	&lt;br /&gt;
&lt;br /&gt;
	# aktuellen Inhalt auslesen&lt;br /&gt;
	my $current_value = $filehandle-&amp;gt;getline;&lt;br /&gt;
&lt;br /&gt;
	if($current_value eq &amp;quot;1&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
		...&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
	{&lt;br /&gt;
		...&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Copy ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Copy ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $old_name, $new_name ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die X_Copy-Funktion wird durch das Modul [[copy]] aufgerufen nachdem ein Nutzer eine Gerätedefinition über den Befehl &amp;lt;code&amp;gt;copy&amp;lt;/code&amp;gt; kopiert hat. Dazu werden als Funktionsparameter die Definitionsnamen der alten und neuen Gerätedefinition übergeben. Es dient dazu zusätzliche Daten aus der zu kopierenden Gerätedefinition in die neue Definition zu übernehmen. Der Befehl &amp;lt;code&amp;gt;copy&amp;lt;/code&amp;gt; überträgt lediglich &amp;lt;code&amp;gt;$hash-&amp;gt;{DEF}&amp;lt;/code&amp;gt; in die neue Definition sowie sämtliche gesetzte Attribute. Weitere Daten müssen dann durch die X_Copy-Funktion übertragen werden. &lt;br /&gt;
&lt;br /&gt;
Die X_Copy-Funktion wird erst nach dem erfolgtem Kopiervorgang aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Der Rückgabewert wird nicht ausgewertet und ist daher irrelevant.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sub X_Copy ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $old_name, $new_name ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	my $old_hash = $defs{$old_name};&lt;br /&gt;
	my $new_hash = $defs{$new_name};&lt;br /&gt;
&lt;br /&gt;
	# copy also temporary session key&lt;br /&gt;
	$new_hash-&amp;gt;{helper}{SESSION_KEY} = $old_hash-&amp;gt;{helper}{SESSION_KEY};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_AsyncOutput ====&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=&#039;&#039;&#039;ACHTUNG:&#039;&#039;&#039; Diese Funktion ist nur relevant, wenn man ein Frontend-Modul erstellt über das FHEM von einem Anwender bedient werden kann (FHEMWEB, telnet, yowsup, telegram, alexa-fhem, homebridge-fhem, tabletui, ...).}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_AsyncOutput ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $client_hash, $text ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion X_AsyncOutput wird durch [[DevelopmentModuleAPI#asyncOutput|asyncOutput()]] von anderen Modulen aufgerufen. Es erlaubt diesen anderen Modulen die Ausgabe von asynchronen Befehlsergebnissen &amp;lt;code&amp;gt;$text&amp;lt;/code&amp;gt; zuvor ausgeführter set-/get-Befehle an den entsprechenden Client (identifiziert durch den Client-Hash &amp;lt;code&amp;gt;$client_hash&amp;lt;/code&amp;gt; der temporären Definition) zurückzugeben. &lt;br /&gt;
&lt;br /&gt;
Wenn ein Client einen set-/get-Befehl ausführt, wird der Client-Hash bei der Ausführung dieser Befehle an die jeweiligen Module übermittelt. Sobald ein Befehl ausgeführt wird, der seine Ausgabe asynchron ausführen möchte und die Client-Verbindung des Server-Moduls dies unterstützt (&amp;lt;code&amp;gt;$client_hash-&amp;gt;{canAsyncOutput}&amp;lt;/code&amp;gt; ist gesetzt), merkt sich das befehlsausführende Modul den Client-Hash und gibt das Ergebnis des Befehls zu späterer Zeit via [[DevelopmentModuleAPI#asyncOutput|asyncOutput()]] an den ursprünglichen Client zurück. Die Funktion X_AsyncOutput des Server-Moduls kümmert sich darum das Ergebnis dem entsprechenden Client in der notwendigen Form zuzustellen.&lt;br /&gt;
&lt;br /&gt;
Der Rückgabewert von X_AsyncOutput() wird als Rückgabewert für asyncOutput() verwendet. Man kann hier im Fehlerfall eine Fehlermeldung angeben und im Erfolgsfall &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt;. Der Rückgabewert wird aber aktuell nicht ausgewertet.&lt;br /&gt;
&lt;br /&gt;
==== X_ActivateInform====&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=&#039;&#039;&#039;ACHTUNG:&#039;&#039;&#039; Diese Funktion ist nur relevant, wenn man ein Frontend-Modul erstellt über das FHEM von einem Anwender bedient werden kann (FHEMWEB, telnet, yowsup, telegram, alexa-fhem, homebridge-fhem, tabletui, ...).}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_ActivateInform($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $client_hash, $arg ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion X_ActivateInform wird aktuell nur durch den [[update]]-Befehl aufgerufen, sofern ein Client eines Frontend-Moduls diesen Befehl aufgerufen hat um den Inform-Mechanismus (Senden von Events) zu aktivieren. Dadurch wird im Falle von [[update]] die umgehende Anzeige der Logmeldungen für den ausführenden Client aktiviert. In [[FHEMWEB]] geschieht das über den Event-Monitor, bei telnet mit der direkten Ausgabe.&lt;br /&gt;
&lt;br /&gt;
Da diese Funktion aktuell nur speziell für den update-Befehl implementiert ist, kann man aktuell keine genaue Angaben zu den möglichen Werten von &amp;lt;code&amp;gt;$arg&amp;lt;/code&amp;gt; geben. Dieser Parameter dient dazu genauer zu spezifizieren was exakt an Events an den entsprechenden Client &amp;lt;code&amp;gt;$client_hash&amp;lt;/code&amp;gt; zu senden ist. Aktuell wird dazu die Parametersyntax des inform-Befehls verwendet (on|off|log|raw|timer|status).&lt;br /&gt;
&lt;br /&gt;
==== X_State ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_State($$$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $time, $readingName, $value ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die X_State-Funktion wird durch fhem.pl aufgerufen, sobald über den Befehl &amp;lt;code&amp;gt;setstate&amp;lt;/code&amp;gt; versucht wird ein Wert für ein Reading oder den Status (&amp;lt;code&amp;gt;$hash-&amp;gt;{STATE}&amp;lt;/code&amp;gt;) einer Gerätedefinition zu setzen. Dieser Befehl wird primär beim Starten von FHEM aufgerufen sobald das State-File eingelesen wird. Je nachdem, ob im gegebenen Fall ein Reading oder der Definitionsstatus gesetzt wird, haben die Übergabeparameter verschiedene Werte:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Funktionsparameter!! Wert beim Setzen eines Readings !! Wert beim Setzen eines Definitionsstatus&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; || colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; | Die Hashreferenz der betreffenden Gerätedefinition&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$time&amp;lt;/code&amp;gt;|| Der Zeitstempel auf welchen das Reading &amp;lt;code&amp;gt;$readingName&amp;lt;/code&amp;gt; gesetzt werden soll. Das Ergebnis entspricht dem Rückgabewert der Funktion || Der aktuelle Zeitstempel zum jetzigen Zeitpunkt.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$readingName&amp;lt;/code&amp;gt;|| Der Name des Readings, welches auf einen neuen Wert gesetzt werden soll. || Statischer Wert &amp;quot;STATE&amp;quot; um anzuzeigen, dass es sich um den Definitionsstatus handelt, welcher gesetzt werden soll (&amp;lt;code&amp;gt;$hash-&amp;gt;{STATE}&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$value&amp;lt;/code&amp;gt; || Den Wert, welchen das Reading &amp;lt;code&amp;gt;$readingName&amp;lt;/code&amp;gt; annehmen soll. || Den Wert, welchen die Gerätedefinition als Status annehmen soll.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Wenn via &amp;lt;code&amp;gt;setstate&amp;lt;/code&amp;gt; ein Reading gesetzt wird, kann die X_State-Funktion das Setzen dieses Readings durch die Rückgabe einer aussagekräftigen Fehlermeldung unterbinden. Sofern &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurückgegeben wird, wird das entsprechende Reading auf den übergebenen Status gesetzt.&lt;br /&gt;
&lt;br /&gt;
Wenn via &amp;lt;code&amp;gt;setstate&amp;lt;/code&amp;gt; der Definitionsstatus gesetzt wird, wird die X_State-Funktion erst nach dem Setzen des Status aufgerufen. Man kann dabei zwar eine Fehlermeldung zurückgeben, der Status wird aber dennoch übernommen. Die Fehlermeldung wird lediglich dem Nutzer angezeigt.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_State($$$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $time, $readingName, $value ) = @_;&lt;br /&gt;
&lt;br /&gt;
	return undef if($readingName &amp;quot;STATE&amp;quot; || $value ne &amp;quot;inactive&amp;quot;);&lt;br /&gt;
	readingsSingleUpdate($hash, &amp;quot;state&amp;quot;, &amp;quot;inactive&amp;quot;, 1);&lt;br /&gt;
	return undef;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Authorize ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Authorize($$$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $client_hash, $type, $arg ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $authorized;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Authorize-Funktion wird von fhem.pl aufgerufen um zu erfragen, ob ein bestimmter Client &amp;lt;code&amp;gt;$client_hash&amp;lt;/code&amp;gt; die Aktion &amp;lt;code&amp;gt;$type&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;$arg&amp;lt;/code&amp;gt; ausführen darf. Auf diese Weise können Module Einfluss nehmen, welcher User welche Funktionen in FHEM nutzen darf. Wenn ein Client eine Aktion ausführen möchte, werden alle Module, die eine Authorize-Funktion implementiert haben, gefragt, ob diese Aktion ausgeführt werden darf. Als Rückgabewert wird das Ergebnis der Überprüfung zurückgegeben, wobei &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (unbekannt / nicht zuständig), &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (erlaubt) oder &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (verboten) zurückgegeben werden können.&lt;br /&gt;
&lt;br /&gt;
Es gibt aktuell folgende &amp;lt;code&amp;gt;$type&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;$arg&amp;lt;/code&amp;gt; Kombinationen, mit denen die Authorize-Funktion aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! $type !! $arg !! Überschrift&lt;br /&gt;
|- &lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&#039;&#039;&#039;$type&#039;&#039;&#039; = &amp;quot;cmd&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Befehlsausführung&#039;&#039;&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&#039;&#039;&#039;$arg&#039;&#039;&#039; = &amp;quot;set Lampe on&amp;quot;&amp;lt;/code&amp;gt; || Jeglicher FHEM-Befehl, der ausgeführt werden soll, wird in &amp;lt;code&amp;gt;$arg&amp;lt;/code&amp;gt; hinterlegt, sodass innerhalb einer Authorize-Funktion der Befehl genauer geparst werden kann um zu entscheiden, ob dieser Befehl erlaubt ist, oder nicht.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&#039;&#039;&#039;$arg&#039;&#039;&#039; = &amp;quot;perl&amp;quot;&amp;lt;/code&amp;gt; || Ausführen von Perl-Befehlen jeglicher Art. Der genaue Befehl wird dabei nicht an die Authorize-Funktion übergeben.&lt;br /&gt;
&lt;br /&gt;
Bsp: &amp;lt;code&amp;gt;{ReadingsVal(&amp;quot;Lampe&amp;quot;, &amp;quot;state&amp;quot;, &amp;quot;off&amp;quot;}&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&#039;&#039;&#039;$arg&#039;&#039;&#039; = &amp;quot;shell&amp;quot;&amp;lt;/code&amp;gt; || Ausführen von Shell-Befehlen jeglicher Art. Der genaue Befehl wird dabei nicht an die Authorize-Funktion übergeben.&lt;br /&gt;
&lt;br /&gt;
Bsp: &amp;lt;code&amp;gt;&amp;quot;/opt/fhem/myScript.sh&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&#039;&#039;&#039;$type&#039;&#039;&#039; = &amp;quot;devicename&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Sichtbarkeit von Geräten/Definitionen&#039;&#039; &lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; |  &amp;lt;code&amp;gt;&#039;&#039;&#039;$arg&#039;&#039;&#039; = &amp;quot;Licht_Wohnzimmer&amp;quot;&amp;lt;/code&amp;gt; || Sichtbarkeit des jeweiligen Gerät/Definition in FHEM. Dies bedeutet konkret die Auffindbarkeit im &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;-Befehl, sowie der Suche via [[DevelopmentModuleAPI#devspec2array|devspec2array()]]. Wird eine solche Anfrage durch die Authorize-Funktion abgelehnt, ist das entsprechende Gerät bzw. Definition für den jeweiligen Client nicht sichtbar.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== X_Authenticate ====&lt;br /&gt;
{{Link2Forum|Topic=72757|Message=644098}}&lt;br /&gt;
&lt;br /&gt;
== Bereitstellen eines eigenen Befehls (Befehlsmodul) ==&lt;br /&gt;
&lt;br /&gt;
Ein Modul kann primär einen neuen FHEM-Befehl bereitstellen. Man spricht in so einem Fall nicht von einem Gerätemodul, sondern einem Befehlsmodul. Ein solches Befehlsmodul stellt nur einen einzelnen Befehl bereit, der dem Modulnamen entsprechen muss. Nur, wenn der Modulname dem Befehlsname entspricht, kann FHEM das Modul beim ersten Ausführen dieses unbekannten Befehls finden und nachladen.&lt;br /&gt;
&lt;br /&gt;
Der entsprechende Befehl wird dazu in der [[#X_Initialize|Initialize]]-Funktion im globalen Hash &amp;lt;code&amp;gt;[[DevelopmentModuleIntro#Wichtige_globale_Variablen_aus_fhem.pl|%cmds]]&amp;lt;/code&amp;gt; registriert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($$) {&lt;br /&gt;
&lt;br /&gt;
    $cmds{X} = { Fn           =&amp;gt; &amp;quot;CommandX&amp;quot;,&lt;br /&gt;
                 Hlp          =&amp;gt; &amp;quot;&amp;lt;argument1&amp;gt; [optional_argument2], print something very useful&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
                 # optionaler Filter für Clientmodule als regulärer Ausdruck&lt;br /&gt;
                 ClientFilter =&amp;gt; &amp;quot;FHEMWEB&amp;quot;&lt;br /&gt;
                };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit wird der neue Befehl &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; in FHEM registriert. Die Funktion mit dem Namen &amp;lt;code&amp;gt;CommandX&amp;lt;/code&amp;gt; setzt diesen Befehl innerhalb des Moduls um. Desweiteren wird eine kurze Aufrufsyntax mitgegeben, welche beim Aufruf des &amp;lt;code&amp;gt;help&amp;lt;/code&amp;gt;-Befehls dem Nutzer angezeigt wird um als Gedankenstütze zu dienen. Optional kann man mittels &amp;lt;code&amp;gt;ClientFilter&amp;lt;/code&amp;gt; (regulärer Ausdruck für Modulnamen) die Ausführbarkeit nur auf bestimmte Client-Module (wie FHEMWEB oder telnet) beschränken. &lt;br /&gt;
&lt;br /&gt;
Nun muss noch die Funktion &amp;lt;code&amp;gt;CommandX&amp;lt;/code&amp;gt; im Rahmen des Moduls implementiert werden, welche den Befehl &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; umsetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub CommandX($$)&lt;br /&gt;
{&lt;br /&gt;
 	my ($client_hash, $arguments) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	return $output;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dabei werden der Befehlsfunktion zwei Parameter übergeben. Zuerst die Hash-Referenz des aufrufenden Clients (sofern manuell ausgeführt, ansonsten &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt;) zwecks Rechteprüfung via [[allowed|allowed-Definitionen]]. Anschließend folgen die Aufrufparameter als zusammenhängende Zeichenkette. Die Trennung der einzelnen Argumente obligt der Funktion (bspw. via [[DevelopmentModuleAPI#parseParams|parseParams()]]). Als Funktionsrückgabewert wird eine Ausgabemeldung erwartet, die dem Nutzer angezeigt werden soll.&lt;br /&gt;
&lt;br /&gt;
== Pollen von Geräten ==&lt;br /&gt;
Wenn Geräte von sich aus keine Informationen senden sondern abgefragt werden müssen, kann man im Modul die Funktion [[DevelopmentModuleAPI#InternalTimer|InternalTimer()]] verwenden um einen Funktionsaufruf zu einem späteren Zeitpunkt durchführen zu können. Man übergibt dabei den Zeitpunkt für den nächsten Aufruf, den Namen der Funktion, die aufgerufen werden soll, sowie den zu übergebenden Parameter. Als zu übergebender Parameter wird üblicherweise der Hash der betroffenen Geräteinstanz verwendet. Damit hat die aufgerufene Funktion Zugriff auf alle wichtigen Daten der Geräteinstanz. Eventuell zusätzlich benötigte Werte können einfach als weitere Internals über den Hash zugänglich gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise könnte man für das Abfragen eines Geräts in der [[#X_Define|Define]]-Funktion den Timer folgendermaßen setzen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
InternalTimer(gettimeofday()+2, &amp;quot;X_GetUpdate&amp;quot;, $hash);	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alternativ kann man auch in der [[#X_Notify|Notify]]-Funktion auf das Event &amp;lt;code&amp;gt;global:INITIALIZED&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;global:REREADCFG&amp;lt;/code&amp;gt; reagieren und erst dort, den Timer anstoßen, sobald die Konfiguration komplett eingelesen wurde. Dies ist insbesondere notwendig, wenn man sicherstellen will, dass alle Attribute aus der Konfiguration gesetzt sind, sobald man einen Status-Update initiiert.&lt;br /&gt;
&lt;br /&gt;
In der Funktion &amp;lt;code&amp;gt;X_GetUpdate&amp;lt;/code&amp;gt; selbst wird dann der Timer neu gesetzt, so dass nach einem Intervall die Funktion erneut aufgerufen wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_GetUpdate($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
	my $name = $hash-&amp;gt;{NAME};&lt;br /&gt;
	Log3 $name, 4, &amp;quot;X: GetUpdate called ...&amp;quot;;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	# neuen Timer starten in einem konfigurierten Interval.&lt;br /&gt;
	InternalTimer(gettimeofday()+$hash-&amp;gt;{Interval}, &amp;quot;X_GetUpdate&amp;quot;, $hash);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Innerhalb der Funktion kann man nun das Gerät abfragen und die abgefragten Werte in Readings speichern. Falls das Abfragen der Werte jedoch zu einer Verzögerung und damit zu einer Blockade von FHEM führen kann, ist es möglich, in der GetUpdate-Funktion nur die Aufforderung zum Senden bestimmter Daten an das angeschlossene Gerät zu senden und dann das Lesen über die oben beschriebene [[#X_Read|Read]]-Funktion zu implementieren.&lt;br /&gt;
&lt;br /&gt;
Eine genaue Beschreibung der Timer-Funktion gibt es [[DevelopmentModuleAPI#Timer|hier im Wiki]]&lt;br /&gt;
&lt;br /&gt;
== Logging / Debugging ==&lt;br /&gt;
Um Innerhalb eines Moduls eine Log-Meldung in die FHEM-Logdatei zu schreiben, wird die Funktion [[DevelopmentModuleAPI#Log3|Log3()]] aufgerufen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
Log3 $name, 3, &amp;quot;X ($name) - Problem erkannt ...&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Eine genaue Beschreibung zu der Funktion inkl. Aufrufparameter findet man [[DevelopmentModuleAPI#Log3|hier]]. Es ist generell ratsam in der Logmeldung sowohl den Namen des eigenen Moduls zu schreiben, sowie den Namen des Geräts, welche diese Logmeldung produziert, da die Meldung, so wie sie ist, direkt in das Logfile wandert und es für User ohne diese Informationen schwierig ist, die Meldungen korrekt zuzuordnen.&lt;br /&gt;
&lt;br /&gt;
Die Funktion Log3() verwendet den Namen der Geräteinstanz um das &amp;lt;code&amp;gt;verbose&amp;lt;/code&amp;gt;-Attribut zu prüfen. In der Regel wird bei Modulfunktionen jedoch immer nur der Gerätehash &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; übergeben. Um den Namen der Definition zu ermitteln ist es daher notwendig sich diesen aus dem Hash extrahieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
my $name = $hash-&amp;gt;{NAME};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um für eine einzelne Geräteinstanz das Verbose-Level zu erhöhen, ohne gleich für das gesamte FHEM den globalen Verbose-Level zu erhöhen und damit alle Meldungen zu erzeugen, kann man den Befehl &lt;br /&gt;
&amp;lt;code&amp;gt;attr &amp;lt;NAME&amp;gt; verbose&amp;lt;/code&amp;gt; verwenden. Beispielsweise &amp;lt;code&amp;gt;attr Lichtschalter_Wohnzimmer verbose 5&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Logmeldungen sollten je nach Art und Wichtigkeit für den Nutzer in unterschiedlichen Loglevels erzeugt werden. Es gibt insgesamt 5 Stufen in denen geloggt werden kann. Standardmäßig steht der systemweite Loglevel (&amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt;-Attribut &amp;lt;code&amp;gt;verbose&amp;lt;/code&amp;gt;) auf der Stufe 3. Die Bedeutung der jeweiligen Stufen ist in der {{Link2CmdRef|Lang=de|Anker=verbose}} beschrieben.&lt;br /&gt;
&lt;br /&gt;
Während der Entwicklung eines Moduls kann man für eigene Debug-Zwecke auch die Funktion [[DevelopmentModuleAPI#Debug|Debug()]] verwenden um schnell und einfach Debug-Ausgaben in das Log zu schreiben. Diese sollten in der endgültigen Fassung jedoch nicht mehr vorhanden sein. Sie dienen ausschließlich zum Debugging während der Entwicklung.&lt;br /&gt;
&lt;br /&gt;
Eine genaue Beschreibung der Log-Funktion gibt es [[DevelopmentModuleAPI#Logging|hier im Wiki]].&lt;br /&gt;
&lt;br /&gt;
== Zweistufiges Modell für Module ==&lt;br /&gt;
[[Datei:Zweistufiges Modulkonzept.jpg|mini|rechts|Schematische Darstellung am Beispiel CUL]]&lt;br /&gt;
Es gibt viele Geräte, welche die Kommunikation mit weiteren Geräten mit tlw. unterschiedlichen Protokollen ermöglichen. Das typischste Beispiel bietet hier der [[CUL]], welcher via Funk mit verschiedenen Protokollen weitere Geräte ansprechen kann (z.B. Aktoren, Sensoren, ...). Hier bildet ein Gerät eine Brücke durch die weitere Geräte in FHEM zugänglich gemacht werden können. Dabei werden über einen Kommunikationsweg (z.B. serielle Schnittstelle, TCP, ...) beliebig viele Geräte gesteuert. Typische Beispiele dazu sind:&lt;br /&gt;
&lt;br /&gt;
* [[CUL]]: stellt Geräte mit verschiedenen Kommunikationsprotokollen via Funk bereit (u.a. [[FS20]], [[HomeMatic]], [[Funk-Heizkörperregler_Kurz-Bedienungsanleitung_FHT|FHT]], [[MAX]], ...)&lt;br /&gt;
* [[HMLAN]]: stellt HomeMatic Geräte via Funk bereit&lt;br /&gt;
* [[MAX#MAXLAN|MAXLAN]]: stellt [[MAX|MAX!]] Geräte via Funk bereit&lt;br /&gt;
* [[PanStamp#panStick.2FShield|panStamp]]: stellt weitere panStamp Geräte via Funk bereit&lt;br /&gt;
&lt;br /&gt;
Dabei wird die Kommunikation in 2 Stufen unterteilt:&lt;br /&gt;
* physisches Modul - z.B. 00_CUL.pm - zuständig für die physikalische Kommunikation mit der Hardware. Empfangene Daten müssen einem logischen Modul zugeordnet werden.&lt;br /&gt;
* logische Modul(e) - z.B. 10_FS20.pm - interpretiert protokollspezifische Nachrichten. Sendet protokollspezifische Daten über das physische Modul an die Hardware.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;physisches Modul&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das physische Modul öffnet die Datenverbindung zum Gerät (z.B. CUL) und verarbeitet sämtliche Daten. Es kümmert sich um den Erhalt der Verbindung (bsp. durch Keep-Alives) und konfiguriert das Gerät so, dass eine Kommunikation mit allen weiteren Geräten möglich ist (bsp. Frequenz, Modulation, Kanal, etc.).&lt;br /&gt;
&lt;br /&gt;
Empfangene Nutzdaten werden als Zeichenkette über die Funktion [[DevelopmentModuleAPI#Dispatch|Dispatch()]] an logische Module weitergegeben.&lt;br /&gt;
&lt;br /&gt;
Das Modul stellt eine [[#Die_Match-Liste|Match-Liste]] bereit, anhand FHEM die Nachricht einem Modul zuordnen kann, sofern dieses noch nicht geladen sein sollte. Die Match-Liste enthält eine Liste von regulären Ausdrücken und ordnet diese einem Modul zu. Wenn eine Nachricht auf einen solchen regulären Ausdruck passt und das Modul noch nicht geladen ist, lädt FHEM dieses automatisch nach, zwecks Verarbeitung der Nachricht. &lt;br /&gt;
&lt;br /&gt;
Anhand einer bereitgestellten [[#Die_Client-Liste|Client-Liste]] (Auflistung von logischen Modulen) kann FHEM feststellen, welche logischen Module mit dem physischen Modul kommunizieren können. Nur die hier aufgelisteten, logischen Module werden beim Aufruf von [[DevelopmentModuleAPI#Dispatch|Dispatch()]] angesprochen.&lt;br /&gt;
&lt;br /&gt;
Das Modul stellt eine [[#X_Write|Write]]-Funktion zur Verfügung, über die logische Module Daten in beliebiger Form an die Hardware übertragen können. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;logisches Modul&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das logische Modul interpretiert die via Dispatch() übergebene Nachricht (Zeichenkette) durch eine bereitgestellte [[#X_Parse|Parse]]-Funktion und erzeugt entsprechende Readings/Events. Es stellt über &amp;lt;code&amp;gt;set&amp;lt;/code&amp;gt;-/&amp;lt;code&amp;gt;get&amp;lt;/code&amp;gt;-Kommandos Steuerungsmöglichkeiten dem Nutzer zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Es stellt FHEM einen [[#Der_Match-Ausdruck|Match-Ausdruck]] (regulärer Ausdruck) zur Verfügung anhand [[DevelopmentModuleAPI#Dispatch|Dispatch()]] ermitteln kann, ob die Nachricht durch das logische Modul verarbeitet werden kann. Nur Nachrichten, welche auf diesen Ausdruck passen, werden an das logische Modul weitergegeben (Aufruf [[#X_Parse|Parse]]-Funktion).&lt;br /&gt;
&lt;br /&gt;
=== Die Client-Liste ===&lt;br /&gt;
&lt;br /&gt;
Die Client-Liste ist eine Auflistung von Modulnamen (genauer: regulären Ausdrücken die auf Modulnamen passen) die in einem physischen Modul gesetzt ist. Damit wird definiert, mit welchen logischen Modulen das physikalische Modul  kommunizieren kann. &lt;br /&gt;
&lt;br /&gt;
Eine Client-Liste ist eine Zeichenkette, welche aus allen logischen Modulnamen besteht. Die einzelnen Namen werden durch einen Doppelpunkt getrennt. Anstatt kompletter Modulnamen können auch reguläre Ausdrücke verwendet werden, die auf mehrere Modulnamen passen (z.B. &amp;lt;code&amp;gt;CUL_.*&amp;lt;/code&amp;gt; um die logischen Module CUL_HM, CUL_MAX, etc. zu verwenden).&lt;br /&gt;
&lt;br /&gt;
Bsp.: Die Client-Liste von dem Modul CUL lautet daher wie folgt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;text&amp;gt;FS20:FHT.*:KS300:USF1000:BS:HMS:CUL_EM:CUL_WS:CUL_FHTTK:CUL_HOERMANN:ESA2000:CUL_IR:CUL_TX:Revolt:IT:UNIRoll:SOMFY:STACKABLE_CC:CUL_RFR:CUL_TCM97001:CUL_REDIRECT&amp;lt;/text&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alle hier aufgelisteten Module können über das Modul CUL Daten empfangen bzw. senden.&lt;br /&gt;
&lt;br /&gt;
Die Client-Liste hat generell folgende Funktion:&lt;br /&gt;
* Die Funktion [[DevelopmentModuleAPI#Dispatch|Dispatch()]] prüft nur Module, welche in der Client-Liste enthalten sind, ob diese die Nachricht verarbeiten können (Prüfung via [[#Der Match-Ausdruck|Match-Ausdruck]])&lt;br /&gt;
* Die Funktion [[DevelopmentModuleAPI#AssignIoPort|AssignIoPort()]] prüft anhand sämtlicher Client-Listen in FHEM, welches IO-Gerät für ein logisches Gerät nutzbar ist.&lt;br /&gt;
&lt;br /&gt;
Üblicherweise wird die Client-Liste in der [[#X_Initialize|Initialize]]-Funktion im Modul-Hash gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
	...&lt;br /&gt;
	$hash-&amp;gt;{Clients} = &amp;quot;FS20:KS300:FHT.*&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man kann die Client-Liste jedoch auch pro physikalisches Gerät setzen. Eine gesetzte Client-Liste in einem Gerät hat immer Vorrang vor der Liste im Modul-Hash. Eine gerätespezifische Client-Liste wird dann verwendet, wenn bspw. ein Gerät je nach Konfiguration nur bestimmte logische Module bedienen kann. Bspw. kann ein CUL je nach RF-Einstellungen FS20, uvm. oder nur HomeMatic bedienen. In einem solchen Fall wird die Client-Liste im Geräte-Hash gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $def ) = @_;&lt;br /&gt;
	...&lt;br /&gt;
	$hash-&amp;gt;{Clients} = &amp;quot;CUL_HM&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In vielen Modulen, welche nach dem zweistufigem Konzept arbeiten, beginnt und endet die Client-Liste mit einem Doppelpunkt. Dies ist ein historisches Überbleibsel, da der Prüfmechanismus die Client-Liste früher auf das Vorhandensein von &amp;lt;code&amp;gt;&#039;&#039;&#039;&amp;lt;u&amp;gt;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;:&amp;lt;/font&amp;gt;&amp;lt;/u&amp;gt;&#039;&#039;&#039;&amp;amp;lt;Modulname&amp;amp;gt;&#039;&#039;&#039;&amp;lt;u&amp;gt;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;:&amp;lt;/font&amp;gt;&amp;lt;/u&amp;gt;&#039;&#039;&#039;&amp;lt;/code&amp;gt; prüfte. Dies ist nun nicht mehr notwendig. Die einzelnen Modulnamen müssen lediglich durch einen Doppelpunkt getrennt werden.&lt;br /&gt;
&lt;br /&gt;
=== Die Match-Liste ===&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;u&amp;gt;&#039;&#039;&#039;ACHTUNG&#039;&#039;&#039;:&amp;lt;/u&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
Sämtliche regulären Ausdrücke in der Match-Liste werden &amp;quot;case insensitive&amp;quot; überprüft. Das bedeutet, dass Groß-/Kleinschreibung nicht berücksichtigt wird.&lt;br /&gt;
&lt;br /&gt;
Um dennoch in einem regulären Ausdruck auf Groß-/Kleinschreibung zu prüfen, kann man dieses mit dem Modifizierer &amp;lt;code&amp;gt;(?-i)&amp;lt;/code&amp;gt; wieder aktivieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
my %matchListFHEMduino = (&lt;br /&gt;
    ....&lt;br /&gt;
    &amp;quot;5:FHEMduino_PT2262&amp;quot;   =&amp;gt; &amp;quot;^(?-i)IR.*\$&amp;quot;,&lt;br /&gt;
    ....&lt;br /&gt;
    &amp;quot;13:IT&amp;quot;                =&amp;gt; &amp;quot;^(?-i)i......\$&amp;quot;,&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Siehe dazu Forumsbeitrag: {{Link2Forum|Topic=33422}}&lt;br /&gt;
}}&lt;br /&gt;
Die Match-Liste ordnet eine Nachrichtensyntax (regulärer Ausdruck) einem Modulnamen zu und wird in einem physikalischen Modul gesetzt. Sollte eine Nachricht vom physikalischen Gerät empfangen werden, die durch kein geladenes Modul verarbeitet werden kann ([[DevelopmentModuleAPI#Dispatch|Dispatch()]] prüft nur alle bisher geladenen Module aus der [[#Die Client-Liste|Client-Liste]]), so wird über die Match-Liste geprüft, welches Modul diese Nachricht verarbeiten kann. Dieses Modul wird anschließend geladen und die Nachricht durch dieses direkt durch Aufruf der [[#X_Parse|Parse]]-Funktion verarbeitet. In dieser Liste findet mittels regulärem Ausdruck eine Zuordnung der Nachrichtenstruktur zum verarbeitenden logischen Modul statt.&lt;br /&gt;
&lt;br /&gt;
Diese Liste wird ausschließlich in der [[DevelopmentModuleAPI#Dispatch|Dispatch()]]-Funktion verwendet. Sollte keine passendes Modul, welches bereits geladen ist, zur Verarbeitung einer Nachricht gefunden werden, so wird mithilfe der Match-Liste aufgrund der vorliegenden Nachricht das entsprechende Modul ermittelt. Dieses Modul wird dann direkt geladen und die Nachricht wird via [[#X_Parse|Parse]]-Funktion verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Die Match-Liste ist eine Zuordnung von einem Sortierpräfix + Modulname zu einem regulären Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;1:FS20&amp;quot;  =&amp;gt; &amp;quot;^81..(04|0c)..0101a001&amp;quot;,&lt;br /&gt;
    &amp;quot;2:KS300&amp;quot; =&amp;gt; &amp;quot;^810d04..4027a001&amp;quot;,&lt;br /&gt;
    &amp;quot;3:FHT&amp;quot;   =&amp;gt; &amp;quot;^81..(04|09|0d)..(0909a001|83098301|c409c401)..&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Sortierpräfix (&amp;lt;code&amp;gt;&amp;lt;u&amp;gt;1:&amp;lt;/u&amp;gt;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;FS20&amp;lt;/font&amp;gt;&amp;lt;/code&amp;gt;) dient als Sortierhilfe um so die Reihenfolge der Prüfung festzulegen. Bei der Prüfung wird die Match-Liste mittels sort() nach dem Schlüssel (Sortierpräfix + Modulname) sortiert und die regulären Ausdrücke werden dann nacheinander getestet. Daher sollten die präzisesten Ausdrücke immer zuerst getestet werden, sofern es weniger präzise Ausdrücke in der Match-Liste gibt. Dabei ist zu beachten, dass der Sortierpräfix nicht nach numerischen Regeln sortiert wird, sondern zeichenbasierend.&lt;br /&gt;
&lt;br /&gt;
Üblicherweise wird die Match-Liste in der [[#X_Initialize|Initialize]]-Funktion im Modul-Hash gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
   my ($hash) = @_;&lt;br /&gt;
&lt;br /&gt;
   ...&lt;br /&gt;
&lt;br /&gt;
   $hash-&amp;gt;{MatchList} = { &amp;quot;1:FS20&amp;quot;      =&amp;gt; &amp;quot;^81..(04|0c)..0101a001&amp;quot;,&lt;br /&gt;
                          &amp;quot;2:KS300&amp;quot;     =&amp;gt; &amp;quot;^810d04..4027a001&amp;quot;,&lt;br /&gt;
                          &amp;quot;3:FHT&amp;quot;       =&amp;gt; &amp;quot;^81..(04|09|0d)..(0909a001|83098301|c409c401)..&amp;quot; };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man kann die Match-Liste, ähnlich wie bei der Client-Liste, auch pro physikalisches Gerät setzen. Dabei hat auch hier die Match-Liste eines Gerätes immer Vorrang vor der Match-Liste aus dem Modul-Hash:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$)&lt;br /&gt;
{&lt;br /&gt;
   my ($hash, $def) = @_;&lt;br /&gt;
&lt;br /&gt;
   ...&lt;br /&gt;
&lt;br /&gt;
   $hash-&amp;gt;{MatchList} = { &amp;quot;1:CUL_HM&amp;quot; =&amp;gt; &amp;quot;^A....................&amp;quot; };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Der Match-Ausdruck ===&lt;br /&gt;
&lt;br /&gt;
Ein Match-Ausdruck wird in einem logischen Modul gesetzt und dient der Prüfung, ob eine Nachricht durch das eigene Modul via [[#X_Parse|Parse]]-Funktion verarbeitet werden kann. Es handelt sich hierbei um einen einzelnen regulären Ausdruck, den FHEM innerhalb der [[DevelopmentModuleAPI#Dispatch|Dispatch()]]-Funktion prüft. Nur wenn eine Nachricht via Dispatch() auf diesen Audruck matcht, wird die Parse-Funktion des eigenen Moduls aufgerufen um die Nachricht zu verarbeiten. &lt;br /&gt;
&lt;br /&gt;
Der Hintergrund, warum man den Aufruf mit einem solchen Ausdruck vorher abprüft, liegt in der Möglichkeit, dass ein physikalisches Modul mehrere unterschiedliche logische Module ansprechen kann. So kann FHEM jedes geladene Modul durch diesen Match-Ausdruck prüfen, ob es diese Nachricht verarbeiten kann. Erst, wenn alle geladenen Module, aufgrund einer Prüfung des Ausdrucks, die Nachricht nicht verarbeiten können, wird via [[#Die_Match-Liste|Match-Liste]] ermittelt, welches Modul geladen werden muss um die Nachricht zu verarbeiten. &lt;br /&gt;
&lt;br /&gt;
Der Match-Ausdruck wird in der [[#X_Initialize|Initialize]]-Funktion zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	# Dieses Modul verarbeitet FS20 Nachrichten&lt;br /&gt;
	$hash-&amp;gt;{Match} = &amp;quot;^81..(04|0c)..0101a001&amp;quot;; &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Die vollständige Implementierung ===&lt;br /&gt;
&lt;br /&gt;
Hier nun eine Zusammenfassung beim zweistufigen Modulkonzept in der jeweiligen Stufe implementiert werden muss, damit die Kommunikation funktioniert.&lt;br /&gt;
&lt;br /&gt;
==== physisches Modul ====&lt;br /&gt;
&lt;br /&gt;
Das physische Modul, welches als Kommunikationsbrücke zwischen der Hardware und logischen Modulen fungieren wird, sollte mindestens folgende Funktionen implementieren:&lt;br /&gt;
&lt;br /&gt;
* [[#X_Initialize|Initialize]]-Funktion - Zum Registrieren des Moduls in FHEM.&lt;br /&gt;
* [[#X_Define|Define]]-Funktion - Zum öffnen der Datenverbindung zur Hardware (IP-Adresse/serielle Schnittstelle/...).&lt;br /&gt;
* [[#X_Read|Read]]-Funktion - Zum Lesen von Daten, welche die Hardware übermittelt.&lt;br /&gt;
* [[#X_Read|Ready]]-Funktion - Zum Wiederaufbau der Verbindung bei Verbindungsabbruch, bzw. Prüfung auf lesbare Daten bei serieller Schnittstelle unter Windows.&lt;br /&gt;
* [[#X_Write|Write]]-Funktion - Zum Senden von Daten, welche logische Module via [[DevelopmentModuleAPI#IOWrite|IOWrite()]] an die Hardware übertragen möchten.&lt;br /&gt;
* [[#X_Undef|Undef]]-Funktion - Schließen der Verbindung zur Hardware beim Löschen via &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt;.&lt;br /&gt;
* [[#X_Shutdown|Shutdown]]-Funktion - Schließen der Verbindung zur Hardware beim Stopp von FHEM via &amp;lt;code&amp;gt;shutdown&amp;lt;/code&amp;gt;.&lt;br /&gt;
* [[#X_DelayedShutdown | DelayedShutdown]]-Funktion - Verzögertes beenden zum Schließen der Verbindung zur Hardware beim Stopp von FHEM via &amp;lt;code&amp;gt;shutdown&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Desweiteren müssen in der [[#X_Initialize|Initialize]]-Funktion folgende Daten bereitgestellt werden:&lt;br /&gt;
&lt;br /&gt;
* [[#Die_Client-Liste|Client-Liste]] - Auflistung aller logischen Module, die über dieses Modul kommunizieren können&lt;br /&gt;
* [[#Die_Match-Liste|Match-Liste]] - Zuordnung von Nachrichtensyntax zu Modul zwecks Autoload-Funktionalität.&lt;br /&gt;
&lt;br /&gt;
==== logisches Modul ====&lt;br /&gt;
&lt;br /&gt;
Das logische Modul, bildet ein einzelnes Gerät ab, über das mit einem physikalisches Modul kommuniziert werden kann. Es sollte mindestens folgende Funktionen implementieren:&lt;br /&gt;
&lt;br /&gt;
* [[#X_Initialize|Initialize]]-Funktion - Zum Registrieren des Moduls in FHEM.&lt;br /&gt;
* [[#X_Define|Define]]-Funktion - Speichern des Definition Pointers (siehe [[#X_Parse|Parse-Funktion]])&lt;br /&gt;
* [[#X_Parse|Parse]]-Funktion - Zum Lesen von Daten, welche die Hardware übermittelt.&lt;br /&gt;
* [[#X_Undef|Undef]]-Funktion - Löschen des Definition Pointers beim Löschen via &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Desweiteren müssen in der [[#X_Initialize|Initialize]]-Funktion folgende Daten bereitgestellt werden:&lt;br /&gt;
&lt;br /&gt;
* [[#Der_Match-Ausdruck|Match-Ausdruck]] - Prüfausdruck, ob eine Nachricht durch dieses Modul verarbeitet werden kann.&lt;br /&gt;
&lt;br /&gt;
=== Kommunikation von der Hardware bis zu den logischen Modulen ===&lt;br /&gt;
&lt;br /&gt;
Die Gerätedefinition des physischen Moduls öffnet eine Verbindung zur Hardware (z.B. via [[DevIo]]). Die [[#X_Read|Read]]-Funktion wird bei anstehenden Daten aus der Hauptschleife von fhem.pl aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Die Read-Funktion stellt dabei sicher, dass die Daten&lt;br /&gt;
* komplett (in der Regel über einen internen Puffer in &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;) und&lt;br /&gt;
* korrekt (z.B. via Prüfung mittels regulärem Ausdruck)&lt;br /&gt;
sind und ruft die globale Funktion [[DevelopmentModuleAPI#Dispatch|Dispatch()]] mit einer kompletten Nachricht auf.&lt;br /&gt;
&lt;br /&gt;
Die Funktion Dispatch() prüft alle geladenen Module aus der [[#Die_Client-Liste|Client-Liste]] des physikalischen Moduls nach möglichen logischen Modulen zur Verarbeitung. Alle zum Zeitpunkt geladenen Module, die in der Client-Liste aufgeführt sind, werden über den [[#Der_Match-Ausdruck|Match-Ausdruck]] geprüft, ob sie mit der Nachricht etwas anfangen können. Sollte bei einem logischen Modul der Match-Ausdruck passen, so wird die entsprechende [[#X_Parse|Parse]]-Funktion des logischen Moduls aufgerufen. Sofern keine passendes Modul gefunden wurde, um die Nachricht zu verarbeiten, wird in der [[#Die_Match-Liste|Match-Liste]] im Geräte- bzw. Modul-Hash der physischen Gerätedefinition nach dem passenden Modul gesucht. Sollte es darin ein Modul geben, was diese Art von Nachricht verarbeiten kann, so wird versucht dieses Modul zu laden um nun die Nachricht via Parse-Funktion zu verarbeiten. Es erfolgt in diesem Fall keine Vorprüfung durch den Match-Ausdruck.&lt;br /&gt;
&lt;br /&gt;
Durch Dispatch() wird nun die [[#X_Parse|Parse]]-Funktion des gefundenen logischen Moduls aufgerufen. Diese&lt;br /&gt;
* interpretiert die übergebene Nachricht,&lt;br /&gt;
* versucht eine existierende Gerätedefinition in FHEM zu finden (z.B. mittels Definition Pointer), für welche die Nachricht addressiert ist,&lt;br /&gt;
* setzt alle [[#Readings|Readings]] für die gefundene Gerätedefinition via [[DevelopmentModuleAPI#Readings_.2F_Events|readings*update]]()-Funktionen,&lt;br /&gt;
* gibt den Namen der logischen Definition zurück, welche die Nachricht verarbeitet hat.&lt;br /&gt;
&lt;br /&gt;
Sollte keine passende Gerätedefinition für die entsprechende Nachricht existieren (Adresse/ID/Kanal/...), wird der Gerätename &amp;quot;UNDEFINED&amp;quot; inkl. einem passenden &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Statement zurückgegeben, um die Definition durch [[autocreate]] erzeugen zu lassen.&lt;br /&gt;
&lt;br /&gt;
Es findet während der Verarbeitung einer Nachricht durch Dispatch()/Parse-Funktion keine sofortige Eventverarbeitung (via [[DevelopmentModuleAPI#Dispatch|DoTrigger()]]) statt, wenn die [[DevelopmentModuleAPI#Readings_.2F_Events|readings*update]]()-Funktionen verwendet werden.&lt;br /&gt;
(Im Gegensatz zum direkten Aufrufen der readings*update Funktionen ohne vorhergehendes Dispatch() )&lt;br /&gt;
&lt;br /&gt;
Die Funktion Dispatch() triggert das Event-Handling für das von der Parse-Funktion zurückgegebene logische Device selbstständig nach Abschluss der Parse-Funktion.&lt;br /&gt;
&lt;br /&gt;
Optional führt die Funktion Dispatch() eine Überprüfung auf Nachrichtenduplikate beim Einsatz von mehreren IO-Geräten durch. Dazu wird eine implementierte [[#X_Fingerprint|Fingerprint]]-Funktion im physischen oder logischen Modul benötigt. Sollte der Fingerprint einer Nachricht innerhalb einer bestimmten Zeit (globales Attribut &amp;lt;code&amp;gt;dupTimeout&amp;lt;/code&amp;gt;, standardmäßig 500ms) bereits empfangen worden sein, so wird die Nachricht verworfen. Dies ist insbesondere bei funkbasierter Hardware notwendig, wenn mehrere Empfänger die selbe Nachricht empfangen.&lt;br /&gt;
&lt;br /&gt;
=== Kommunikation von den logischen Modulen bis zur Hardware ===&lt;br /&gt;
&lt;br /&gt;
Um von einem logischen Modul eine Nachricht an die Hardware senden zu können, muss zunächst im logischen Gerät ein passenden IO-Gerät ausgewählt sein. Dazu muss die Funktion [[DevelopmentModuleAPI#AssignIoPort|AssignIoPort()]] ein entsprechendes IO-Gerät auswählen und in &amp;lt;code&amp;gt;$hash-&amp;gt;{IODev}&amp;lt;/code&amp;gt; setzen. Dieser Aufruf wird üblicherweise in der [[#X_Define|Define]]-Funktion des logischen Moduls ausgeführt. Erst, wenn ein IO-Gerät ausgewählt wurde, können Daten über das physikalische Gerät an die Hardware übermittelt werden.&lt;br /&gt;
&lt;br /&gt;
Zum Senden von Daten ruft das logische Modul die Funktion [[DevelopmentModuleAPI#IOWrite|IOWrite()]] samt Daten auf. Diese ruft für das entsprechende IO-Gerät die [[#X_Write|Write]]-Funktion auf und übergibt die Daten zum Schreiben an das physikalische Modul. Die Write-Funktion kümmert sich nun um die Übertragung der Daten an die Hardware. &lt;br /&gt;
&lt;br /&gt;
Keine direkten Zugriffe zwischen dem logischen und dem physischen Gerät gibt (d.h. keine direkten Aufrufe von Funktionen, kein direktes Überprüfen von &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;-Inhalten, ...), so können die Module hintereinander geschaltet werden (z.B. für Routerfunktionen wie bei der [[RFR_CUL|RFR]]-Funktionalität) oder mittels [[FHEM2FHEM]] im RAW-Modus zwei FHEM-Installationen verbunden werden und die logischen Geräte können dennoch kommunizieren.&lt;br /&gt;
&lt;br /&gt;
=== Automatisches Anlegen von logischen Gerätedefinitionen (autocreate) ===&lt;br /&gt;
&lt;br /&gt;
Das logische Modul kann im Rahmen der [[#X_Parse|Parse]]-Funktion eine neue Gerätedefinition anlegen, sofern eine passende Definition nicht existieren sollte. Die Parse-Funktion gibt generell den Namen der logischen Gerätedefinition zurück, für welche die Nachricht verarbeitet wurde. Sollte keine passende Definition gefunden werden, so muss die Parse-Funktion folgenden Rückgabewert liefern (zusammenhängende Zeichenkette):&lt;br /&gt;
&lt;br /&gt;
 UNDEFINED &#039;&#039;&amp;amp;lt;Namensvorschlag&amp;amp;gt;&#039;&#039; &#039;&#039;&amp;amp;lt;Modulname&amp;amp;gt;&#039;&#039; &#039;&#039;&amp;amp;lt;Define-Parameter...&amp;amp;gt;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sollte also bspw. im Rahmen der Parse-Funktion zu Modul X eine Nachricht nicht einer existierenden Gerätedefinition zugeordnet werden können, so muss ein Namensvorschlag erstellt werden der eine eindeutige Komponente wie bspw. eine Adresse/ID/Kanal-Nr enthält. In der Regel wird hier immer der Modulname zusammen mit der eindeutigen Komponente, durch einen Unterstrich getrennt, verwendet (Bsp: &amp;lt;code&amp;gt;X_4834&amp;lt;/code&amp;gt;). Der Modulname ist in der Regel immer der, des eigenen Moduls. In besonderen Fällen kann man hier auch einen abweichenden Modulnamen angeben. Dies wird bspw. bei den [[PanStamp#FHEM-Module.2FDevice_Definition_Files|SWAP-Modulen]] eingesetzt. Als Define-Parameter müssen alle notwendigen Parameter angegeben werden, die beim Aufruf des &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehls notwendig sind, damit eine neu angelegte Gerätedefinition Nachrichten zu dieser eindeutigen Adresse Daten verarbeitet. Dazu muss mind. die eindeutige Adresse mitgegeben werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel für FS20:&lt;br /&gt;
&lt;br /&gt;
 UNDEFINED FS20_0ae42f8 FS20 0ae42 f8&lt;br /&gt;
&lt;br /&gt;
Sobald [[DevelopmentModuleAPI#Dispatch|Dispatch()]] einen solchen Rückgabewert von einer [[#X_Parse|Parse]]-Funktion erhält, wird diese Zeichenkette so wie sie ist via [[DevelopmentModuleAPI#DoTrigger|DoTrigger()]] als Event für die Definition &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt; getriggert.&lt;br /&gt;
&lt;br /&gt;
Sofern der Nutzer das Modul [[autocreate]] verwendet (definiert hat), kümmert sich dieses nun um das Anlegen einer entsprechenden Gerätedefinition. Es lauscht dabei auf generierte Events der Definition &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt; via [[#X_Notify|Notify]]-Funktion. Der Nutzer kann dabei das Verhalten von autocreate durch entsprechende Parameter beeinflussen.&lt;br /&gt;
&lt;br /&gt;
Das Modul, für welches autocreate eine neue Definition anlegen möchte, kann das Verhalten durch entsprechende Parameter im Modul-Hash beeinflussen. Dabei gilt, dass gesetzte Attribute durch den Nutzer generell Vorrang haben. Die entsprechenden Parameter werden dabei im Rahmen der [[#X_Initialize|Initialize]]-Funktion im Modul-Hash gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
 &lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	$hash-&amp;gt;{AutoCreate} = {&amp;quot;X_.*&amp;quot;  =&amp;gt; { ATTR   =&amp;gt; &amp;quot;event-on-change-reading:.* event-min-interval:.*:300&amp;quot;,&lt;br /&gt;
	                                    FILTER =&amp;gt; &amp;quot;%NAME&amp;quot;,&lt;br /&gt;
	                                    GPLOT  =&amp;gt; &amp;quot;temp4hum4:Temp/Hum,&amp;quot;,&lt;br /&gt;
	                                    autocreateThreshold =&amp;gt; &amp;quot;2:140&amp;quot;&lt;br /&gt;
					  }&lt;br /&gt;
	                      };&lt;br /&gt;
			    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei wird unterhalb von &amp;lt;code&amp;gt;$hash-&amp;gt;{AutoCreate}&amp;lt;/code&amp;gt; eine Liste angelegt, wo einem regulären Ausdruck für einen anzulegenden Definitionsnamen entsprechende Optionen zugeordnet werden. Sobald durch autocreate eine Gerätedefintion angelegt wird, auf den ein hier gelisteter Ausdruck matcht, so werden die zugeordneten Optionen berücksichtigt.&lt;br /&gt;
&lt;br /&gt;
Hier eine Auflistung aller möglichen Optionen und ihrer Bedeutung:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Optionsname !! Beispiel !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;ATTR&amp;lt;/code&amp;gt;|| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; |  &amp;lt;code&amp;gt;&amp;quot;event-on-change-reading:.* event-min-interval:.*:300&amp;quot;&amp;lt;/code&amp;gt; || Eine Auflistung von Attributen, die nach dem Anlegen einer Definition zusätzlich gesetzt werden. Es handelt sich hierbei um eine Leerzeichen-separierte Liste von Doppelpunkt-getrennten Tupels mit Attributname und -wert.&lt;br /&gt;
&lt;br /&gt;
Für das dargestellte Beispiel bedeutet dies, dass nach dem Anlegen der Definition folgende FHEM-Befehle zusätzlich ausgeführt werden:&lt;br /&gt;
&lt;br /&gt;
 attr &#039;&#039;&amp;amp;lt;Name&amp;amp;gt;&#039;&#039; event-on-change-reading .*&lt;br /&gt;
 attr &#039;&#039;&amp;amp;lt;Name&amp;amp;gt;&#039;&#039; event-min-interval .*:300&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;FILTER&amp;lt;/code&amp;gt; || style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; |  &amp;lt;code&amp;gt;&amp;quot;%NAME&amp;quot;&amp;lt;/code&amp;gt;|| Sofern in der autocreate-Definiton das Attribut &amp;lt;code&amp;gt;filelog&amp;lt;/code&amp;gt; entsprechend durch den Nutzer gesetzt ist, wird eine zugehörige FileLog-Definition angelegt. Diese Option setzt den dabei benutzten Filter-Regexp, der beim Anlegen der FileLog-Definition gesetzt wird. &lt;br /&gt;
&lt;br /&gt;
Dabei werden folgende Platzhalter durch die entsprechenden Werte der neu angelegten Gerätedefinition ersetzt:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;%NAME&amp;lt;/code&amp;gt; - wird ersetzt durch den Definitionsnamen&lt;br /&gt;
* &amp;lt;code&amp;gt;%TYPE&amp;lt;/code&amp;gt; - wird ersetzt durch den Modulnamen&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; |  &amp;lt;code&amp;gt;GPLOT&amp;lt;/code&amp;gt; || style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&amp;quot;temp4hum4:Temp/Hum,&amp;quot;&amp;lt;/code&amp;gt; || Sofern eine FileLog-Definition angelegt wurde, kann man weiterführend dazu eine passende SVG-Definition erzeugen um Daten aus dem erzeugten FileLog zu visualisieren. Ein typischer Fall sind hierbei Temperatursensoren, wo es sinnvoll sein kann, einen passenden SVG-Plot mit Temperatur/Luftfeuchtigkeit direkt anzulegen.&lt;br /&gt;
&lt;br /&gt;
Es handelt sich hierbei um eine kommaseparierte Auflistung von gplot-Dateinamen und optionalen Label-Texten durch einen Doppelpunkt getrennt. Im genannten Beispiel entspricht &amp;lt;code&amp;gt;temp4hum4&amp;lt;/code&amp;gt; der zu verwendenden GnuPlot-Datei und &amp;lt;code&amp;gt;Temp/Hum&amp;lt;/code&amp;gt; dem zu verwendenden Label ([[SVG]] Attribut &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt;). Das Label wird auch durch FileLog verwendet als Link-Text zum entsprechenden SVG Plot. Alternativ kann auch nur die entsprechende GnuPlot-Datei anegeben werden ohne Label. Für jede angegebene GnuPlot-Datei wird anschließend eine entsprechende SVG-Definition erzeugt mit der vorher erzeugten FileLog-Definition als Datenquelle.&lt;br /&gt;
&lt;br /&gt;
Der gesamte Inhalt der &amp;lt;code&amp;gt;GPLOT&amp;lt;/code&amp;gt;-Option wird beim Anlegen einer FileLog-Definition dem Attribut &amp;lt;code&amp;gt;logtype&amp;lt;/code&amp;gt; als Wert plus dem Text &amp;lt;code&amp;gt;text&amp;lt;/code&amp;gt; zugewiesen. Daher muss der Inhalt der Option &amp;lt;code&amp;gt;GPLOT&amp;lt;/code&amp;gt; immer mit einem Komma enden. &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;autocreateThreshold&amp;lt;/code&amp;gt; || style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&amp;quot;2:10&amp;quot;&amp;lt;/code&amp;gt; || Definiert, wie viele Aufrufe (im Bsp: &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;) von autocreate innerhalb welcher Zeit (im Bsp: &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt; Sek.) stattfinden müssen, bevor die Gerätedefinition tatsächlich durch autocreate angelegt wird. Dadurch kann das ungewollte Anlegen von Geräten verhindert werden die tatsächlich nicht in Echt existieren. Aufgrund von Funkstörungen kann es durchaus zum ungewollten Anlegen einer Definition kommen. Diese Funktion lässt eine Definition erst zu wenn innerhalb einer vorgegeben Zeit eine Mindestzahl an Nachrichten eintrifft.&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl stellt dabei die Mindestanzahl an Nachrichten dar. Die Zweite Zahl stellt die Zeit in Sekunden dar, in der die Mindestanzahl an Nachrichten erreicht werden muss um eine entsprechende Gerätedefinition anzulegen. &lt;br /&gt;
&lt;br /&gt;
Sofern diese Option nicht gesetzt ist, wird standardmäßig &amp;lt;code&amp;gt;2:60&amp;lt;/code&amp;gt; verwendet.&lt;br /&gt;
&lt;br /&gt;
Diese Option kann durch den Anwender über das Attribut &amp;lt;code&amp;gt;autocreateThreshold&amp;lt;/code&amp;gt; übersteuert werden.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;noAutocreatedFilelog&amp;lt;/code&amp;gt;|| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; |  &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;|| Flag. Sofern gesetzt, wird keine FileLog- und ggf. SVG-Definition erzeugt. Selbst wenn der Nutzer durch entsprechende Attribute das Anlegen wünscht. Diese Option ist sinnvoll für Module bzw. Geräte die keine Readings erzeugen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Ergänzende Hinweise ==&lt;br /&gt;
Die Wahl der vorangestellten Nummer für den Dateinamen eines neuen Moduls hat keine Bedeutung mehr, es sei denn die Nummer ist 99. Module, die mit 99_ beginnen, werden von FHEM automatisch geladen. Module mit einer anderen Nummer nur wenn ein &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl dafür sorgt, dass das Modul geladen wird.&lt;br /&gt;
&lt;br /&gt;
Wenn ein Modul Initialisierungsdaten benötigt, sollten diese im Modul selbst enthalten sein. Eine zusätzliche Datei oder sogar ein Unterverzeichnis mit mehreren Dateien ist bei FHEM nicht üblich und sollte bei Modulen, die mit FHEM ausgeliefert werden nur in Rücksprache mit Rudolf König angelegt werden, da sie sonst bei einem Update nicht verteilt werden.&lt;br /&gt;
&lt;br /&gt;
== Weitere Informationen ==&lt;br /&gt;
Wenn man weitere Details wissen möchte, ist ein erster sinnvoller Schritt ein Blick in die Datei fhem.pl. Dort sieht man im Perl-Code wie die Module aufgerufen werden, was vorher passiert und was danach. Am Anfang der Datei (ca. ab Zeile 130) findet man beispielsweise eine Liste der globalen Variablen, die den Modulen zur Verfügung stehen sowie Details zu den wichtigen Hashes %modules und %defs. Wer mit Perl noch nicht so gut klar kommt, dem hilft eventuell ein Blick auf die Perldoc Website[http://perldoc.perl.org/] oder in das Perl-Buch seiner Wahl. Auch die FHEM {{Link2CmdRef}} sollte nicht unterschätzt werden. Es stehen oft mehr interessante Details auch für Modulentwickler darin als man zunächst vermuten könnte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Hello World&amp;quot; Beispiel ==&lt;br /&gt;
&lt;br /&gt;
98_Hello.pm&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
package main;&lt;br /&gt;
use strict;&lt;br /&gt;
use warnings;&lt;br /&gt;
&lt;br /&gt;
my %Hello_gets = (&lt;br /&gt;
	&amp;quot;whatyouwant&amp;quot;	=&amp;gt; &amp;quot;can&#039;t&amp;quot;,&lt;br /&gt;
	&amp;quot;whatyouneed&amp;quot;	=&amp;gt; &amp;quot;try sometimes&amp;quot;,&lt;br /&gt;
	&amp;quot;satisfaction&amp;quot;  =&amp;gt; &amp;quot;no&amp;quot;&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
sub Hello_Initialize($) {&lt;br /&gt;
    my ($hash) = @_;&lt;br /&gt;
&lt;br /&gt;
    $hash-&amp;gt;{DefFn}      = &#039;Hello_Define&#039;;&lt;br /&gt;
    $hash-&amp;gt;{UndefFn}    = &#039;Hello_Undef&#039;;&lt;br /&gt;
    $hash-&amp;gt;{SetFn}      = &#039;Hello_Set&#039;;&lt;br /&gt;
    $hash-&amp;gt;{GetFn}      = &#039;Hello_Get&#039;;&lt;br /&gt;
    $hash-&amp;gt;{AttrFn}     = &#039;Hello_Attr&#039;;&lt;br /&gt;
    $hash-&amp;gt;{ReadFn}     = &#039;Hello_Read&#039;;&lt;br /&gt;
&lt;br /&gt;
    $hash-&amp;gt;{AttrList} =&lt;br /&gt;
          &amp;quot;formal:yes,no &amp;quot;&lt;br /&gt;
        . $readingFnAttributes;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub Hello_Define($$) {&lt;br /&gt;
    my ($hash, $def) = @_;&lt;br /&gt;
    my @param = split(&#039;[ \t]+&#039;, $def);&lt;br /&gt;
    &lt;br /&gt;
    if(int(@param) &amp;lt; 3) {&lt;br /&gt;
        return &amp;quot;too few parameters: define &amp;lt;name&amp;gt; Hello &amp;lt;greet&amp;gt;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    my $hash-&amp;gt;{name}  = $param[0];&lt;br /&gt;
    my $hash-&amp;gt;{greet} = $param[2];&lt;br /&gt;
    &lt;br /&gt;
    return undef;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub Hello_Undef($$) {&lt;br /&gt;
    my ($hash, $arg) = @_; &lt;br /&gt;
    # nothing to do&lt;br /&gt;
    return undef;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub Hello_Get($@) {&lt;br /&gt;
	my ($hash, @param) = @_;&lt;br /&gt;
	&lt;br /&gt;
	return &#039;&amp;quot;get Hello&amp;quot; needs at least one argument&#039; if (int(@param) &amp;lt; 2);&lt;br /&gt;
	&lt;br /&gt;
	my $name = shift @param;&lt;br /&gt;
	my $opt = shift @param;&lt;br /&gt;
	if(!$Hello_gets{$opt}) {&lt;br /&gt;
		my @cList = keys %Hello_gets;&lt;br /&gt;
		return &amp;quot;Unknown argument $opt, choose one of &amp;quot; . join(&amp;quot; &amp;quot;, @cList);&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	if($attr{$name}{formal} eq &#039;yes&#039;) {&lt;br /&gt;
	    return $Hello_gets{$opt}.&#039;, sir&#039;;&lt;br /&gt;
    }&lt;br /&gt;
	return $Hello_gets{$opt};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub Hello_Set($@) {&lt;br /&gt;
	my ($hash, @param) = @_;&lt;br /&gt;
	&lt;br /&gt;
	return &#039;&amp;quot;set Hello&amp;quot; needs at least one argument&#039; if (int(@param) &amp;lt; 2);&lt;br /&gt;
	&lt;br /&gt;
	my $name = shift @param;&lt;br /&gt;
	my $opt = shift @param;&lt;br /&gt;
	my $value = join(&amp;quot;&amp;quot;, @param);&lt;br /&gt;
	&lt;br /&gt;
	if(!defined($Hello_gets{$opt})) {&lt;br /&gt;
		my @cList = keys %Hello_gets;&lt;br /&gt;
		return &amp;quot;Unknown argument $opt, choose one of &amp;quot; . join(&amp;quot; &amp;quot;, @cList);&lt;br /&gt;
	}&lt;br /&gt;
    $hash-&amp;gt;{STATE} = $Hello_gets{$opt} = $value;&lt;br /&gt;
    &lt;br /&gt;
	return &amp;quot;$opt set to $value. Try to get it.&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub Hello_Attr(@) {&lt;br /&gt;
	my ($cmd,$name,$attr_name,$attr_value) = @_;&lt;br /&gt;
	if($cmd eq &amp;quot;set&amp;quot;) {&lt;br /&gt;
        if($attr_name eq &amp;quot;formal&amp;quot;) {&lt;br /&gt;
			if($attr_value !~ /^yes|no$/) {&lt;br /&gt;
			    my $err = &amp;quot;Invalid argument $attr_value to $attr_name. Must be yes or no.&amp;quot;;&lt;br /&gt;
			    Log 3, &amp;quot;Hello: &amp;quot;.$err;&lt;br /&gt;
			    return $err;&lt;br /&gt;
			}&lt;br /&gt;
		} else {&lt;br /&gt;
		    return &amp;quot;Unknown attr $attr_name&amp;quot;;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	return undef;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
1;&lt;br /&gt;
&lt;br /&gt;
=pod&lt;br /&gt;
=begin html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;a name=&amp;quot;Hello&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Hello&amp;lt;/h3&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
    &amp;lt;i&amp;gt;Hello&amp;lt;/i&amp;gt; implements the classical &amp;quot;Hello World&amp;quot; as a starting point for module development. &lt;br /&gt;
    You may want to copy 98_Hello.pm to start implementing a module of your very own. See &lt;br /&gt;
    &amp;lt;a href=&amp;quot;http://wiki.fhem.de/wiki/DevelopmentModuleIntro&amp;quot;&amp;gt;DevelopmentModuleIntro&amp;lt;/a&amp;gt; for an &lt;br /&gt;
    in-depth instruction to your first module.&lt;br /&gt;
    &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
    &amp;lt;a name=&amp;quot;Hellodefine&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
    &amp;lt;b&amp;gt;Define&amp;lt;/b&amp;gt;&lt;br /&gt;
    &amp;lt;ul&amp;gt;&lt;br /&gt;
        &amp;lt;code&amp;gt;define &amp;amp;lt;name&amp;amp;gt; Hello &amp;amp;lt;greet&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        Example: &amp;lt;code&amp;gt;define HELLO Hello TurnUrRadioOn&amp;lt;/code&amp;gt;&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        The &amp;quot;greet&amp;quot; parameter has no further meaning, it just demonstrates&lt;br /&gt;
        how to set a so called &amp;quot;Internal&amp;quot; value. See &amp;lt;a href=&amp;quot;http://fhem.de/commandref.html#define&amp;quot;&amp;gt;commandref#define&amp;lt;/a&amp;gt; &lt;br /&gt;
        for more info about the define command.&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;br&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;a name=&amp;quot;Helloset&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
    &amp;lt;b&amp;gt;Set&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
    &amp;lt;ul&amp;gt;&lt;br /&gt;
        &amp;lt;code&amp;gt;set &amp;amp;lt;name&amp;amp;gt; &amp;amp;lt;option&amp;amp;gt; &amp;amp;lt;value&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        You can &amp;lt;i&amp;gt;set&amp;lt;/i&amp;gt; any value to any of the following options. They&#039;re just there to &lt;br /&gt;
        &amp;lt;i&amp;gt;get&amp;lt;/i&amp;gt; them. See &amp;lt;a href=&amp;quot;http://fhem.de/commandref.html#set&amp;quot;&amp;gt;commandref#set&amp;lt;/a&amp;gt; &lt;br /&gt;
        for more info about the set command.&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        Options:&lt;br /&gt;
        &amp;lt;ul&amp;gt;&lt;br /&gt;
              &amp;lt;li&amp;gt;&amp;lt;i&amp;gt;satisfaction&amp;lt;/i&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
                  Defaults to &amp;quot;no&amp;quot;&amp;lt;/li&amp;gt;&lt;br /&gt;
              &amp;lt;li&amp;gt;&amp;lt;i&amp;gt;whatyouwant&amp;lt;/i&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
                  Defaults to &amp;quot;can&#039;t&amp;quot;&amp;lt;/li&amp;gt;&lt;br /&gt;
              &amp;lt;li&amp;gt;&amp;lt;i&amp;gt;whatyouneed&amp;lt;/i&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
                  Defaults to &amp;quot;try sometimes&amp;quot;&amp;lt;/li&amp;gt;&lt;br /&gt;
        &amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;a name=&amp;quot;Helloget&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
    &amp;lt;b&amp;gt;Get&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
    &amp;lt;ul&amp;gt;&lt;br /&gt;
        &amp;lt;code&amp;gt;get &amp;amp;lt;name&amp;amp;gt; &amp;amp;lt;option&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        You can &amp;lt;i&amp;gt;get&amp;lt;/i&amp;gt; the value of any of the options described in &lt;br /&gt;
        &amp;lt;a href=&amp;quot;#Helloset&amp;quot;&amp;gt;paragraph &amp;quot;Set&amp;quot; above&amp;lt;/a&amp;gt;. See &lt;br /&gt;
        &amp;lt;a href=&amp;quot;http://fhem.de/commandref.html#get&amp;quot;&amp;gt;commandref#get&amp;lt;/a&amp;gt; for more info about &lt;br /&gt;
        the get command.&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;br&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;a name=&amp;quot;Helloattr&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
    &amp;lt;b&amp;gt;Attributes&amp;lt;/b&amp;gt;&lt;br /&gt;
    &amp;lt;ul&amp;gt;&lt;br /&gt;
        &amp;lt;code&amp;gt;attr &amp;amp;lt;name&amp;amp;gt; &amp;amp;lt;attribute&amp;amp;gt; &amp;amp;lt;value&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        See &amp;lt;a href=&amp;quot;http://fhem.de/commandref.html#attr&amp;quot;&amp;gt;commandref#attr&amp;lt;/a&amp;gt; for more info about &lt;br /&gt;
        the attr command.&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        Attributes:&lt;br /&gt;
        &amp;lt;ul&amp;gt;&lt;br /&gt;
            &amp;lt;li&amp;gt;&amp;lt;i&amp;gt;formal&amp;lt;/i&amp;gt; no|yes&amp;lt;br&amp;gt;&lt;br /&gt;
                When you set formal to &amp;quot;yes&amp;quot;, all output of &amp;lt;i&amp;gt;get&amp;lt;/i&amp;gt; will be in a&lt;br /&gt;
                more formal language. Default is &amp;quot;no&amp;quot;.&lt;br /&gt;
            &amp;lt;/li&amp;gt;&lt;br /&gt;
        &amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=end html&lt;br /&gt;
&lt;br /&gt;
=cut&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der HTML-Code zwischen den Tags &amp;lt;code&amp;gt;=pod&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;=cut&amp;lt;/code&amp;gt; dient zur Generierung der commandref.html. Der HTML-Inhalt wird automatisch beim Verteilen des Moduls im Rahmen des Update-Mechanismus aus jedem Modul extrahiert und daraus die Commandref in verschiedenen Sprachen erstellt. Eine detaillierte Beschreibung wie ein Commandref-Abschnitt in einem Modul definiert wird, siehe: [[Guidelines zur Dokumentation]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Development]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=DevelopmentModuleIntro&amp;diff=33084</id>
		<title>DevelopmentModuleIntro</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=DevelopmentModuleIntro&amp;diff=33084"/>
		<updated>2020-04-22T06:55:12Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: Die Client-Liste (Beispiel) anstatt als Computer-Code jetzt als Tabelle dargestellt, da die Liste unter IOS (IPAD) offensichtlich als Steuercode interpretiert wird und deswegen die gesamte Seite ständig neu geladen wird.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Hinweis|Dieser Text ist in Arbeit und muss noch an einigen Stellen ergänzt werden. }}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Einleitung ==&lt;br /&gt;
&lt;br /&gt;
Um neue Geräte, Dienste, o.ä. in FHEM verfügbar zu machen, kann man ein eigenes Modul in Perl schreiben. Ein Modul wird in FHEM automatisch geladen, wenn ein entsprechendes Device in FHEM definiert wird. Das Modul ermöglicht eine spezifische Kommunikation mit einem physikalischen Gerät, stellt Ergebnisse (&amp;quot;Readings&amp;quot;) und Events innerhalb von FHEM zur Verfügung und erlaubt es, das Gerät mit &amp;quot;Set&amp;quot;-/&amp;quot;Get&amp;quot;-Befehlen zu beeinflussen. Dieser Artikel soll den Einstieg in die Entwicklung eigener Module erleichtern.&lt;br /&gt;
&lt;br /&gt;
Mit dem FHEM-Befehl &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt; werden Devices in FHEM basierend auf einem Modul definiert. Dieser Befehl sorgt dafür, dass ein neues Modul bei Bedarf geladen und initialisiert wird. Ein gutes Beispiel ist hierbei die zentrale Konfigurationsdatei &amp;quot;fhem.cfg&amp;quot; in der sämtliche Devices in Form von &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Statements gespeichert sind.&lt;br /&gt;
&lt;br /&gt;
Damit das funktioniert müssen der Name des Moduls und der Name der [[#X_Initialize|Initialisierungsfunktion]]  identisch sein. Das folgende Beispiel soll dies verdeutlichen:&lt;br /&gt;
&lt;br /&gt;
Ein Jeelink USB-Stick könnte beispielsweise mit dem Befehl &amp;lt;code&amp;gt;define JeeLink1 &#039;&#039;JeeLink&#039;&#039; /dev/ttyUSB0@57600&amp;lt;/code&amp;gt; definiert werden.&lt;br /&gt;
&lt;br /&gt;
In fhem.pl wird der &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl verarbeitet und geprüft, ob ein Modul mit dem Namen &amp;quot;JeeLink&amp;quot; schon geladen ist. Falls nicht, wird ein Modul mit Namen XY_JeeLink.pm im Modulverzeichnis (z.B. /opt/fhem/FHEM) gesucht und, falls vorhanden, anschließend geladen. &lt;br /&gt;
Danach wird die Funktion &amp;lt;code&amp;gt;&#039;&#039;JeeLink&#039;&#039;_Initialize()&amp;lt;/code&amp;gt; aufgerufen um das Modul in FHEM zu registrieren. Eine Moduldatei muss dazu eine Funktion &amp;lt;code&amp;gt;&#039;&#039;&amp;amp;lt;Modulname&amp;amp;gt;&#039;&#039;_Initialize()&amp;lt;/code&amp;gt; enthalten. Durch den Aufruf dieser Funktion wird FHEM mitgeteilt, welche Funktionalitäten dieses Modul unterstützt und durch welche Perl-Funktionen im Modul selbst diese ausimplementiert werden.&lt;br /&gt;
&lt;br /&gt;
In der Initialisierungsfunktion des Moduls werden die Namen aller weiteren Perl-Funktionen des Moduls, die von fhem.pl aus aufgerufen werden, bekannt gemacht. Dazu wird für jedes Modul ein eigener Hash (genauer &amp;quot;Modul-Hash&amp;quot;) mit entsprechenden Werten gefüllt, der in fhem.pl für jedes Modul entsprechend abgelegt wird. Dadurch weiß FHEM wie dieses Modul anzusprechen ist.&lt;br /&gt;
&lt;br /&gt;
== Grundlegender Aufbau eines Moduls ==&lt;br /&gt;
&lt;br /&gt;
=== Dateiname ===&lt;br /&gt;
&lt;br /&gt;
Ein FHEM-Modul wird als Perl-Modul mit der Dateiendung *.pm abgespeichert. Der Dateiname folgt dabei folgendem Schema:&lt;br /&gt;
&lt;br /&gt;
:&amp;lt;code&amp;gt;&#039;&#039;[&#039;&#039;&#039;Schlüsselnummer&#039;&#039;&#039;]&#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;_&amp;lt;/font&amp;gt;&#039;&#039;[&#039;&#039;&#039;Modulname&#039;&#039;&#039;]&#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;.pm&amp;lt;/font&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Schlüsselnummer&#039;&#039;&#039; - Eine zweistellige Zahl zwischen 00 - 99. Die Schlüsselnummer hat aktuell keine technische Relevanz mehr. In früheren FHEM-Versionen ist sie relevant für [[#Zweistufiges_Modell_f.C3.BCr_Module|zweistufige Module]] (Reihenfolge für [[DevelopmentModuleAPI#Dispatch|Dispatch()]] um logische Module zu prüfen). Die allgemeine Empfehlung ist hierbei eine Schlüsselnummer eines Moduls zu verwenden, welches eine ähnliche Funktionalität bietet. Die Schlüsselnummer 99 hat hierbei eine besondere Bedeutung, da alle Module mit dieser Schlüsselnummer beim Start von FHEM automatisch geladen werden, selbst, wenn sie in der Konfiguration nicht verwendet werden. Daher wird für myUtils 99 als Schlüsselnummer verwendet (99_myUtils.pm). Module mit der Schlüsselnummer 99 werden im SVN nicht akzeptiert (siehe [[SVN Nutzungsregeln]])&lt;br /&gt;
* &#039;&#039;&#039;Modulname&#039;&#039;&#039; - Der Name des Moduls wie er in FHEM bei dem Anlegen einer Gerätedefinition zu verwenden ist. Der Modulname sollte nur aus den folgenden möglichen Zeichen bestehen: Groß-/Kleinbuchstaben, Zahlen sowie Unterstrich (_)&lt;br /&gt;
&lt;br /&gt;
=== Inhaltlicher Aufbau ===&lt;br /&gt;
&lt;br /&gt;
Ein Modul ist inhaltlich in folgende Abschnitte unterteilt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
#&lt;br /&gt;
#  72_MYMODULE.pm &lt;br /&gt;
#&lt;br /&gt;
&lt;br /&gt;
package main;&lt;br /&gt;
&lt;br /&gt;
# Laden evtl. abhängiger Perl- bzw. FHEM-Hilfsmodule&lt;br /&gt;
use HttpUtils;&lt;br /&gt;
use [...]&lt;br /&gt;
&lt;br /&gt;
# FHEM Modulfunktionen&lt;br /&gt;
&lt;br /&gt;
sub MYMODULE_Initialize() {&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub MYMODULE_Define() {&lt;br /&gt;
   ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
# Eval-Rückgabewert für erfolgreiches&lt;br /&gt;
# Laden des Moduls&lt;br /&gt;
1;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# Beginn der Commandref&lt;br /&gt;
&lt;br /&gt;
=pod&lt;br /&gt;
=item [helper|device|command]&lt;br /&gt;
=item summary Kurzbeschreibung in Englisch was MYMODULE steuert/unterstützt&lt;br /&gt;
=item summary_DE Kurzbeschreibung in Deutsch was MYMODULE steuert/unterstützt&lt;br /&gt;
&lt;br /&gt;
=begin html&lt;br /&gt;
 Englische Commandref in HTML&lt;br /&gt;
=end html&lt;br /&gt;
&lt;br /&gt;
=begin html_DE&lt;br /&gt;
 Deutsche Commandref in HTML&lt;br /&gt;
=end html&lt;br /&gt;
&lt;br /&gt;
# Ende der Commandref&lt;br /&gt;
=cut&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man kann hierbei von folgender Reihenfolge sprechen:&lt;br /&gt;
&lt;br /&gt;
# Perl-Code, welcher das Modul implementiert&lt;br /&gt;
# Die Zeile &amp;lt;code&amp;gt;1;&amp;lt;/code&amp;gt; nachdem der Perl-Code abgeschlossen ist. Dies dient FHEM der Erkennung, dass das Modul erfolgreich und vollständig geladen wurde. Sollte diese Zeile nicht enthalten sein, wird FHEM beim Laden des Moduls die Fehlermeldung &amp;lt;code&amp;gt;Error:Modul 72_MYMODULE deactivated&amp;lt;/code&amp;gt; in das Logfile schreiben.&lt;br /&gt;
# Commandref zur Dokumentation des Moduls. Diese Dokumentation soll dem User die möglichen Befehle/Attribute/Readings/Events vermitteln. Weitere Informationen und Hinweise findet man in den [[Guidelines zur Dokumentation]].&lt;br /&gt;
&lt;br /&gt;
== Der Hash einer Geräteinstanz ==&lt;br /&gt;
Eine Besonderheit in Perl sind [http://de.wikipedia.org/wiki/Assoziatives_Array#Perl assoziative Arrays], (nicht ganz richtig als &amp;quot;Hash&amp;quot; bezeichnet) in denen die Adressierung nicht über eine Zählvariable erfolgt, sondern über einen beliebigen String. Die internen Abläufe bei der Adressierung führen dazu, dass die Speicherung in und der Abruf aus Hashes relativ langsam ist.&lt;br /&gt;
&lt;br /&gt;
Der zentrale Speicherort für Informationen einer Geräteinstanz bei FHEM ist ein solcher Hash, der seinerseits in fhem.pl von einem globalen Hash referenziert wird. &lt;br /&gt;
&lt;br /&gt;
In fhem.pl werden alle Gerätedefinitionen in dem globalen Hash &amp;lt;code&amp;gt;%defs&amp;lt;/code&amp;gt; abgelegt. Der Inhalt von &amp;lt;code&amp;gt;$defs{&#039;&#039;&amp;amp;lt;Name&amp;amp;gt;&#039;&#039;}&amp;lt;/code&amp;gt; in fhem.pl verweist dabei auf den Hash der Geräteinstanz in Form einer Hashreferenz. Diesen Verweis (also nur die Adresse) bekommen die Funktionen eines Moduls übergeben (i.d.R. als &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; bezeichnet), welche direkt von fhem.pl aufgerufen werden. In dem Hash stehen beispielsweise die internen Werte des Geräts, die im Frontend als &amp;quot;Internals&amp;quot; angezeigt werden, sowie die Readings des Geräts. &lt;br /&gt;
&lt;br /&gt;
Beispiele:&lt;br /&gt;
*&amp;lt;code&amp;gt;$hash-&amp;gt;{NAME}&amp;lt;/code&amp;gt; enthält den Namen der Geräteinstanz, &lt;br /&gt;
*&amp;lt;code&amp;gt;$hash-&amp;gt;{TYPE}&amp;lt;/code&amp;gt; enthält die Typbezeichnung des Geräts (Modulname)&lt;br /&gt;
&lt;br /&gt;
==Ausführung von Modulen==&lt;br /&gt;
FHEM arbeitet intern nicht parallel, sondern arbeitet alle Aufgaben seriell nacheinander kontinuierlich ab. Daher wäre es ungünstig, wenn Module Daten von einem physikalischen Gerät abfragen wollen und dabei innerhalb der selben Funktion auf die Antwort des Geräts warten. In dieser Zeit, in der FHEM auf die Antwort des Gerätes warten muss, wäre der Rest von FHEM blockiert. Da immer nur eine Aufgabe zur selben Zeit bearbeitet wird, müssen alle weiteren Aufgaben solange warten. Eine Datenkommunikation innerhalb eines Moduls sollte daher immer ohne Blockierung erfolgen. Dadurch kann FHEM die Wartezeit effizient für andere Aufgaben nutzen um bspw. anstehende Daten für andere Module zu verarbeiten. Es gibt in FHEM entsprechende Mechanismen, welche eine &amp;quot;Non-Blocking&amp;quot;-Kommunikation über verschiedene Wege (z.B. seriell, HTTP, TCP, ...) ermöglichen.&lt;br /&gt;
&lt;br /&gt;
Dafür werden in FHEM zwei zentrale Listen gepflegt, in der die Filedeskriptoren der geöffneten Kommunikatonsverbindungen gespeichert sind. Auf Linux- bzw. Unix-basierten Plattformen wird der select-Befehl des Betriebssystems verwendet um Filedeskriptoren auf lesbare Daten zu überprüfen. In FHEM gibt es dazu eine Liste (&amp;lt;code&amp;gt;%selectlist&amp;lt;/code&amp;gt;), in der die Filedeskriptoren sämtlicher Geräte (z.B. serielle Verbindung, TCP-Verbindung, etc.) gespeichert sind. &lt;br /&gt;
&lt;br /&gt;
In der zentralen Schleife (Main-Loop) von fhem.pl wird mit &amp;lt;code&amp;gt;select()&amp;lt;/code&amp;gt; überwacht, ob über eine der geöffneten Schnittstellen Daten zum Lesen anstehen. Wenn dies der Fall ist, dann wird die Lesefunktion ([[#X_Read|X_Read]]) des zuständigen Moduls aufgerufen, damit es die Daten entgegennimmt und verarbeitet. Anschließend wird die Schleife weiter ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Auf Windows-Systemen funktioniert dies anders. Hier können USB/Seriell-Geräte nicht per &amp;lt;code&amp;gt;select()&amp;lt;/code&amp;gt; überwacht werden. In FHEM unter Windows werden daher diese Schnittstellen kontinuierlich abgefragt ob Daten bereitstehen. Dafür müssen Module zusätzlich zur Lesefunktion eine Abfragefunktion ([[#X_Ready|X_Ready]]) implementieren, welche prüft, ob Daten zum Lesen anstehen. Auch auf Linux/Unix-Plattformen hat diese Funktion eine Aufgabe. Falls nämlich eine Schnittstelle ausfällt, beziehungsweise ein CUL oder USB-zu-Seriell Adapter ausgesteckt wird, dann wird über diese Funktion regelmäßig geprüft ob die Schnittstelle wieder verfügbar wird.&lt;br /&gt;
&lt;br /&gt;
Innerhalb der eigentlichen Lesefunktion (X_Read) werden dann die Daten vom zugehörigen Gerät gelesen, das nötige Protokoll implementiert um die Daten zu interpretieren und Werte in Readings geschrieben.&lt;br /&gt;
&lt;br /&gt;
Auch wenn von einem Anwender über einen Get-Befehl Daten aktiv von einem Gerät angefordert werden, sollte nicht blockierend gewartet werden. Eine asynchrone Ausgabe, sobald das Ergebnis vorliegt, ist über [[DevelopmentModuleAPI#asyncOutput|asyncOutput()]] möglich. Siehe {{Link2Forum|Topic=43771|Message=357870|LinkText=Beschreibung}} und {{Link2Forum|Topic=43771|Message=360935|LinkText=Beispiel}}. Weitere Anwendungsbeispiele finden sich im  {{Link2Forum|Topic=43052|Message=353477|LinkText=PLEX Modul}} und im überarbeiteten und nicht-blockierenden {{Link2Forum|Topic=42771|Message=348498|LinkText=SYSSTAT Modul}}.&lt;br /&gt;
&lt;br /&gt;
== Wichtige globale Variablen aus fhem.pl ==&lt;br /&gt;
&lt;br /&gt;
FHEM arbeitet mit einer Vielzahl an internen Variablen. Die nun folgenden aufgelisteten Variablen sind die wichtigsten, welche man im Rahmen der Modulprogrammierung kennen sollte:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Variable !! Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; || Dient der Erkennung für fhem.pl sowie den Modulen, ob FHEM den Initialisierungsvorgang abgeschlossen hat. Beim Starten von FHEM ist &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; gleich &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;. Erst, wenn das Einlesen der Konfiguration, sowie des State-Files (Readings) abgeschlossen ist, wird &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; auf &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; gesetzt.&lt;br /&gt;
Das gleiche Verfahren wird auch bei dem Befehl &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt; angewandt. Während &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt; ausgeführt wird (Konfiguration löschen, neu einlesen), ist &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; gleich &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Dies ist insbesondere in der [[#X_Define|Define]]-Funktion eines Moduls relevant. Durch eine Prüfung auf &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; kann man erkennen, ob eine Definition von Hand (&amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; = 1) oder im Rahmen der Initialisierung (FHEM Start / Rereadcfg =&amp;gt; &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; = 0) erfolgte. Während der Initialisierung stehen bspw. die gesetzten Attribute der Definition noch nicht zur Verfügung und können daher nicht ausgewertet werden (siehe . &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt; || In &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt; werden sämtliche gesetzten Attribute aller Geräte gespeichert. Diese Datenstruktur wird generell durch den &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt;-Befehl verwaltet. Hierbei wird einem Gerätenamen eine Mehrzahl an Attributnamen mit einem Wert zugeordnet. Attribut-Inhalte können über die Funktion [[DevelopmentModuleAPI#AttrVal|AttrVal()]] ausgelesen werden.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%cmds&amp;lt;/code&amp;gt; || In &amp;lt;code&amp;gt;%cmds&amp;lt;/code&amp;gt; wird jedem in FHEM existierendem Befehl die entsprechende Funktion zugewiesen, welche diesen Befehl umsetzt. Module können durch das Eintragen eines Befehlsnamen samt Funktion in &amp;lt;code&amp;gt;%cmds&amp;lt;/code&amp;gt; über die [[#X_Initialize|Initialize]]-Funktion eines Moduls einen (oder mehrere) eigene Befehle in FHEM registrieren.&lt;br /&gt;
&lt;br /&gt;
Die Struktur ist dabei wiefolgt:&lt;br /&gt;
&lt;br /&gt;
  $cmds{&#039;&#039;&amp;amp;lt;Befehlsname&amp;amp;gt;&#039;&#039;} = {  Fn  =&amp;gt; &amp;quot;&#039;&#039;&amp;amp;lt;Funktionsname&amp;amp;gt;&#039;&#039;&amp;quot;,&lt;br /&gt;
                            Hlp =&amp;gt; &amp;quot;&#039;&#039;&amp;amp;lt;Aufrufsyntax&amp;amp;gt;&#039;&#039;&amp;quot;};&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%data&amp;lt;/code&amp;gt;|| Der eigentliche Zweck von &amp;lt;code&amp;gt;%data&amp;lt;/code&amp;gt; ist dem Nutzer eine Möglichkeit zum Speichern von temporären Daten im globalen Kontext zu ermöglichen. Einige Module verwenden &amp;lt;code&amp;gt;%data&amp;lt;/code&amp;gt; jedoch auch um modul- &amp;amp; geräteübergreifend Daten auszutauschen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%defs&amp;lt;/code&amp;gt;|| In &amp;lt;code&amp;gt;%defs&amp;lt;/code&amp;gt; werden sämtliche Gerätedefinitionen, bzw. die Hash-Referenzen auf diese, gespeichert. Hier ist jedem Gerätenamen eine Hash-Referenz zugeordnet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%modules&amp;lt;/code&amp;gt;|| In &amp;lt;code&amp;gt;%modules&amp;lt;/code&amp;gt; sind alle geladenen Module gelistet mit ihren entsprechenden Initialisierungsdaten (Funktionsnamen, Attribut-Listen, spezielle Einstellungen, ...). Hier wird für jeden Modulname der Modul-Hash aus der [[#X_Initialize|Initialize]]-Funktion gespeichert. &lt;br /&gt;
Desweiteren legen viele Module, welche nach dem [[DevelopmentModuleIntro#Zweistufiges_Modell_f.C3.BCr_Module|zweistufigen Modulkonzept]] hier eine Rückwärtszuordnung von Geräteadressen zu Geräte-Hash an.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt;|| In &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt; sind alle zu prüfenden Verbindungen mit ihrer entsprechendem Geräte-Hash gelistet. FHEM prüft alle hier gelisteten Geräte regelmäßig über eine Aufruf der entsprechenden [[#X_Ready|Ready]]-Funktion.&lt;br /&gt;
&lt;br /&gt;
Bei einer Nutzung von dem Hilfsmodul [[DevIo|DevIo.pm]] zum Aufbau einer Kommunikationsverbindung, kümmert sich DevIo selbständig um den entsprechenden Eintrag in &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;%selectlist&amp;lt;/code&amp;gt;|| In &amp;lt;code&amp;gt;%selectlist&amp;lt;/code&amp;gt; sind alle geöffneten Verbindungen mit ihrer entsprechendem Geräte-Hash gelistet. FHEM prüft alle hier gelisteten Geräte, ob der geöffnete Filedeskriptor unter &amp;lt;code&amp;gt;$hash-&amp;gt;{FD}&amp;lt;/code&amp;gt; Daten zum Lesen bereitgestellt hat. Ist dass der Fall, wird die entsprechende [[#X_Read|Read]]-Funktion aufgerufen, um anstehende Daten durch das Modul zu verarbeiten.&lt;br /&gt;
Bei einer Nutzung von dem Hilfsmodul [[DevIo|DevIo.pm]] zum Aufbau einer Kommunikationsverbindung, kümmert sich DevIo selbständig um den entsprechenden Eintrag in &amp;lt;code&amp;gt;%selectlist&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Es gibt durchaus viele weitere globale Variablen, die jedoch für sehr spezielle Anwendungsfälle und z.T. nur einzelne Module gedacht sind und daher hier nicht aufgeführt werden.&lt;br /&gt;
&lt;br /&gt;
== Internals ==&lt;br /&gt;
Daten, die ein Modul im Geräte-Hash speichert nennt man Internals. Sie werden als Unterstruktur des Hashes der jeweiligen Geräteinstanz gespeichert, beispielswiese &amp;lt;code&amp;gt;$hash-&amp;gt;{NAME}&amp;lt;/code&amp;gt; für den Gerätenamen, welcher beim Define-Befehl übergeben wurde und als Internal gespeichert wird. Diese Daten spielen für FHEM eine sehr wichtige Rolle, da sämtliche gerätespezifischen Daten als Internal im Gerätehash gespeichert werden.&lt;br /&gt;
&lt;br /&gt;
Falls Werte wie z.B. ein Intervall nicht über den Define-Befehl gesetzt werden sollen und im Betrieb einfach änderbar sein sollten, ist eine alternative Möglichkeit die Speicherung in so genannten Attributen. Dann würde man den Define-Befehl so implementieren, dass er kein Intervall übergeben bekommt und statt dessen das Interval als Attribut über den Befehl &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt; gesetzt wird.&lt;br /&gt;
&lt;br /&gt;
Generell werden alle Werte, welche direkt in der ersten Ebene von &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; (Gerätehash) gespeichert werden auf der Detail-Seite einer Definition in der FHEMWEB Oberfläche angezeigt. Es gibt jedoch Ausnahmen:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;$hash-&amp;gt;{helper}{URL}&amp;lt;/code&amp;gt; - Alle Elemente, welche als Unterelement wieder einen Hash besitzen werden nicht in FHEMWEB dargestellt. Typischerweise speichern Module Daten unter &amp;lt;code&amp;gt;$hash-&amp;gt;{helper}&amp;lt;/code&amp;gt; interne Daten zwischen, die für den User nicht relevant sind, sondern nur der internen Verarbeitung dienen.&lt;br /&gt;
* &amp;lt;code&amp;gt;$hash-&amp;gt;{&#039;&#039;&#039;.&#039;&#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;ELEMENT&amp;lt;/font&amp;gt;}&amp;lt;/code&amp;gt; - Alle Knoten, welche mit einem Punkt beginnen werden in der FHEMWEB Oberfläche nicht angezeigt. Man kann diese Daten jedoch beim Aufruf des [[List|list-Kommandos]] einsehen.&lt;br /&gt;
&lt;br /&gt;
Es gibt bereits vorbelegte Internals welche in FHEM dazu dienen definitionsbezogene Informationen wie bspw. Namen und Readings zu speichern. Dies sind im besonderen:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;min-width: 13em;&amp;quot; | Internal !!  Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{NAME}&amp;lt;/code&amp;gt;  || Der Definitionsname, mit dem das Gerät angelegt wurde.  &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{READINGS}&amp;lt;/code&amp;gt;  || Enthält alle aktuell vorhandenen Readings. Daten unterhalb dieses Knotens sollte man nicht direkt manipulieren. Um Readings zu Erzeugen gibt es entsprechende [[DevelopmentModuleAPI#Readings_.2F_Events|Reading-Funktionen]].&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{NR}&amp;lt;/code&amp;gt;  || Die Positions-Nr. der Definition innerhalb der Konfiguration. Diese dient dazu die Konfiguration in der gleichen Reihenfolge zu speichern, wie die einzelnen Geräte angelegt wurden.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{TYPE}&amp;lt;/code&amp;gt;  || Der Modulname, mit welchem die Definition angelegt wurde.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{DEF}&amp;lt;/code&amp;gt;  || Sämtliche Argumente, welche beim &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl nach dem Modulnamen übergeben wurden.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{CFGFN}&amp;lt;/code&amp;gt;  || Der Dateiname der Konfigurationsdatei in der diese Definition enthalten ist (sofern nicht in fhem.cfg). Dieser Wert ist nur gefüllt, wenn man mit mehreren Konfigurationsdateien arbeitet, welche dann in fhem.cfg via include-Befehl eingebunden werden.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{NTFY_ORDER}&amp;lt;/code&amp;gt;  || Sofern das Modul Events via [[DevelopmentModuleIntro#X_Notify|Notify-Funktion]] verarbeitet enthält jede Definition eine Notify-Order als Zeichenkette bestehend aus dem Notify Order Prefix und dem Definitionsnamen. Details zur Funktionsweise gibt es in der Beschreibung zur [[DevelopmentModuleIntro#X_Notify|Notify-Funktion]] im Abschnitt &amp;quot;Reihenfolge für den Aufruf der Notify-Funktion beeinflussen&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{NOTIFYDEV}&amp;lt;/code&amp;gt;  || Sofern das Modul Events via NotifyFn verarbeitet kann man damit die Definitionen, von denen man Events erhalten will begrenzen. Details zur Funktionsweise gibt es in der Beschreibung zur [[DevelopmentModuleIntro#X_Notify|Notify-Funktion]] im Abschnitt &amp;quot;Begrenzung der Aufrufe auf bestimmte Geräte&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{IODev}&amp;lt;/code&amp;gt;  || Hier wird das zugeordnete IO-Gerät durch [[DevelopmentModuleAPI#AssignIoPort|AssignIoPort()]] gespeichert, welches für den Datentransport und -empfang dieses logischen Gerätes zuständig ist. Dieser Wert existiert nur bei Modulen die nach dem [[DevelopmentModuleIntro#Zweistufiges_Modell_f.C3.BCr_Module|zweistufigen Modulkonzept]] arbeiten. &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{CHANGED}&amp;lt;/code&amp;gt;  || Hier werden alle Events kurzzeitig gesammelt, welche für die Eventverarbeitung anstehen. Insbesondere die [[DevelopmentModuleAPI#Readings_.2F_Events|Reading-Funktionen]] speichern hier alle Events zwischen um sie nach Abschluss via [[DevelopmentModuleAPI#DoTrigger|DoTrigger()]] zu verarbeiten. &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{FD}&amp;lt;/code&amp;gt;  || Wenn die Definition eine Netzwerkverbindung oder serielle Schnittstelle geöffnet hat (z.B. via [[DevIo]]), so wird der entsprechende File-Deskriptor in diesem Internal gespeichert. Damit kann FHEM alle geöffneten Filedeskriptoren der entsprechenden Definition zuordnen um bei ankommenden Daten die Definition via [[DevelopmentModuleIntro#X_Read|Read-Funktion]] damit zu versorgen.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash-&amp;gt;{EXCEPT_FD}&amp;lt;/code&amp;gt;  || Ähnlich wie &amp;lt;code&amp;gt;$hash-&amp;gt;{FD}&amp;lt;/code&amp;gt;. Sofern die Definition in &amp;lt;code&amp;gt;[[#Wichtige_globale_Variablen_aus_fhem.pl|%selectlist]]&amp;lt;/code&amp;gt; eingetragen ist und ein Fildeskriptor in diesem Internal gesetzt ist, wird bei einer auftretenden Exception bzw. Interrupt die [[DevelopmentModuleIntro#X_Except|Except]]-Funktion des entsprechenden Moduls aufgerufen um darauf zu reagieren.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Generell sollte man die meisten der hier genannten systemweiten Internals nicht modifizieren, da ansonsten die korrekte Funktionsweise von FHEM nicht mehr garantiert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Readings ==&lt;br /&gt;
Daten, welche von einem Gerät gelesen werden und in FHEM in einer für Menschen verständlichen Form zur Verfügung gestellt werden können, werden Readings genannt. Sie geben den Status des Gerätes wieder und erzeugen Events innerhalb von FHEM auf die andere Geräte reagieren können. Sie werden als Unterstruktur des Hashes der jeweiligen Geräteinstanz gespeichert, beispielsweise &lt;br /&gt;
*&amp;lt;code&amp;gt;$hash-&amp;gt;{READINGS}{temperature}{VAL}&amp;lt;/code&amp;gt; für die Temperatur eines Fühlers&lt;br /&gt;
*&amp;lt;code&amp;gt;$hash-&amp;gt;{READINGS}{temperature}{TIME}&amp;lt;/code&amp;gt; für den Zeitstempel der Messung&lt;br /&gt;
&lt;br /&gt;
Für den lesenden Zugriff auf Readings steht die Funktion &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#ReadingsVal|ReadingsVal()]]&amp;lt;/code&amp;gt; zur Verfügung. Ein direkter Zugriff auf die Datenstruktur sollte nicht vorgenommen werden.&lt;br /&gt;
&lt;br /&gt;
Readings werden im Statefile von FHEM automatisch auf der Festplatte zwischengespeichert, damit sie nach einem Neustart sofort wieder zur Verfügung stehen. Dadurch ist der letzte Status eines Gerätes vor einem Neustart nachvollziehbar.&lt;br /&gt;
&lt;br /&gt;
Readings, die mit einem Punkt im Namen beginnen, haben eine funktionale Besonderheit. Sie werden im FHEMWEB nicht angezeigt und können somit als &amp;quot;Permanentspeicher&amp;quot; für kleinere Daten innerhalb des Moduls genutzt werden. Um größere Datenmengen permanent zu speichern sollte man jedoch die Funktion &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#setKeyValue|setKeyValue()]]&amp;lt;/code&amp;gt; verwenden.&lt;br /&gt;
&lt;br /&gt;
Zum Setzen von Readings sollen &lt;br /&gt;
*bei Gruppen von Readings der Funktionsblock &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsBeginUpdate|readingsBeginUpdate()]]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsBulkUpdate|readingsBulkUpdate()]]&amp;lt;/code&amp;gt; (mehrfach wiederholt), &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsEndUpdate|readingsEndUpdate()]]&amp;lt;/code&amp;gt;&lt;br /&gt;
*bei einzelnen Updates die Funktion &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsSingleUpdate|readingsSingleUpdate()]]&amp;lt;/code&amp;gt; &lt;br /&gt;
aufgerufen werden. Dabei kann man auch angeben, ob dabei ein Event ausgelöst werden soll oder nicht. Events erzeugen, je nach Hardwareperformance, spürbare Last auf dem System (siehe [[DevelopmentModuleIntro#X_Notify|NotifyFn]]), das Ändern von Readings ohne dass dabei Events erzeugt werden jedoch nicht.&lt;br /&gt;
&lt;br /&gt;
Eine Sequenz zum Setzen von Readings könnte folgendermaßen aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
readingsBeginUpdate($hash);&lt;br /&gt;
readingsBulkUpdate($hash, $readingName1, $wert1 );&lt;br /&gt;
readingsBulkUpdate($hash, $readingName2, $wert2 );&lt;br /&gt;
readingsEndUpdate($hash, 1);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um Readings zu löschen, wird für die Modulprogrammierung die Funktion &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsDelete|readingsDelete()]]&amp;lt;/code&amp;gt; empfohlen. Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
readingsDelete($hash, $readingsname) &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{Hinweis|&#039;&#039;&#039;Hintergrundinfo dazu aus dem Forum:&#039;&#039;&#039; {{Link2Forum|Topic=83069|Message=753066}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;CommandDeleteReading()&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;deletereading&amp;lt;/code&amp;gt; ist eher fuer den Endbenutzer und seine userReadings gedacht, und macht bei den Modulen die unnoetige Schleife ueber [[DevelopmentModuleAPI#devspec2array|devspec2array()]]. Wenn der Modulautor beim Aufruf auch &amp;lt;code&amp;gt;$cl&amp;lt;/code&amp;gt; weitergibt, und der Anwender meint, dieses Geraet auf blacklist setzen zu muessen, dann kann das Modul sein eigenes Reading nicht entfernen, und das ist kontraproduktiv.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Events ==&lt;br /&gt;
&lt;br /&gt;
FHEM verfügt über einen Event-Mechanismus um Änderungen verschiedenster Art an einzelne oder alle Definitionen mitzuteilen. Jedes Modul (und damit alle Definitionen dieses Moduls) können auf Events von FHEM selber (Definition &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt;) oder von anderen Definitionen reagieren und dadurch selber aktiv werden. Ein Event wird innerhalb von FHEM als Zeichenkette behandelt.&lt;br /&gt;
&lt;br /&gt;
Events sind grundsätzlich immer definitionsbezogen. Das bedeutet, dass ein Event immer in Verbindung mit einem Definitionsnamen erzeugt wird. Jede Definition, welche ein Event verarbeitet, erhält den Definitions-Hash (&amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;) der auslösenden Definition.&lt;br /&gt;
&lt;br /&gt;
Events werden typischerweise bei der Erstellung von Readings implizit für jedes einzelne Reading erzeugt. Es gibt jedoch auch Events die nichts mit Readings zu tun haben um anderweitige Änderungen bekannt zu geben.&lt;br /&gt;
&lt;br /&gt;
Eigene Events können in FHEM mit der Funktion [[DevelopmentModuleAPI#DoTrigger|DoTrigger()]] erzeugt werden. Um auf Events in einem Modul reagieren zu können, muss eine [[#X_Notify|Notify]]-Funktion implementiert sein. Sobald ein oder mehrere Events für eine Definition getriggert werden, prüft FHEM, welche Definitionen über Events der auslösenden Definition informiert werden möchten. Diese werden dann nacheinander in einer bestimmten Reihenfolge durch Aufruf der [[#X_Notify|Notify]]-Funktion über anstehende Events in Kenntnis gesetzt. Es obliegt dann dem jeweiligen Modul, wie es auf die Events reagiert.&lt;br /&gt;
&lt;br /&gt;
=== globale Events ===&lt;br /&gt;
&lt;br /&gt;
Als &amp;quot;globale Events&amp;quot; werden alle Events bezeichnet, die durch die Definition &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt; erzeugt werden. Es handelt sich hierbei um Events die Strukturänderungen in der Konfiguration, als auch systemweite Ereignisse zu FHEM selbst signalisieren.&lt;br /&gt;
&lt;br /&gt;
Hier eine kurze Zusammenfassung, welche Events durch &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt; getriggert werden können:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Allgemeine Events:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event-Text !! Beschreibung.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;INITIALIZED&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Der Start von FHEM ist abgeschlossen. Sämtliche Definitionen und Attribute wurden aus der Konfiguration (fhem.cfg oder configDB) eingelesen, sowie sämtliche Readings sind aus dem State-File eingelesen und stehen nun voll umfänglich zur Verfügung.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;REREADCFG&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Die Konfiguration wurde erneut eingelesen. Dies bedeutet, es wurden alle Definitionen/Attribute/Readings aus FHEM entfernt und durch Einlesen der Konfiguration neu angelegt. (FHEM-Befehl: &amp;quot;rereadcfg&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;SAVE&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Die laufende Konfiguration soll gespeichert werden (in fhem.cfg oder configDB). Dieses Event wird &#039;&#039;&#039;VOR&#039;&#039;&#039; dem Speichern der Konfiguration getriggert. Sobald der Trigger verarbeitet wurde, beginnt das Speichern der Konfiguration. (FHEM-Befehl: &amp;quot;save&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;SHUTDOWN&amp;lt;/code&amp;gt;&#039;&#039;&#039; || FHEM wird sich beenden. (FHEM-Befehl: &amp;quot;shutdown&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt; DELAYEDSHUTDOWN &amp;lt;/code&amp;gt;&#039;&#039;&#039; || FHEM wird sich beenden. (FHEM-Befehl: &amp;quot;shutdown&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;UPDATE&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Es wurde ein Update erfolgreich installiert. (FHEM-Befehl: &amp;quot;update&amp;quot;)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Definitionsbezogene Events:&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Event-Text !! Beschreibung.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;DEFINED &#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Es wurde eine neue Definition mit Namen &amp;lt;code&amp;gt;&#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; angelegt. (FHEM-Befehl: &amp;quot;define&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;DELETED &#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Die Definition mit dem Namen &amp;lt;code&amp;gt;&#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; wurde gelöscht. (FHEM-Befehl: &amp;quot;delete&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;RENAMED &#039;&#039;&amp;lt;Alt&amp;gt;&#039;&#039; &#039;&#039;&amp;lt;Neu&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Die Definition mit dem Namen &amp;lt;code&amp;gt;&#039;&#039;&amp;lt;Alt&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; wurde in den Namen &amp;lt;code&amp;gt;&#039;&#039;&amp;lt;Neu&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; umbenannt. (FHEM-Befehl: &amp;quot;rename&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;MODIFIED &#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Die Definition mit dem Namen &amp;lt;code&amp;gt;&#039;&#039;&amp;lt;Name&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; wurde modifiziert. (FHEM-Befehl: &amp;quot;modify&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &#039;&#039;&#039;&amp;lt;code&amp;gt;UNDEFINED &#039;&#039;&amp;lt;Name&amp;gt; &amp;lt;Modul&amp;gt; &amp;lt;Define-Parameter&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&#039;&#039;&#039; || Es wurde eine Nachricht von einem physikalischen Modul (siehe [[#Zweistufiges Modell für Module|zweistufiges Modulkonzept]]) erhalten, für die keine passende logische Definition in FHEM existiert. Details dazu, siehe dazu Abschnitt [[#Automatisches Anlegen von logischen Gerätedefinitionen (autocreate)|Automatisches Anlegen von logischen Gerätedefinitionen (autocreate)]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Begrenzung von Events ===&lt;br /&gt;
&lt;br /&gt;
Ein Modul, welches Events verarbeitet, kann die Eventverarbeitung auf bestimmte Definitionen begrenzen. Dadurch werden nur Events an das Modul gemeldet (via [[#X_Notify|X_Notify()]]), welche von einer oder mehreren bestimmten Definitionen getriggert wurden. Dadurch werden unnötige Events nicht an das Modul gemeldet und schont somit Ressourcen.&lt;br /&gt;
&lt;br /&gt;
Standardmäßig werden sämtliche Events ohne Begrenzung an ein Modul gemeldet, welches eine [[#X_Notify|Notify]]-Funktion implementiert hat und somit Events verarbeiten kann. Details zur Begrenzung von Events findet man in der Beschreibung zur Modulfunktion [[#X_Notify|X_Notify()]].&lt;br /&gt;
&lt;br /&gt;
=== Reihenfolge der Eventverarbeitung ===&lt;br /&gt;
&lt;br /&gt;
Ein getriggertes Event wird nacheinander gegen jede Definition geprüft, deren Modul eine [[#X_Notify|Notify]]-Funktion implementiert hat. Dies bedeutet, jede Definition wird nacheinander durch Aufruf der [[#X_Notify|Notify]]-Funktion mit dem Definitionshash der auslösenden Definition aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Unter bestimmten Umständen kann es erforderlich sein, in diese Reihenfolge einzugreifen. Beispielsweise wenn das eigene Modul und deren Definitionen das Event als letztes oder erstes verarbeiten müssen. Ein Beispiel bietet hierbei das Modul [[dewpoint]], welches Events vor allen anderen Modulen verarbeiten muss.&lt;br /&gt;
&lt;br /&gt;
Details, wie man die Reihenfolge der Eventverarbeitung steuern kann, findet man in der Beschreibung zur Modulfunktion [[#X_Notify|X_Notify()]].&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
Damit der Nutzer das Verhalten einer einzelnen Gerätedefinition zur Laufzeit individuell anpassen kann, gibt es in FHEM für jede Definition sogenannte Attribute, welche mit dem Befehl &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt; gesetzt werden können.&lt;br /&gt;
Diese stehen dann dem Modul unmittelbar zur Verfügung um das Verhalten während der Ausführung zu beeinflussen. Attribute werden zusammen mit dem &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl der jeweiligen Definition beim Speichern der aktuellen Konfiguration von FHEM in die Konfigurationsdatei geschrieben. Beim Neustart werden die entsprechenden Befehle ausgeführt um alle Definition inkl. Attribute wieder anzulegen. Zur Laufzeit werden Attribute in dem globalen Hash &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt; mit dem Definitionsnamen als Index (&amp;lt;code&amp;gt;$attr{$name} = $value&amp;lt;/code&amp;gt;) gespeichert. Ein Attribut mit dem Namen &amp;lt;code&amp;gt;header&amp;lt;/code&amp;gt; würde beispielsweise mit &amp;lt;code&amp;gt;$attr{$name}{header}&amp;lt;/code&amp;gt; adressiert. Generell sollte &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt; nicht durch direkten Zugriff manipuliert/benutzt werden.&lt;br /&gt;
&lt;br /&gt;
Zum Auslesen von Attributen sollte die Funktion [[DevelopmentModuleAPI#AttrVal|AttrVal()]] verwendet werden.&lt;br /&gt;
&lt;br /&gt;
Welche Attribute ein Modul unterstützt muss in der Funktion &amp;lt;code&amp;gt;[[#X_Initialize|X_Initialize]]&amp;lt;/code&amp;gt; durch Setzen von &amp;lt;code&amp;gt;$hash-&amp;gt;{AttrList}&amp;lt;/code&amp;gt; bekannt gemacht werden (siehe unten).&lt;br /&gt;
&lt;br /&gt;
Wenn beim Setzen von Attributen in einer Gerätedefinition entsprechende Werte geprüft werden sollen oder zusätzliche Funktionalitäten implementiert werden müssen, dann muss dies in der Funktion &amp;lt;code&amp;gt;[[#X_Attr|X_Attr]]&amp;lt;/code&amp;gt; (siehe unten) implementiert werden. Hier kann man bspw. einen Syntaxcheck für Attribut-Werte implementieren um ungültige Werte zurückzuweisen.&lt;br /&gt;
&lt;br /&gt;
== Modulfunktionen ==&lt;br /&gt;
&lt;br /&gt;
Damit fhem.pl ein Modul nutzen kann, muss dieses entsprechende Funktionen mit einer vorgegebenen Aufrufsyntax implementieren. Durch die Bekanntgabe dieser modulspezifischen Funktionen können Daten zwischen fhem.pl und einem Modul entsprechend ausgetauscht werden. Es gibt verschiedene Arten von Funktionen die ein Modul anbieten muss bzw. kann, je nach Funktionsumfang.&lt;br /&gt;
&lt;br /&gt;
=== Die wichtigsten Funktionen in einem Modul ===&lt;br /&gt;
&lt;br /&gt;
Folgende Funktion muss ein Modul mit dem beispielhaften Namen &amp;quot;X&amp;quot; mindestens bereitstellen:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;text-align:left&amp;quot; | Funktionsname !! style=&amp;quot;text-align:left&amp;quot; | Kurzbeschreibung&lt;br /&gt;
|-&lt;br /&gt;
|  [[#X_Initialize|X_Initialize]] || Initialisiert das Modul und gibt den Namen zusätzlicher Modulfunktionen bekannt, sowie modulspezifische Einstellungen. Wird direkt nach dem erfolgreichen Laden des Moduls durch fhem.pl aufgerufen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Die folgenden Funktionen sind die wichtigsten Funktionen, welche je nach Anwendungsfall zu implementieren sind. Es handelt sich hierbei um die wichtigsten Vertreter, welche in den meisten Modulen Verwendung finden. Nicht alle Funktionen machen jedoch in jedem Modul Sinn. Generell sollte auch hier bei jeder Funktion der Modulname vorangestellt werden um ein einheitliches Namensschema zu gewährleisten. Hier die wichtigsten Modulfunktionen:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;text-align:left&amp;quot; | Funktionsname !! style=&amp;quot;text-align:left&amp;quot; class=&amp;quot;unsortable&amp;quot; | Kurzbeschreibung&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Define|X_Define]] || Wird im Rahmen des &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehls aufgerufen.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Undef|X_Undef]] || Wird im Rahmen des &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt;-Befehls, sowie &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt;-Befehl aufgerufen. Dient zum Abbau von offenen Verbindungen, Timern, etc.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Delete|X_Delete]] || Wird im Rahmen des beim &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt;-Befehls aufgerufen wenn das Gerät endgültig gelöscht wird um weiterführende Aktionen vor dem Löschen durchzuführen.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Get|X_Get]] || Wird im Rahmen des &amp;lt;code&amp;gt;get&amp;lt;/code&amp;gt;-Befehls aufgerufen um Daten vom Gerät abzufragen&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Set|X_Set]]  || Wird im Rahmen des &amp;lt;code&amp;gt;set&amp;lt;/code&amp;gt;-Befehls aufgerufen um Daten an das Gerät zu senden.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Attr|X_Attr]]  || Wird im Rahmen des &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt;-Befehls aufgerufen um Attributwerte zu prüfen)&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Read|X_Read]]  || Wird durch FHEM aufgerufen, wenn ein gelisteter Filedeskriptor in &amp;lt;code&amp;gt;[[#Wichtige_globale_Variablen_aus_fhem.pl|%selectlist]]&amp;lt;/code&amp;gt; Daten zum Lesen bereitstellt.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Ready|X_Ready]]  || Wird unter Windows durch FHEM aufgerufen um zyklisch einen seriellen Filedeskriptor auf lesbare Daten zu prüfen. Unter Linux dient diese Funktion dem Wiederaufbau verlorener Verbindungen.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Notify|X_Notify]]  || Verarbeitet Events von anderen Geräten innerhalb von FHEM&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Rename|X_Rename]] || Wird aufgerufen, wenn ein Gerät umbenannt wird.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Shutdown|X_Shutdown]] || Wird beim Herunterfahren von FHEM ausgeführt.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_DelayedShutdown | X_DelayedShutdown]] || Wird beim Herunterfahren von FHEM ausgeführt.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Diese Funktionen werden in diesem Abschnitt genauer beschrieben.&lt;br /&gt;
&lt;br /&gt;
==== X_Initialize ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; im Namen muss dabei auf den Namen des Moduls bzw. des definierten Gerätetyps geändert werden. Im Modul mit der Datei &amp;lt;code&amp;gt;36_JeeLink.pm&amp;lt;/code&amp;gt; beispielsweise ist der Name der Funktion &amp;lt;code&amp;gt;JeeLink_Initialize&amp;lt;/code&amp;gt;. Die Funktion wird von fhem.pl nach dem Laden des Moduls aufgerufen und bekommt eine leere Hashreferenz für den Initialisierungsvorgang übergeben. &lt;br /&gt;
&lt;br /&gt;
Dieser Hash muss nun von X_Initialize mit allen modulrelevanten Funktionsnamen gefüllt werden. Anschließend wird dieser Hash durch fhem.pl im globalen Hash &amp;lt;code&amp;gt;%modules&amp;lt;/code&amp;gt; gespeichert. &amp;lt;code&amp;gt;$modules{ModulName}&amp;lt;/code&amp;gt; wäre dabei der Hash für das Modul mit dem Namen &amp;lt;code&amp;gt;ModulName&amp;lt;/code&amp;gt;. Es handelt sich also nicht um den oben beschriebenen Hash der Geräteinstanzen sondern einen Hash, der für jedes Modul existiert und modulspezifische Daten wie bspw. die implementierten Modulfunktionen enthält. Die Initialize-Funktion setzt diese Funktionsnamen, in den Hash des Moduls wie folgt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
$hash-&amp;gt;{DefFn}                = &amp;quot;X_Define&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{UndefFn}              = &amp;quot;X_Undef&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{DeleteFn}             = &amp;quot;X_Delete&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{SetFn}                = &amp;quot;X_Set&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{GetFn}                = &amp;quot;X_Get&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{AttrFn}               = &amp;quot;X_Attr&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{ReadFn}               = &amp;quot;X_Read&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{ReadyFn}              = &amp;quot;X_Ready&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{NotifyFn}             = &amp;quot;X_Notify&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{RenameFn}             = &amp;quot;X_Rename&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{ShutdownFn}           = &amp;quot;X_Shutdown&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{DelayedShutdownFn}    = &amp;quot;X_ DelayedShutdown&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um eine entsprechende Funktion in FHEM bekannt zu machen muss dazu der Funktionsname, wie er im Modul als &amp;lt;code&amp;gt;sub &amp;amp;lt;&#039;&#039;Funktionsname&#039;&#039;&amp;amp;gt;() { ... }&amp;lt;/code&amp;gt; definiert ist, als Zeichenkette in &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; gesetzt werden. Dabei sollten die entsprechenden Funktionsnamen immer den Modulnamen (in diesem Beispiel &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt;) als Präfix verwenden.&lt;br /&gt;
Auf diese Weise können sämtliche modulspezifisch implementierten Funktionen wie &amp;lt;code&amp;gt;X_Read&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;X_Parse&amp;lt;/code&amp;gt; etc. durch Zuweisung an &amp;lt;code&amp;gt;$hash-&amp;gt;{ReadFn}&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;$hash-&amp;gt;{ParseFn}&amp;lt;/code&amp;gt; usw. bekannt gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Darüber hinaus sollten die vom Modul unterstützten Attribute definiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
$hash-&amp;gt;{AttrList} =&lt;br /&gt;
  &amp;quot;do_not_notify:1,0 &amp;quot; . &lt;br /&gt;
  &amp;quot;header &amp;quot; .&lt;br /&gt;
  $readingFnAttributes;  &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Auflistung aller unterstützten modulspezifischen Attribute erfolgt in Form einer durch Leerzeichen getrennten Liste in &amp;lt;code&amp;gt;$hash-&amp;gt;{AttrList}&amp;lt;/code&amp;gt;. Es gibt in FHEM globale Attribute, die in allen Gerätedefinitionen verfügbar sind und nur modulspezifische Attribute die jedes Modul via &amp;lt;code&amp;gt;$hash-&amp;gt;{AttrList}&amp;lt;/code&amp;gt; über die eigene Initialize-Funktion setzt.  In fhem.pl werden dann die entsprechenden Attributwerte beim Aufruf eines &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt;-Befehls in die globale Datenstruktur &amp;lt;code&amp;gt;$attr{$name}&amp;lt;/code&amp;gt;, z.B. &amp;lt;code&amp;gt;$attr{$name}{header}&amp;lt;/code&amp;gt; für das Attribut &amp;lt;code&amp;gt;header&amp;lt;/code&amp;gt; gespeichert. Falls im Modul weitere Aktionen oder Prüfungen beim Setzen eines Attributs nötig sind, dann kann wie im Beispiel oben die [[#X_Attr|Attr]]-Funktion implementiert und in der Initialize-Funktion bekannt gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Die Variable &amp;lt;code&amp;gt;$readingFnAttributes&amp;lt;/code&amp;gt;, die im obigen Beispiel an die Liste der unterstützten Attribute angefügt wird, definiert Attributnamen, die dann zusätzlich gemacht werden, wenn das Modul zum Setzen von Readings die Funktionen &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsBeginUpdate|readingsBeginUpdate()]]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsBulkUpdate|readingsBulkUpdate()]]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsEndUpdate|readingsEndUpdate()]]&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#readingsSingleUpdate|readingsSingleUpdate()]]&amp;lt;/code&amp;gt; verwendet. In diesen Funktionen werden Attribute wie &amp;lt;code&amp;gt;event-min-interval&amp;lt;/code&amp;gt; oder auch &amp;lt;code&amp;gt;event-on-change-reading&amp;lt;/code&amp;gt; ausgewertet. Für Details hierzu siehe commandref zu {{Link2CmdRef|Anker=readingFnAttributes|Label=readingFnAttributes}}.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von parseParams()&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion &amp;lt;code&amp;gt; [[DevelopmentModuleAPI#parseParams|parseParams()]]&amp;lt;/code&amp;gt; unterstützt Modul-Autoren beim Parsen von Übergabeparametern, welche bei &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;get&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;set&amp;lt;/code&amp;gt; Kommandos an die entsprechenden Modulfunktionen übergeben werden. Dadurch lassen sich auf einfache Weise insbesondere komplexe Parameter (wie bspw. Perl-Ausdrücke) sehr einfach parsen.&lt;br /&gt;
&lt;br /&gt;
Diese Zusatzfunktion kann man in der Initialize-Funktion einfach über folgenden Parameter für [[#X_Define|Define]]-, [[#X_Get|Get]]- und [[#X_Set|Set]]-Funktion modulweit aktivieren:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;$hash-&amp;gt;{parseParams} = 1;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Sobald es gesetzt ist wird automatisch durch fhem.pl &amp;lt;code&amp;gt;[[DevelopmentModuleAPI#parseParams|parseParams()]]&amp;lt;/code&amp;gt; aufgerufen und die an die [[#X_Define|Define]]-, [[#X_Get|Get]]- und [[#X_Set|Set]]-Funktion übergebenen Parameter ändern sich wie weiter unten in den jeweiligen Funktionen beschrieben.&lt;br /&gt;
&lt;br /&gt;
==== X_Define ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $def ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Define-Funktion eines Moduls wird von FHEM aufgerufen wenn der Define-Befehl für ein Geräte ausgeführt wird und das Modul bereits geladen und mit der Initialize-Funktion initialisiert ist. Sie ist typischerweise dazu da, die übergebenen Parameter zu prüfen und an geeigneter Stelle zu speichern sowie einen Kommunikationsweg zum Gerät zu öffnen (z.B. TCP-Verbindung, USB-Schnittstelle o.ä.) oder einen [[#Pollen_von_Geräten|Status-Timer]] zu starten.&lt;br /&gt;
Sie beginnt typischerweise mit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $def ) = @_;&lt;br /&gt;
	my @a = split( &amp;quot;[ \t][ \t]*&amp;quot;, $def );&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Als Übergabeparameter bekommt die Define-Funktion den Hash der Geräteinstanz sowie den die im &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl übergebenen Parameter. Welche bzw. wie viele Parameter &lt;br /&gt;
akzeptiert werden und welcher Syntax diese entsprechen müssen ist Sache dieser Funktion. Im obigen Beispiel wird die Argumentzeile &amp;lt;code&amp;gt;$def&amp;lt;/code&amp;gt; in ein Array aufgeteilt (durch Leerzeichen/Tabulator getrennt) und so können die vom Modul bzw. der Define-Funktion erwarteten Werte über das Array der Reihe nach verarbeitet werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
my $name   = $a[0];&lt;br /&gt;
my $module = $a[1];&lt;br /&gt;
my $url    = $a[2];&lt;br /&gt;
my $inter  = 300;&lt;br /&gt;
&lt;br /&gt;
if(int(@a) == 4) { &lt;br /&gt;
	$inter = $a[3]; &lt;br /&gt;
	if ($inter &amp;lt; 5) {&lt;br /&gt;
		return &amp;quot;interval too small, please use something &amp;gt; 5s, default is 300 seconds&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit die übergebenen Werte auch anderen Funktionen zur Verfügung stehen und an die jeweilige Geräteinstanz gebunden sind, werden die Werte typischerweise als Internals im Hash der Geräteinstanz gespeichert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
$hash-&amp;gt;{url} 		= $url;&lt;br /&gt;
$hash-&amp;gt;{Interval}	= $inter;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald alle Parameter korrekt verarbeitet wurden, wird in der Regel die erste Verbindung zum Gerät aufgebaut. Je nach Art des Geräts kann das eine permanente Datenverbindung sein (z.B. serielle Schnittstelle oder TCP-Verbindung) oder das Starten eines regelmäßigen Timers, der zyklisch den Status z.B. via [[HttpUtils|HTTP]] ausliest.&lt;br /&gt;
&lt;br /&gt;
Sollten im Rahmen der Define-Funktion Syntax-Probleme der Übergabeparameter festgestellt werden oder es kann bspw. keine Verbindung aufgebaut werden, so ist als Funktionsrückgabewert eine entsprechende Fehlermeldung zurückzugeben. Nur wenn alle Übergabeparameter akzeptiert werden, darf &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurückgegeben werden. Sobald eine Define-Funktion eine Fehlermeldung zurückmeldet, wird der define-Befehl durch FHEM zurückgewiesen und der User erhält die Fehlermeldung, welche die Define-Funktion produziert hat, als Ausgabe zurück.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Verfügbarkeit von Attributen&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Während die Define-Funktion ausgeführt wird, sollte man nicht davon ausgehen, dass alle vom Nutzer konfigurierten Attribute via [[DevelopmentModuleAPI#AttrVal|AttrVal()]] verfügbar sind. Attribute stehen in der Define-Funktion nur dann zur Verfügung, wenn FHEM sich nicht in der Initialisierungsphase befindet (globale Variable &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; ist wahr; der Nutzer hat die Gerätedefinition modifiziert). Daher sollte man weiterführende Funktion, welche auf gesetzte Attribute angewiesen sind, nur dann in der Define-Funktion starten, wenn &amp;lt;code&amp;gt;$init_done&amp;lt;/code&amp;gt; zutrifft.&lt;br /&gt;
&lt;br /&gt;
Andernfalls sollte man den Aufruf in der Notify-Funktion durchführen sobald &amp;lt;code&amp;gt;global:INITIALIZED&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;global:REREADCFG&amp;lt;/code&amp;gt; getriggert wurde:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $def ) = @_;&lt;br /&gt;
 &lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	$hash-&amp;gt;{NOTIFYDEV} = &amp;quot;global&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	X_FunctionWhoNeedsAttr($hash) if($init_done);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub X_Notify($$)&lt;br /&gt;
{&lt;br /&gt;
	my ($own_hash, $dev_hash) = @_;&lt;br /&gt;
	my $ownName = $own_hash-&amp;gt;{NAME}; # own name / hash&lt;br /&gt;
 &lt;br /&gt;
	return &amp;quot;&amp;quot; if(IsDisabled($ownName)); # Return without any further action if the module is disabled&lt;br /&gt;
 &lt;br /&gt;
	my $devName = $dev_hash-&amp;gt;{NAME}; # Device that created the events&lt;br /&gt;
	my $events = deviceEvents($dev_hash, 1);&lt;br /&gt;
&lt;br /&gt;
	if($devName eq &amp;quot;global&amp;quot; &amp;amp;&amp;amp; grep(m/^INITIALIZED|REREADCFG$/, @{$events}))&lt;br /&gt;
	{&lt;br /&gt;
		 X_FunctionWhoNeedsAttr($hash);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dadurch wird die Modulfunktion X_FunctionWhoNeedsAttr() nach dem Start erst aufgerufen, wenn alle Attribute aus der Konfiguration geladen wurden.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von parseParams()&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Aufteilen und Parsen von &amp;lt;code&amp;gt;$def&amp;lt;/code&amp;gt; lässt sich die Funktion [[DevelopmentModuleAPI#parseParams|parseParams()]] verwenden um die einzelnen Argumente einfach zu parsen. Wenn in [[#X_Initialize|X_Initialize()]] &amp;lt;code&amp;gt;$hash-&amp;gt;{parseParams} = 1;&amp;lt;/code&amp;gt; gesetzt wurde dann wird parseParams() automatisch aufgerufen und X_Define() ändert sich wie folgt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $a, $h ) = @_;&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die genauen Möglichkeiten von parseParams() sind in dem entsprechenden [[DevelopmentModuleAPI#parseParams|Artikel]] dokumentiert.&lt;br /&gt;
&lt;br /&gt;
==== X_Undef ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Undef ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Die Undef-Funktion wird aufgerufen wenn ein Gerät mit &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; gelöscht wird oder bei der Abarbeitung des Befehls &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt;, der ebenfalls alle Geräte löscht und danach das Konfigurationsfile neu einliest. Entsprechend müssen in der Funktion typische Aufräumarbeiten durchgeführt werden wie das saubere Schließen von Verbindungen oder das Entfernen von internen Timern, sofern diese im Modul zum Pollen verwendet wurden (siehe Abschnitt [[#Pollen_von_Geräten|Pollen von Geräten]]). &lt;br /&gt;
&lt;br /&gt;
Zugewiesene Variablen im Hash der Geräteinstanz, Internals oder Readings müssen hier nicht gelöscht werden. In fhem.pl werden die entsprechenden Strukturen beim Löschen der Geräteinstanz ohnehin vollständig gelöscht.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Undef($$)    &lt;br /&gt;
{                     &lt;br /&gt;
	my ( $hash, $name) = @_;       &lt;br /&gt;
	DevIo_CloseDev($hash);         &lt;br /&gt;
	RemoveInternalTimer($hash);    &lt;br /&gt;
	return undef;                  &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollten im Rahmen der Undef-Funktion Probleme festgestellt werden, die ein Löschen nicht zulassen, so ist als Funktionsrückgabewert eine entsprechende Fehlermeldung zurückzugeben. Nur wenn die Undef-Funktion erfolgreich durchgeführt wurde, darf &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurückgegeben werden. Nur dann wird eine Gerätedefinition von FHEM auch tatsächlich gelöscht bzw. neu angelegt. Sollte die Undef-Funktion jedoch eine Fehlermeldung zurückgeben, wird der entsprechende Vorgang (&amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt;) für dieses Gerät abgebrochen. Es bleibt dann unverändert in FHEM bestehen.&lt;br /&gt;
&lt;br /&gt;
==== X_Delete ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Delete ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Delete-Funktion ist das Gegenstück zur Funktion [[#X_Define|X_Define]] und wird aufgerufen wenn ein Gerät mit dem Befehl &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; gelöscht wird. &lt;br /&gt;
&lt;br /&gt;
Wenn ein Gerät in FHEM gelöscht wird, wird zuerst die Funktion [[#X_Undef|X_Undef]] aufgerufen um offene Verbindungen zu schließen, anschließend wird die Funktion X_Delete aufgerufen. Diese dient eher zum Aufräumen von dauerhaften Daten, welche durch das Modul evtl. für dieses Gerät spezifisch erstellt worden sind. Es geht hier also eher darum, alle Spuren sowohl im laufenden FHEM-Prozess, als auch dauerhafte Daten bspw. im physikalischen Gerät zu löschen die mit dieser Gerätedefinition zu tun haben.&lt;br /&gt;
&lt;br /&gt;
Dies kann z.B. folgendes sein:&lt;br /&gt;
&lt;br /&gt;
* Löschen von Dateien im Dateisystem die während der Nutzung dieses Geräts angelegt worden sind.&lt;br /&gt;
* Lösen von evtl. Pairings mit dem physikalischen Gerät &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Delete($$)    &lt;br /&gt;
{                     &lt;br /&gt;
	my ( $hash, $name ) = @_;       &lt;br /&gt;
&lt;br /&gt;
	# Löschen von Geräte-assoziiertem Temp-File&lt;br /&gt;
	unlink($attr{global}{modpath}.&amp;quot;/FHEM/FhemUtils/$name.tmp&amp;quot;;)&lt;br /&gt;
&lt;br /&gt;
	return undef;&lt;br /&gt;
}    &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollten im Rahmen der Delete-Funktion Probleme festgestellt werden, die ein Löschen nicht zulassen, so ist als Funktionsrückgabewert eine entsprechende Fehlermeldung zurückzugeben. Nur die Delete-Funktion erfolgreich durchgeführt wurde, darf &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurückgegeben werden. Nur dann wird eine Gerätedefinition von FHEM auch tatsächlich gelöscht. Sollte die Delete-Funktion eine Fehlermeldung zurückgeben, wird der Löschvorgang abgebrochen und das Gerät bleibt weiter in FHEM bestehen.&lt;br /&gt;
&lt;br /&gt;
==== X_Get ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Get ($$@)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name, $opt, @args ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $result;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Die Get-Funktion wird aufgerufen wenn der FHEM-Befehl &amp;lt;code&amp;gt;get&amp;lt;/code&amp;gt; für eine Definition dieses Moduls ausgeführt wird. Mit &amp;lt;code&amp;gt;get&amp;lt;/code&amp;gt; werden typischerweise Werte von einem Gerät abgefragt. In vielen Modulen wird auf diese Weise auch der Zugriff auf generierte Readings ermöglicht. Der Get-Funktion wird dabei der Definitions-Hash &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;, der Definitionsname &amp;lt;code&amp;gt;$name&amp;lt;/code&amp;gt;, sowie die Aufrufparameter &amp;lt;code&amp;gt;$opt&amp;lt;/code&amp;gt; plus optional weiterer Parameter &amp;lt;code&amp;gt;@args&amp;lt;/code&amp;gt; übergeben. Als Rückgabewert &amp;lt;code&amp;gt;$result&amp;lt;/code&amp;gt; wird das Ergebnis des entsprechenden Befehls in Form einer Zeichenkette zurückgegeben. Der Rückgabewert &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; hat hierbei keine besondere Bedeutung und wird behandelt wie eine leere Zeichenkette &amp;lt;code&amp;gt;&amp;quot;&amp;quot;&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Get($$@)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name, $opt, @args ) = @_;&lt;br /&gt;
&lt;br /&gt;
	return &amp;quot;\&amp;quot;get $name\&amp;quot; needs at least one argument&amp;quot; unless(defined($opt));&lt;br /&gt;
&lt;br /&gt;
	if($opt eq &amp;quot;status&amp;quot;) &lt;br /&gt;
	{&lt;br /&gt;
	   ...&lt;br /&gt;
	}&lt;br /&gt;
	elsif($opt eq &amp;quot;power&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
	   ...&lt;br /&gt;
	}&lt;br /&gt;
	...&lt;br /&gt;
	else&lt;br /&gt;
	{&lt;br /&gt;
		return &amp;quot;Unknown argument $opt, choose one of status power [...]&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn eine unbekannte Option an die Get-Funktion übergeben wird, so muss als Rückgabewert der Funktion eine bestimmte Syntax eingehalten werden um FHEM mitzuteilen, welche Optionen für einen Get-Befehl aktuell unterstützt werden. Dies gilt insbesondere für den Aufruf &amp;lt;code&amp;gt;get &amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;&#039;&#039;&amp;lt;NAME&amp;gt;&#039;&#039;&amp;lt;/font&amp;gt; &amp;lt;u&amp;gt;&#039;&#039;&#039;?&#039;&#039;&#039;&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt;, welche durch verschiedene Module (z.B. FHEMWEB) benutzt wird, um eine Liste aller unterstützten Befehle für eine Definition zu ermitteln. Die Rückgabe muss dabei folgender Syntax entsprechen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&#039;&#039;&#039;unknown&#039;&#039;&#039; argument &#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;[Parameter]&amp;lt;/font&amp;gt;&#039;&#039; &#039;&#039;&#039;choose one of&#039;&#039;&#039; &#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;[Liste möglicher Optionen]&amp;lt;/font&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei sind die fett gedruckten Teile der Rückmeldung besonders wichtig. Sind diese nicht vorhanden, können Module wie FHEMWEB nicht die möglichen Get-Kommandos für das entsprechende Gerät ermitteln. Es muss am Anfang der Meldung das Stichwort &amp;quot;unknown&amp;quot; vorkommen gefolgt von einer frei definierbaren Fehlermeldung (i.d.R der übergebene Parameter, welcher ungültig ist). Anschließend folgt &amp;quot;choose one of&amp;quot; mit einer anschließenden Liste möglicher Optionen getrennt durch ein Leerzeichen. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;return &amp;quot;unknown argument $opt choose one of status temperature humidity&amp;quot;;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden als mögliche Optionen für einen Get-Befehl folgende Parameter angegeben:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;temperature&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;humidity&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies würde in folgenden, mögliche Get-Befehle für einen User resultieren:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;get &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; status&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;get &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; temperature&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;get &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; humidity&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im weiteren Verlauf der Get-Funktion könnte man dann mit dem physischen Gerät kommunizieren und den gefragten Wert direkt abfragen und diesen als Return-Wert der Get-Funktion zurückgeben. Vielfach werden aber auch die vorhandenen Readings zurückgegeben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von parseParams()&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in [[#X_Initialize|X_Initialize()]] &amp;lt;code&amp;gt;$hash-&amp;gt;{parseParams} = 1;&amp;lt;/code&amp;gt; gesetzt wurde dann wird [[DevelopmentModuleAPI#parseParams|parseParams()]] automatisch aufgerufen und X_Get() ändert sich wie folgt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Get($$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $a, $h ) = @_;&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die genauen Möglichkeiten von parseParams() sind in dem entsprechenden [[DevelopmentModuleAPI#parseParams|Artikel]] dokumentiert.&lt;br /&gt;
&lt;br /&gt;
==== X_Set ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Set ($$@)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name, $cmd, @args ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	return $error;&lt;br /&gt;
	return ($error, $skip_trigger);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Set-Funktion ist das Gegenteil zur [[#X_Get|Get]]-Funktion. Sie ist dafür gedacht, Daten zum physischen Gerät zu schicken, bzw. entsprechende Aktionen im Gerät selber auszulösen. Ein Set-Befehl dient daher der direkten Steuerung des physikalischen Gerätes in dem es bspw. Zustände verändert (wie &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt;). Der Set-Funktion wird dabei der Definitions-Hash &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;, der Definitionsname &amp;lt;code&amp;gt;$name&amp;lt;/code&amp;gt;, sowie die Aufrufparameter &amp;lt;code&amp;gt;$cmd&amp;lt;/code&amp;gt; und optional weitere Argumente &amp;lt;code&amp;gt;@args&amp;lt;/code&amp;gt; übergeben. Als Rückgabewert &amp;lt;code&amp;gt;$error&amp;lt;/code&amp;gt; kann eine Fehlermeldung in Form Zeichenkette zurückgegeben werden. Der Rückgabewert &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; bedeutet hierbei, dass der Set-Befehl erfolgreich durchgeführt wurde. Eine Set-Funktion gibt daher nur im Fehlerfall eine Rückmeldung mit einer entsprechenden Fehlermeldung. Der Wert &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; wird als &amp;quot;erfolgreich&amp;quot; interpretiert. &lt;br /&gt;
&lt;br /&gt;
Standardmäßig wird jeder Set-Befehl, welcher erfolgreich ausgeführt wurde (&amp;lt;code&amp;gt;$error&amp;lt;/code&amp;gt; ist &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt;), als Event getriggert um dies bspw. in einem FileLog festzuhalten. Dieses Verhalten kann optional unterbunden werden indem der optionale zweite Rückgabewert &amp;lt;code&amp;gt;$skip_trigger&amp;lt;/code&amp;gt; auf &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; gesetzt wird. Damit wird das Generieren eines Events für das erfolgreich ausgeführte Set-Kommando unterbunden. Falls nicht gesetzt, wird ein Event erzeugt (&amp;lt;code&amp;gt;$cmd&amp;lt;/code&amp;gt; mit sämtlichen &amp;lt;code&amp;gt;@args&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
Rückmeldungen (Fehler) von set-Befehlen sämtlicher Module, die im Rahmen der Ausführung eines getriggerten [[Notify]] auftreten, werden im FHEM Logfile festgehalten.&lt;br /&gt;
&lt;br /&gt;
Falls nur interne Daten, die ausschließlich für das Modul relevant sind, gesetzt werden müssen, so sollte statt Set die [[#X_Attr|Attr]]-Funktion verwendet werden. Attribute werden bei Save-Config auch in der Fhem.cfg gesichert. Set-Befehle nicht, da sie nur zu Steuerungszwecken im laufenden Betrieb von FHEM dienen.&lt;br /&gt;
 &lt;br /&gt;
Eine Set-Funktion ist ähnlich aufgebaut wie die Get-Funktion, sie bekommt jedoch in der Regel weitere zusätzliche Parameter (&amp;lt;code&amp;gt;@args&amp;lt;/code&amp;gt;) übergeben um Zustände zu setzen/ändern. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Set($@)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name, $cmd, @args ) = @_;&lt;br /&gt;
&lt;br /&gt;
	return &amp;quot;\&amp;quot;set $name\&amp;quot; needs at least one argument&amp;quot; unless(defined($cmd));&lt;br /&gt;
&lt;br /&gt;
	if($cmd eq &amp;quot;status&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
	   if($args[0] eq &amp;quot;up&amp;quot;)&lt;br /&gt;
	   {&lt;br /&gt;
	      ...&lt;br /&gt;
	   }&lt;br /&gt;
	   elsif($args[0] eq &amp;quot;down&amp;quot;)&lt;br /&gt;
	   {&lt;br /&gt;
	      ...&lt;br /&gt;
	   }&lt;br /&gt;
	   else&lt;br /&gt;
	   {&lt;br /&gt;
	      return &amp;quot;Unknown value $args[0] for $cmd, choose one of status power&amp;quot;;&lt;br /&gt;
	   }   &lt;br /&gt;
	}&lt;br /&gt;
	elsif($cmd eq &amp;quot;power&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
	   if($args[0] eq &amp;quot;on&amp;quot;)&lt;br /&gt;
	   {&lt;br /&gt;
	      ...&lt;br /&gt;
	   }&lt;br /&gt;
	   elsif($args[0] eq &amp;quot;off&amp;quot;)&lt;br /&gt;
	   {&lt;br /&gt;
	      ...&lt;br /&gt;
	   }  &lt;br /&gt;
	   else&lt;br /&gt;
	   {&lt;br /&gt;
	      return &amp;quot;Unknown value $args[0] for $cmd, choose one of status power&amp;quot;;&lt;br /&gt;
	   }       &lt;br /&gt;
	}&lt;br /&gt;
	...&lt;br /&gt;
	else&lt;br /&gt;
	{&lt;br /&gt;
		return &amp;quot;Unknown argument $cmd, choose one of status power&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn eine unbekannte Option an die Set-Funktion übergeben wird, so muss als Rückgabewert der Funktion eine bestimmte Syntax eingehalten werden um FHEM mitzuteilen, welche Optionen für einen Set-Befehl aktuell unterstützt werden. Dies gilt insbesondere für den Aufruf &amp;lt;code&amp;gt;set &amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;&#039;&#039;&amp;lt;NAME&amp;gt;&#039;&#039;&amp;lt;/font&amp;gt; &amp;lt;u&amp;gt;&#039;&#039;&#039;?&#039;&#039;&#039;&amp;lt;/u&amp;gt;&amp;lt;/code&amp;gt;, welcher durch verschiedene Module (z.B. FHEMWEB) benutzt wird, um eine Liste aller unterstützten Befehle für eine Definition zu ermitteln. Die Rückgabe muss dabei folgender Syntax entsprechen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&#039;&#039;&#039;unknown&#039;&#039;&#039; argument &#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;[Parameter]&amp;lt;/font&amp;gt;&#039;&#039; &#039;&#039;&#039;choose one of&#039;&#039;&#039; &#039;&#039;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;[Liste möglicher Optionen]&amp;lt;/font&amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei sind die fett gedruckten Teile der Rückmeldung besonders wichtig. Sind diese nicht vorhanden, können Module wie FHEMWEB nicht die möglichen Set-Kommandos für das entsprechende Gerät ermitteln. Es muss am Anfang der Meldung das Stichwort &amp;quot;unknown&amp;quot; vorkommen gefolgt von einer frei definierbaren Fehlermeldung (i.d.R der übergebene Parameter, welcher ungültig ist). Anschließend folgt &amp;quot;choose one of&amp;quot; mit einer anschließenden Liste möglicher Optionen getrennt durch ein Leerzeichen. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;return &amp;quot;unknown argument $cmd choose one of status power&amp;quot;;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hier werden als mögliche Optionen für einen Set-Befehl folgende Parameter angegeben:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;power&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies würde in folgenden, mögliche Set-Befehle für einen User resultieren:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;set &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; status&amp;lt;/code&amp;gt;&lt;br /&gt;
* &amp;lt;code&amp;gt;set &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; power&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von SetExtensions.pm&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn man dem Nutzer zusätzlich zu den Set-Befehlen &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; auch weiterführende Befehle wie &amp;lt;code&amp;gt;on-for-timer&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;on-till&amp;lt;/code&amp;gt;, usw. anbieten möchte, obwohl die zu steuernde Hardware solche Kommandos nicht unterstützt, kann man dies über das Hilfsmodul SetExtensions.pm realisieren.&lt;br /&gt;
&lt;br /&gt;
Das Hilfsmodul SetExtensions.pm bietet weiterführende Set-Kommandos basierend auf den Befehlen &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; an. Dabei werden durch interne Timer bzw. eigens angelegten [[at]]-Definitionen diese Befehle durch FHEM selber umgesetzt. Je nach ausgeführtem Befehl wird der &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;- bzw. &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt;-Befehl dann durch FHEM zum richtigen Zeitpunkt ausgeführt. Vorausgesetzt das Modul unterstützt in der Set-Funktion die Befehle &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt;, so werden durch den Einsatz von SetExtensions.pm folgende Befehle zusätzlich unterstützt:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Set-Kommando !! Beispiel !! Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-for-timer &#039;&#039;&amp;amp;lt;Dauer&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-for-timer 120&amp;lt;/code&amp;gt; || Schaltet das Gerät sofort mit dem &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;-Befehl ein und nach der angegebenen Dauer in Sekunden via &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; wieder aus.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-for-timer &#039;&#039;&amp;amp;lt;Dauer&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-for-timer 120&amp;lt;/code&amp;gt; || Schaltet das Gerät sofort mit dem &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt;-Befehl aus und nach der angegebenen Dauer in Sekunden via &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; wieder ein.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-till &#039;&#039;&amp;amp;lt;Zeitpunkt&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-till 16:30&amp;lt;/code&amp;gt; || Schaltet das Gerät sofort mit dem &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt;-Befehl ein und zum angegebenen Zeitpunkt via &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; wieder aus.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-till &#039;&#039;&amp;amp;lt;Zeitpunkt&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-till 16:30&amp;lt;/code&amp;gt; || Schaltet das Gerät sofort mit dem &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt;-Befehl aus und zum angegebenen Zeitpunkt via &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; wieder ein.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-till-overnight &#039;&#039;&amp;amp;lt;Zeitpunkt&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;on-till-overnight 01:00&amp;lt;/code&amp;gt; || Ähnlich wie &amp;lt;code&amp;gt;on-till&amp;lt;/code&amp;gt;. Der übergebene Zeitpunkt wird aber nicht geprüft, ob er für den heutigen Tag bereits überschritten wurde. Dadurch kann man Abends einen Zeitpunkt setzen, der erst am nächsten Tag zutrifft.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-till-overnight &#039;&#039;&amp;amp;lt;Zeitpunkt&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;off-till-overnight 01:00&amp;lt;/code&amp;gt; || Ähnlich wie &amp;lt;code&amp;gt;off-till&amp;lt;/code&amp;gt;. Der übergebene Zeitpunkt wird aber nicht geprüft, ob er für den heutigen Tag bereits überschritten wurde. Dadurch kann man Abends einen Zeitpunkt setzen, der erst am nächsten Tag zutrifft.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;blink &#039;&#039;&amp;amp;lt;Anzahl&amp;amp;gt; &amp;amp;lt;Interval&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt;  || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;blink 3 1&amp;lt;/code&amp;gt; || Schaltet das Gerät via &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; für &amp;lt;code&amp;gt;&#039;&#039;&amp;amp;lt;Interval&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; Sekunden ein und anschließend via &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; wieder aus. Nach &amp;lt;code&amp;gt;&#039;&#039;&amp;amp;lt;Interval&amp;amp;gt;&#039;&#039;&amp;lt;/code&amp;gt; Sekunden wird das ganze wiederholt, solange bis die angegebene Anzahl erreicht ist.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;intervals &#039;&#039;&amp;amp;lt;Start&amp;amp;gt;-&amp;amp;lt;Ende&amp;amp;gt;&#039;&#039; &#039;&#039;&amp;amp;lt;Start&amp;amp;gt;-&amp;amp;lt;Ende&amp;amp;gt;&#039;&#039; ...&amp;lt;/code&amp;gt; || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;intervals 07:00-08:00 16:30-18:00&amp;lt;/code&amp;gt; || Schaltet das Gerät innerhalb der übergebenen Zeiträumen via &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; ein. Sobald die aktuelle Zeit ausserhalb dieser Zeiträume liegt, wird das Gerät via &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; wieder ausgeschaltet. Es können dabei beliebig viele Zeiträume angegeben werden.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;toggle&amp;lt;/code&amp;gt; || style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;toggle&amp;lt;/code&amp;gt;  || Sofern der aktuelle Status &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; ist, wird das Gerät via &amp;lt;code&amp;gt;off&amp;lt;/code&amp;gt; ausgeschaltet. Andernfalls wird es via &amp;lt;code&amp;gt;on&amp;lt;/code&amp;gt; eingeschaltet.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Eine kurze Beschreibung zu den möglichen Befehlen durch SetExtensions.pm gibt es auch in der commandref zum {{Link2CmdRef|Anker=set|Label=set-Befehl}}.&lt;br /&gt;
&lt;br /&gt;
Um SetExtensions.pm in der Set-Funktion nutzen zu können müssen folgende Aktionen durchgeführt werden:&lt;br /&gt;
&lt;br /&gt;
# Laden von SetExtensions.pm via &amp;lt;code&amp;gt;use SetExtensions;&amp;lt;/code&amp;gt; am Anfang des Moduls&lt;br /&gt;
# Aufruf und Rückgabe der Funktion [[DevelopmentModuleAPI#SetExtensions|SetExtensions()]] sofern die Set-Funktion mit dem übergebenen Befehl nichts anfangen kann.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
use SetExtensions;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
sub X_Set($@)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $name, $cmd, @args ) = @_;&lt;br /&gt;
	my $cmdList = &amp;quot;on off&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	return &amp;quot;\&amp;quot;set $name\&amp;quot; needs at least one argument&amp;quot; unless(defined($cmd));&lt;br /&gt;
&lt;br /&gt;
	if($cmd eq &amp;quot;on&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
		# Gerät einschalten...&lt;br /&gt;
	}&lt;br /&gt;
	elsif($cmd eq &amp;quot;off&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
		# Gerät ausschalten...&lt;br /&gt;
	}&lt;br /&gt;
	...&lt;br /&gt;
	else # wenn der übergebene Befehl nicht durch X_Set() verarbeitet werden kann, Weitergabe an SetExtensions()&lt;br /&gt;
	{&lt;br /&gt;
		return SetExtensions($hash, $cmdList, $name, $cmd, @args);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollte der übergebene Set-Befehl auch für SetExtensions unbekannt sein (bspw. &amp;lt;code&amp;gt;set &#039;&#039;&amp;amp;lt;Name&amp;amp;gt;&#039;&#039; ?&amp;lt;/code&amp;gt;), so generiert SetExtensions() eine entsprechende Usage-Meldung, welche innerhalb der Set-Funktion an FHEM zurückgegeben werden muss.&lt;br /&gt;
&lt;br /&gt;
Eine ausführliche Beschreibung zu der Funktion SetExtensions() gibt es in der  [[DevelopmentModuleAPI#SetExtensions|API-Referenz]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von parseParams()&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn in [[#X_Initialize|X_Initialize()]] &amp;lt;code&amp;gt;$hash-&amp;gt;{parseParams} = 1;&amp;lt;/code&amp;gt; gesetzt wurde dann wird [[DevelopmentModuleAPI#parseParams|parseParams()]] automatisch aufgerufen und X_Set() ändert sich wie folgt:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Set($$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $a, $h ) = @_;&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die genauen Möglichkeiten von parseParams() sind in dem entsprechenden [[DevelopmentModuleAPI#parseParams|Artikel]] dokumentiert.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Nutzung von FHEMWEB-Widgets&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das GUI-Modul [[FHEMWEB]] kann für die einzelnen Set-Optionen, die das Modul versteht, automatisch Eingabehilfen wie Drop-Down Boxen oder Slider erzeugen. In der Detailansicht der GUI kann der Anwender dann die jeweiligen Werte komfortabel auswählen. Dafür muss die Set-Funktion, wenn sie mit der Option &amp;lt;code&amp;gt;?&amp;lt;/code&amp;gt; aufgerufen wird, nicht nur einen Text mit  &amp;lt;code&amp;gt;&amp;quot;Unknown ... choose one of ...&amp;quot;&amp;lt;/code&amp;gt; zurückgeben sondern den einzelnen Set-Optionen in diesem Rückgabetext nach einem Doppelpunkt entsprechende Zusatzinformationen anhängen.&lt;br /&gt;
Meist prüft man in den Modulen gar nicht auf die Option &amp;lt;code&amp;gt;?&amp;lt;/code&amp;gt; sondern gibt generell bei unbekannten Optionen diesen Text zurück. Das Modul FHEMWEB ermittelt die Syntax eines Gerätes jedoch immer mit dem Befehl:&lt;br /&gt;
 set &#039;&#039;&amp;amp;lt;NAME&amp;amp;gt;&#039;&#039; ?&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
	return &amp;quot;Unknown argument $cmd, choose one of status:up,down power:on,off on:noArg off:noArg&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mit Kommata getrennte Werte ergeben eine Drop-Down Liste, mit der der User die Werte auswählen kann&lt;br /&gt;
&amp;lt;pre&amp;gt;timer:30,120,300&lt;br /&gt;
mode:verbose,ultra,relaxed&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wird kein Doppelpunkt zum Kommando angegeben, so wird eine Eingabezeile angezeigt, die die freie Eingabe eines Wertes erlaubt.&lt;br /&gt;
&lt;br /&gt;
Man kann jedoch die Eingabe-/Auswahlmöglichkeiten durch Widgets vereinfachen. Dazu gibt man hinter dem Doppelpunkt einen Widgetnamen und widgetspezifische Parameter an. Es existieren mehrere solcher Widgets in FHEMWEB. Die gebräuchlichsten sind:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Zusatz !! Beispiel !! Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;noArg&#039;&#039;&#039; || &amp;lt;code&amp;gt;reset:noArg&amp;lt;/code&amp;gt;|| Es werden keine weiteren Argumente mehr benötigt. In so einem Fall wird bei der Auswahl keine Textbox oder ähnliches angezeigt, da keine weiteren Argumente für diesen Befehl notwendig sind.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;slider&#039;&#039;&#039;,&amp;lt;min&amp;gt;,&amp;lt;step&amp;gt;,&amp;lt;max&amp;gt; || &amp;lt;code&amp;gt;dim:slider,0,1,100&amp;lt;/code&amp;gt;|| Es wird ein Schieberegler angezeigt um den Parameter auszuwählen. Dabei werden als Zusatzparameter Minimum, Schrittweite und Maximum angegeben.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;colorpicker&#039;&#039;&#039; || &amp;lt;code&amp;gt;rgb:colorpicker,RGB&amp;lt;/code&amp;gt;|| Es wird ein Colorpicker angezeigt, der dem Anwender die Auswahl einer Farbe ermöglicht. Die genaue Parametersyntax kann man dem Artikel zum  [[Color#Colorpicker|Colorpicker]] entnehmen.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;multiple&#039;&#039;&#039; || &amp;lt;code&amp;gt;group:multiple,Telefon,Multimedia,Licht,Heizung&amp;lt;/code&amp;gt; || Es erscheint ein Auswahldialog, wo man verschiedene Werte durch klicken auswählen kann. Optional kann man in einem Freitext eigene Werte ergänzen. dieser Dialog wird bspw. bei der Raum-Auswahl (Attribut &amp;quot;room&amp;quot;) oder der Gruppen-Auswahl (Attribut &amp;quot;group&amp;quot;) in FHEMWEB genutzt. &lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;sortable&#039;&#039;&#039; || &amp;lt;code&amp;gt;command:sortable,monday,tuesday,...&amp;lt;/code&amp;gt; || Es erscheint ein Auswahldialog, wo man verschiedene Werte auswählen und sortieren kann. Man kann dabei Werte durch Klicken auswählen und durch Drag&#039;n&#039;Drop sortieren.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Es gibt noch weitere solcher Widgets. Eine genaue Auflistung dazu findet sich in der {{Link2CmdRef|Anker=widgetOverride}} unter widgetOverride zu FHEMWEB.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Hinweise&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Damit in einer Eingabe bereits der aktuelle Wert vorbelegt bzw. in einer Auswahlliste der aktuelle Wert vorselektiert ist, muss es im Modul bzw. Gerät ein Reading mit dem gleichen Namen wie die Set-Option geben. Der Wert des gleichnamigen Readings wird dann als Vorbelegung / Vorselektion verwendet. &lt;br /&gt;
* Der User kann sich in der Raumübersicht nach wie vor via [[WebCmd|webCmd]] eine entsprechende Steuerung anlegen.&lt;br /&gt;
&lt;br /&gt;
==== X_Attr ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Attr($$$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $cmd, $name, $attrName, $attrValue  ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Attr-Funktion dient der Prüfung von Attributen, welche über den &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt;-Befehl gesetzt werden können. Sobald versucht wird, ein Attribut für ein Gerät zu setzen, wird vorher die Attr-Funktion des entsprechenden Moduls aufgerufen um zu prüfen, ob das Attribut aus Sicht des Moduls korrekt ist.&lt;br /&gt;
Liegt ein Problem mit dem Attribut bzw. dem Wert vor, so muss die Funktion eine aussagekräftige Fehlermeldung zurückgeben, welche dem User angezeigt wird.&lt;br /&gt;
Sofern das übergebene Attribut samt Inhalt korrekt ist, gibt die Attr-Funktion den Wert &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurück. Erst dann wird das Attribut in der globalen Datenstruktur &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt; gespeichert und ist somit erst aktiv.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Attr($$$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $cmd, $name, $attrName, $attrValue ) = @_;&lt;br /&gt;
    &lt;br /&gt;
  	# $cmd  - Vorgangsart - kann die Werte &amp;quot;del&amp;quot; (löschen) oder &amp;quot;set&amp;quot; (setzen) annehmen&lt;br /&gt;
	# $name - Gerätename&lt;br /&gt;
	# $attrName/$attrValue sind Attribut-Name und Attribut-Wert&lt;br /&gt;
    &lt;br /&gt;
	if ($cmd eq &amp;quot;set&amp;quot;) {&lt;br /&gt;
		if ($aName eq &amp;quot;Regex&amp;quot;) {&lt;br /&gt;
			eval { qr/$aVal/ };&lt;br /&gt;
			if ($@) {&lt;br /&gt;
				Log3 $name, 3, &amp;quot;X ($name) - Invalid regex in attr $name $aName $aVal: $@&amp;quot;;&lt;br /&gt;
				return &amp;quot;Invalid Regex $aVal: $@&amp;quot;;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	return undef;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zusätzlich ist es möglich auch übergebene Attributwerte zu verändern bzw. zu korrigieren, indem man im Parameterarray &amp;lt;code&amp;gt;@_&amp;lt;/code&amp;gt; den ursprünglichen Wert anpasst. Dies erfolgt im Beispiel über die Modifikation des Wertes mit Index 3 (entspricht dem 4. Element) im Parameterarray, also &amp;lt;code&amp;gt;$_[3]&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Da das Attribut zum Zeitpunkt des Aufrufs der Attr-Funktion noch nicht gespeichert ist, wird der neue Wert zu diesem Zeitpunkt noch nicht via [[DevelopmentModuleAPI#AttrVal|AttrVal()]] zurückgegeben. Erst, wenn die Attr-Funktion mit &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; beendet ist, wird der neue Wert in FHEM gespeichert und steht dann via AttrVal() zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Die Attr-Funktion bekommt nicht den Hash der Geräteinstanz übergeben, da sie normalerweise keine Werte dort speichern muss, sondern lediglich das Attribut auf Korrektheit prüfen muss.&lt;br /&gt;
Im obigen Beispiel wird für ein Attribut mit Namen &amp;quot;Regex&amp;quot; geprüft ob der reguläre Ausdruck fehlerhaft ist. Sofern dieser OK ist, wird &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurückgegeben und fhem.pl speichert den Wert des Attributs in &amp;lt;code&amp;gt;%attr&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Attributnamen mit Platzhaltern&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Falls man Attribute in der [[#X_Initialize|Initialize]]-Funktion mit Platzhaltern definiert (Wildcard-Attribute) wie z.B.:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
    $hash-&amp;gt;{AttrList} =&lt;br /&gt;
      &amp;quot;reading[0-9]*Name &amp;quot; .&lt;br /&gt;
    # usw.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
dann können Anwender Attribute wie reading01Name, reading02Name etc. setzen. Leider funktioniert das bisher nicht durch Klicken in der Web-Oberfläche, da FHEMWEB nicht alle denkbaren Ausprägungen in einem Dropdown anbieten kann. Der Benutzer muss solche Attribute manuell über den &amp;lt;code&amp;gt;attr&amp;lt;/code&amp;gt;-Befehl eingeben.&lt;br /&gt;
&lt;br /&gt;
Man kann jedoch in der Attr-Funktion neu gesetzte Ausprägungen von Wildcard-Attributen an die gerätespezifische userattr-Variable anfügen. Dann können bereits gesetzte Attribute in FHEMWEB durch Klicken ausgewählt und geändert werden.&lt;br /&gt;
Dazu reicht ein Aufruf der Funktion [[DevelopmentModuleAPI#addToDevAttrList|addToDevAttrList()]]: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
    addToDevAttrList($name, $aName);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Read ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Read ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Die X_Read-Funktion wird aufgerufen, wenn ein dem Gerät zugeordneter Filedeskriptor (serielle Schnittstelle, TCP-Verbindung, ...) Daten zum Lesen bereitgestellt hat. Die Daten müssen nun eingelesen und interpretiert werden.&lt;br /&gt;
&lt;br /&gt;
Im folgenden Beispiel wird über eine serielle Schnittstelle (beziehungsweise über einen USB-To-Serial-Konverter) von einem angeschlossenen Gerät gelesen. Dazu werden die bisher verfügbaren Daten mit der Funktion [[DevIo#DevIo_SimpleRead()|DevIo_SimpleRead()]] gelesen. Da die Übertragung möglicherweise noch nicht vollständig ist, kann es sein, dass kurz darauf die X_Read-Funktion wieder aufgerufen wird und ein weiterer Teil oder der Rest der Daten gelesen werden kann.&lt;br /&gt;
Die Funktion muss daher prüfen ob schon alle erwarteten Daten angekommen sind und gegebenenfalls die bisher gelesenen Daten in einem eigenen Puffer (idealerweise in &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;) zwischenspeichern (siehe auch [[DevIo#Hinweis bei der Datenverarbeitung (Buffering)|DevIo]]). Im Beispiel ist dies &amp;lt;code&amp;gt;$hash-&amp;gt;{helper}{BUFFER}&amp;lt;/code&amp;gt; an den die aktuell gelesenen Daten angehängt werden, bis die folgende Prüfung ein für das jeweilige Protokoll vollständige Frame erkennt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Read($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
	my $name = $hash-&amp;gt;{NAME};&lt;br /&gt;
	&lt;br /&gt;
	# einlesen der bereitstehenden Daten&lt;br /&gt;
	my $buf = DevIo_SimpleRead($hash);		&lt;br /&gt;
	return &amp;quot;&amp;quot; if ( !defined($buf) );&lt;br /&gt;
	Log3 $name, 5, &amp;quot;X ($name) - received data: &amp;quot;.$buf;    &lt;br /&gt;
&lt;br /&gt;
	# Daten in Hex konvertieren und an den Puffer anhängen&lt;br /&gt;
	$hash-&amp;gt;{helper}{BUFFER} .= unpack (&#039;H*&#039;, $buf);	&lt;br /&gt;
	Log3 $name, 5, &amp;quot;X ($name) - current buffer content: &amp;quot;.$hash-&amp;gt;{helper}{BUFFER};&lt;br /&gt;
&lt;br /&gt;
	# prüfen, ob im Buffer ein vollständiger Frame zur Verarbeitung vorhanden ist.&lt;br /&gt;
	if ($hash-&amp;gt;{helper}{BUFFER} =~ &amp;quot;ff1002(.{4})(.*)1003(.{4})ff(.*)&amp;quot;) {&lt;br /&gt;
	...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die zu lesenden Nutzdaten können dann je nach Protokoll des Geräts beispielsweise an einer festgelegten Stelle im Frame (dann in &amp;lt;code&amp;gt;$hash-&amp;gt;{helper}{BUFFER}&amp;lt;/code&amp;gt;) stehen oder aus dem Kontext mit einem Regex-Match extrahiert werden und via [[DevelopmentModuleAPI#Readings_.2F_Events|Reading-Funktionen]] in Readings gespeichert werden (siehe unten).&lt;br /&gt;
&lt;br /&gt;
Der Rückgabewert der Read-Funktion wird nicht geprüft und hat daher keinerlei Bedeutung.&lt;br /&gt;
&lt;br /&gt;
==== X_Ready ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Ready ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
    &lt;br /&gt;
	return $success;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wird im Main-Loop aufgerufen falls das Modul in der globalen Liste &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt; existiert. Diese Funktion hat, je nachdem auf welchem OS FHEM ausgeführt wird, unterschiedliche Aufgaben:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;UNIX-artiges Betriebssystem:&#039;&#039;&#039; prüfen, ob eine Verbindung nach einem Verbindungsabbruch wieder aufgebaut werden kann. Sobald der Verbindungsaufbau erfolgreich war, muss die Funktion einen erfolgreichen Wahrheitswert zurückliefern (z.B. &amp;quot;1&amp;quot;) und den eigenen Eintrag entsprechend aus &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt; löschen.&lt;br /&gt;
* &#039;&#039;&#039;Windows-Betriebssystem:&#039;&#039;&#039; prüfen, ob lesbare Daten für ein serielles Device (via COM1, COM2, ...) vorliegen. Sofern lesbare Daten vorliegen, muss Funktion einen erfolgreichen Wahrheitswert zurückliefern (z.B. &amp;quot;1&amp;quot;). Zusätzlich dazu muss die Funktion, wie bei UNIX-artigen Betriebssystem, ebenfalls bei einem Verbindungsabbruch einen neuen Verbindungsversuch initiieren. Der Eintrag in &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt; bleibt solange erhalten, bis die Verbindung seitens FHEM beendet wird.&lt;br /&gt;
&lt;br /&gt;
Der Windows-spezifische Teil zur Datenprüfung ist dabei nur zu implementieren, wenn das Modul über eine serielle Verbindung kommuniziert.&lt;br /&gt;
&lt;br /&gt;
Bei der Nutzung des Moduls [[DevIo]] wird dem Modulentwickler der Umgang mit &amp;lt;code&amp;gt;%readyfnlist&amp;lt;/code&amp;gt; abgenommen, da DevIo sich selbst um die entsprechenden Einträge kümmert und diese selbstständig wieder entfernt.&lt;br /&gt;
&lt;br /&gt;
In der Regel sieht eine Ready-Funktion immer gleich aus.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Ready($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
      &lt;br /&gt;
	# Versuch eines Verbindungsaufbaus, sofern die Verbindung beendet ist.&lt;br /&gt;
	return DevIo_OpenDev($hash, 1, undef ) if ( $hash-&amp;gt;{STATE} eq &amp;quot;disconnected&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
	# This is relevant for Windows/USB only&lt;br /&gt;
	if(defined($hash-&amp;gt;{USBDev})) {&lt;br /&gt;
		my $po = $hash-&amp;gt;{USBDev};&lt;br /&gt;
		my ( $BlockingFlags, $InBytes, $OutBytes, $ErrorFlags ) = $po-&amp;gt;status;&lt;br /&gt;
		return ( $InBytes &amp;gt; 0 );&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Notify ====&lt;br /&gt;
&lt;br /&gt;
Die X_Notify-Funktion wird aus der Funktion [[DevelopmentModuleAPI#DoTrigger|DoTrigger()]] in fhem.pl heraus aufgerufen sobald ein Modul Events erzeugt hat. Damit kann ein Modul auf Events anderer Module reagieren. Typische Beispiele sind dabei das [[FileLog]]-Modul oder das [[notify]]-Modul.&lt;br /&gt;
&lt;br /&gt;
Die Notify-Funktion bekommt dafür zwei Hash-Referenzen übergeben: den Hash des eigenen Geräts und den Hash des Geräts, das die Events erzeugt hat. &lt;br /&gt;
Über den Hash des eigenen Geräts kann die Notify-Funktion beispielsweise auf die Internals oder Attribute des eigenen Geräts zugreifen.&lt;br /&gt;
Über den Hash des Gerätes und der [[DevelopmentModuleAPI#deviceEvents|deviceEvents()]]-Funktion kann man auf die generierten Events zugreifen. Über den zweiten Parameter dieser Routine lässt sich bestimmen ob für das Reading &amp;lt;code&amp;gt;state&amp;lt;/code&amp;gt; ein &#039;normales&#039; Event (d.h. in der form &amp;lt;code&amp;gt;state: &amp;lt;wert&amp;gt;&amp;lt;/code&amp;gt;) erzeugen soll (Wert: 1) oder ob z.b. aus Gründen der Rückwärtskompatibilität ein Event ohne &amp;lt;code&amp;gt;state: &amp;lt;/code&amp;gt; erzeugt werden soll. Falls dem Anwender die Wahl des verwendeten Formats überlassen werden soll ist hierzu das {{Link2CmdRef|Anker=addStateEvent|Lang=de|Label=addStateEvent-Attribut}} vorzusehen.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff auf &amp;lt;code&amp;gt;$hash-&amp;gt;{CHANGED}&amp;lt;/code&amp;gt; ist nicht mehr zu empfehlen.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Notify($$)&lt;br /&gt;
{&lt;br /&gt;
  my ($own_hash, $dev_hash) = @_;&lt;br /&gt;
  my $ownName = $own_hash-&amp;gt;{NAME}; # own name / hash&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot; if(IsDisabled($ownName)); # Return without any further action if the module is disabled&lt;br /&gt;
&lt;br /&gt;
  my $devName = $dev_hash-&amp;gt;{NAME}; # Device that created the events&lt;br /&gt;
&lt;br /&gt;
  my $events = deviceEvents($dev_hash,1);&lt;br /&gt;
  return if( !$events );&lt;br /&gt;
&lt;br /&gt;
  foreach my $event (@{$events}) {&lt;br /&gt;
    $event = &amp;quot;&amp;quot; if(!defined($event));&lt;br /&gt;
&lt;br /&gt;
    # Examples:&lt;br /&gt;
    # $event = &amp;quot;readingname: value&amp;quot; &lt;br /&gt;
    # or&lt;br /&gt;
    # $event = &amp;quot;INITIALIZED&amp;quot; (for $devName equal &amp;quot;global&amp;quot;)&lt;br /&gt;
    #&lt;br /&gt;
    # processing $event with further code&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Begrenzung der Aufrufe auf bestimmte Geräte&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da die Notify-Funktion für jedes definierte Gerät mit all seinen Events aufgerufen wird, muss sie in einer Schleife jedesmal prüfen und entscheiden, ob es mit dem jeweiligen Event etwas anfangen kann. Ein Gerät, das die Notify-Funktion implementiert, sieht dafür typischerweise einen regulären Ausdruck vor, welcher für die Filterung verwendet wird.&lt;br /&gt;
&lt;br /&gt;
Wenn man nur gezielt von bestimmten Definitionen Events erhalten will, kann man diese auch in Form einer {{Link2CmdRef|Lang=de|Anker=devspec|Label=devspec}} in &amp;lt;code&amp;gt;$hash-&amp;gt;{NOTIFYDEV}&amp;lt;/code&amp;gt; angeben. Bspw. kann man in der Define-Funktion diesen Wert setzen. Dadurch wird die Notify-Funktion nur aufgerufen wenn eine der Definitionen, auf welche die devspec passt, ein Event erzeugt hat. Ein typischer Fall ist die Begrenzung von Events auf &amp;quot;global&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
in der Define-Funktion:&lt;br /&gt;
&lt;br /&gt;
$hash-&amp;gt;{NOTIFYDEV} = &amp;quot;global&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{NOTIFYDEV} = &amp;quot;global,Definition_.*&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{NOTIFYDEV} = &amp;quot;global,Definition_A,Definition_B&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{NOTIFYDEV} = &amp;quot;global,TYPE=CUL_HM&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies schont insbesondere bei grossen Installationen Ressourcen, da die Notify-Funktion nicht sämtliche Events, sondern nur noch Events der gewünschten Definitionen erhält. Dadurch erfolgen deutlich weniger Aufrufe der Notify-Funktion, was Systemressourcen schont.&lt;br /&gt;
&lt;br /&gt;
Sofern in der [[#X_Define|Define-Funktion]] eine Regexp als Argument übergeben wird, die ähnlich wie beim Modul [[notify]] auf Events wie &amp;lt;code&amp;gt;&amp;amp;lt;Definitionsname&amp;amp;gt;&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;&amp;amp;lt;Definitionsname&amp;amp;gt;:&amp;amp;lt;Event&amp;amp;gt;&amp;lt;/code&amp;gt; reagiert, so sollte man in der Define-Funktion die Funktion [[DevelopmentModuleAPI#notifyRegexpChanged|notifyRegexpChanged()]] verwenden. Diese versucht einen passenden Eintrag für &amp;lt;code&amp;gt;$hash-&amp;gt;{NOTIFYDEV}&amp;lt;/code&amp;gt; basierend auf der übergebenen Regexp zu setzen, sofern dies möglich ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;Reihenfolge für den Aufruf der Notify-Funktion beeinflussen&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sobald ein Event ausgelöst wurde, stellt sich FHEM eine Liste aller relevanten Geräte-Hashes zusammen, welche via Notify-Funktion prüfen müssen, ob das Event relevant ist. Dabei wird die Liste nach &amp;lt;code&amp;gt;$hash-&amp;gt;{NTFY_ORDER}&amp;lt;/code&amp;gt; sortiert. Diese enthält ein Order-Präfix in Form einer Ganzzahl, sowie den Namen der Definition (Bsp: &amp;lt;code&amp;gt;&#039;&#039;&#039;50&#039;&#039;&#039;-Lampe_Wohnzimmer&amp;lt;/code&amp;gt;). Dadurch kann man jedoch nicht sicherstellen, dass Events von bestimmten Modulen zuerst verarbeitet werden.&lt;br /&gt;
&lt;br /&gt;
Wenn das eigene Modul bei der Eventverarbeitung gegenüber den anderen Modulen eine bestimmte Reihenfolge einhalten muss, kann man in der [[#X_Initialize|Initialize]]-Funktion durch Setzen von &amp;lt;code&amp;gt;$hash-&amp;gt;{NotifyOrderPrefix}&amp;lt;/code&amp;gt; diese Reihenfolge beeinflussen. Standardmäßig werden Module immer mit einem Order-Präfix von &amp;quot;50-&amp;quot; in FHEM registriert. Durch die Veränderung dieses Präfixes kann man das eigene Modul in der Reihenfolge gegenüber anderen Modulen bei der Eventverarbeitung beeinflussen. &lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	$hash-&amp;gt;{NotifyOrderPrefix} = &amp;quot;45-&amp;quot;  # Alle Definitionen des Moduls X werden bei der Eventverarbeitung zuerst geprüft&lt;br /&gt;
	&lt;br /&gt;
	# oder...&lt;br /&gt;
	&lt;br /&gt;
	$hash-&amp;gt;{NotifyOrderPrefix} = &amp;quot;55-&amp;quot;  # Alle Definitionen des Moduls X werden bei der Eventverarbeitung als letztes geprüft&lt;br /&gt;
	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Da dieses Präfix bei eventverarbeitenden Definitionen in &amp;lt;code&amp;gt;$hash-&amp;gt;{NTFY_ORDER}&amp;lt;/code&amp;gt; dem Definitionsnamen vorangestellt wird bewirkt es bei einer normalen aufsteigenden Sortierung nach &amp;lt;code&amp;gt;$hash-&amp;gt;{NTFY_ORDER}&amp;lt;/code&amp;gt; eine veränderte Reihenfolge. Alle Module die in der Initialize-Funktion nicht &amp;lt;code&amp;gt;$hash-&amp;gt;{NotifyOrderPrefix}&amp;lt;/code&amp;gt; explizit setzen, werden mit &amp;quot;50-&amp;quot; als Standardwert vorbelegt.&lt;br /&gt;
&lt;br /&gt;
==== X_Rename ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Rename($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $new_name, $old_name) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Rename-Funktion wird ausgeführt, nachdem ein Gerät umbenannt wurde. Auf diese Weise kann ein Modul auf eine Namensänderung reagieren, wenn das Gerät &amp;lt;code&amp;gt;$old_name&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;$new_name&amp;lt;/code&amp;gt; umbenannt wurde. Ein typischer Fall ist das Umsetzen der Namensänderungen bei Daten die mittels [[DevelopmentModuleAPI#setKeyValue|setKeyValue()]] gespeichert wurden. Hierbei müssen die Daten, welche unter dem alten Namen gespeichert sind, auf den neuen Namen geändert werden.&lt;br /&gt;
&lt;br /&gt;
Der Rename-Funktion wird lediglich der alte, sowie der neue Gerätename übergeben. Der Rückgabewert wird nicht ausgewertet.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Rename($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $new_name, $old_name ) = @_;&lt;br /&gt;
&lt;br /&gt;
	my $old_index = &amp;quot;Module_X_&amp;quot;.$old_name.&amp;quot;_data&amp;quot;;&lt;br /&gt;
	my $new_index = &amp;quot;Module_X_&amp;quot;.$new_name.&amp;quot;_data&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	my ($err, $data) = getKeyValue($old_index);&lt;br /&gt;
	return undef unless(defined($old_pwd));&lt;br /&gt;
&lt;br /&gt;
	setKeyValue($new_index, $data);&lt;br /&gt;
	setKeyValue($old_index, undef);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_DelayedShutdown ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_DelayedShutdown($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	return $delay_needed;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Mit der X_DelayedShutdown Funktion kann eine Definition das Stoppen von FHEM verzögern um asynchron hinter sich aufzuräumen. Dies kann z.B. der ordnungsgemäße Verbindungsabbau mit dem physikalischen Gerät sein (z.B. Session beenden, Logout, etc.), welcher mehrfache Requests/Responses benötigt. Als Übergabeparameter wird der Geräte-Hash &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; bereitgestellt. Je nach Rückgabewert &amp;lt;code&amp;gt;$delay_needed&amp;lt;/code&amp;gt; wird der Stopp von FHEM verzögert. Ist ein verzögerter Stopp von FHEM notwendig, darf der Rückgabewert in diesem Fall nicht &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; oder &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; sein.&lt;br /&gt;
&lt;br /&gt;
Im Unterschied zur [[#X_Shutdown|Shutdown]]-Funktion steht vor einem bevorstehenden Stopp von FHEM für einen User-konfigurierbaren Zeitraum (global-Attribut: &amp;lt;code&amp;gt;maxShutdownDelay&amp;lt;/code&amp;gt; / Standard: 10 Sekunden) weiterhin die asynchrone FHEM Infrastruktur ([[DevIo]]/[[#X_Read|Read]]-Funktion und [[DevelopmentModuleAPI#InternalTimer|InternalTimer]]) zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Sobald alle nötigen Maßnahmen erledigt sind, muss der Abschluss mit [[DevelopmentModuleAPI#CancelDelayedShutdown|CancelDelayedShutdown(&amp;lt;code&amp;gt;$name&amp;lt;/code&amp;gt;)]] an FHEM zurückgemeldet werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_DelayedShutdown($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
&lt;br /&gt;
	# Aufräumen starten&lt;br /&gt;
	&lt;br /&gt;
	return 1;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Shutdown ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Shutdown ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Mit der X_Shutdown Funktion kann ein Modul Aktionen durchführen bevor FHEM gestoppt wird. Dies kann z.B. der ordnungsgemäße Verbindungsabbau mit dem physikalischen Gerät sein (z.B. Session beenden, Logout, etc.). Nach der Ausführung der Shutdown-Fuktion wird FHEM sofort beendet. Falls vor dem Herunterfahren von FHEM asynchrone Kommunikation (via [[DevIo]]/[[#X_Read|X_Read]]) notwendig ist um eine vorhandene Verbindung sauber zu beenden, sollte man [[#X_DelayedShutdownFn|X_DelayedShutdownFn]] verwenden.&lt;br /&gt;
&lt;br /&gt;
Als Übergabeparameter wird der Geräte-Hash bereitgestellt. Der Rückgabewert einer Shutdown-Funktion wird nicht ausgewertet und ist daher irrelevant.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Shutdown($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
&lt;br /&gt;
	# Verbindung schließen&lt;br /&gt;
	DevIo_CloseDev($hash);&lt;br /&gt;
	return undef;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Funktionen für zweistufiges Modulkonzept ===&lt;br /&gt;
&lt;br /&gt;
Für das [[#Zweistufiges_Modell_für_Module|zweistufige Modulkonzept]] gibt es weiterhin:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;text-align:left&amp;quot; | Funktionsname !! style=&amp;quot;text-align:left&amp;quot; class=&amp;quot;unsortable&amp;quot; | Kurzbeschreibung&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Parse|X_Parse]] || Zustellen von Daten via [[DevelopmentModuleAPI#Dispatch|Dispatch()]] vom physischen Modul zum logischen Modul zwecks der Verarbeitung.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Write|X_Write]]|| Zustellen von Daten via [[DevelopmentModuleAPI#Dispatch|IOWrite()]] vom logischen zum physischen Modul um diese an die Hardware weiterzureichen.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Fingerprint|X_Fingerprint]] || Rückgabe eines &amp;quot;Fingerabdrucks&amp;quot; einer Nachricht. Dient der Erkennung von Duplikaten im Rahmen von [[DevelopmentModuleAPI#Dispatch|Dispatch()]]. Kann im physischen, als auch logischen Modul benutzt werden.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Für das zweistufige Modulkonzept muss in einem logischen Modul eine [[#X_Parse|Parse]]-Funktion im Modul-Hash registriert werden. In einem physikalischen Modul muss eine [[#X_Write|Write]]-Funktion registriert sein. Diese dienen dem Datenaustausch in beide Richtungen und werden von dem jeweils anderen Modul indirekt aufgerufen.&lt;br /&gt;
&lt;br /&gt;
In der [[#X_Initialize|Initialize]]-Funktion werden diese wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
$hash-&amp;gt;{ParseFn}       = &amp;quot;X_Parse&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{WriteFn}       = &amp;quot;X_Write&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{FingerprintFn} = &amp;quot;X_Fingerprint&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diese Funktionen werden in diesem Abschnitt genauer beschrieben.&lt;br /&gt;
&lt;br /&gt;
==== X_Parse ====&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;u&amp;gt;&#039;&#039;&#039;ACHTUNG&#039;&#039;&#039;:&amp;lt;/u&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
Dieser Abschnitt geht davon aus, dass das Modul mit dem Namen &amp;quot;X&amp;quot; ein &#039;&#039;&#039;logisches Modul&#039;&#039;&#039; im Sinne des zweistufigen Modulkonzepts ist, also Daten mit einem übergeordneten, physikalischen Modul austauscht.}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Parse ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $io_hash, $message) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	return $found;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion X_Parse wird aufgerufen, sobald von dem IO-Gerät &amp;lt;code&amp;gt;$io_hash&amp;lt;/code&amp;gt; eine Nachricht &amp;lt;code&amp;gt;$message&amp;lt;/code&amp;gt; via [[DevelopmentModuleAPI#Dispatch|Dispatch()]] zur Verarbeitung angefragt wird. Die Parse-Funktion muss dann prüfen, zu welcher Gerätedefinition diese Nachricht gehört und diese entsprechend verarbeiten.&lt;br /&gt;
&lt;br /&gt;
Üblicherweise enthält eine Nachricht immer eine Komponente durch welche sich die Nachricht einem Gerät zuordnen lässt (z.B. Adresse, ID-Nummer, ...). Eine solche Identifikation sollte man im Rahmen der [[#X_Define|Define]]-Funktion im logischen Modul an geeigneter Stelle speichern, um in der Parse-Funktion eine einfache Zuordnung von Adresse/ID einer Nachricht zur entsprechenden Gerätedefinition zu haben. Dazu wird in der Regel im Modul-Hash im modulspezifischen Bereich eine Liste &amp;lt;code&amp;gt;defptr&amp;lt;/code&amp;gt; (Definition Pointer) geführt, welche jede eindeutige Adresse/ID dem entsprechenden Geräte-Hash zuordnet:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sub X_Define ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $def) = @_;&lt;br /&gt;
	my @a = split(&amp;quot;[ \t][ \t]*&amp;quot;, $def);&lt;br /&gt;
	my $name = $a[0];&lt;br /&gt;
&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	# erstes Argument ist die eindeutige Geräteadresse&lt;br /&gt;
	my $address = $a[1];&lt;br /&gt;
&lt;br /&gt;
	# Adresse rückwärts dem Hash zuordnen (für ParseFn)&lt;br /&gt;
	$modules{X}{defptr}{$address} = $hash;&lt;br /&gt;
&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Auf Basis dieses Definition Pointers kann die Parse-Funktion nun sehr einfach prüfen, ob für die empfangene Nachricht bereits eine entsprechende Gerätedefinition existiert. Sofern diese existiert, kann die Nachricht entsprechend verarbeitet werden. Sollte jedoch keine passende Gerätedefinition zu der empfangenen Nachricht existieren, so muss die Parse-Funktion den Gerätenamen &amp;quot;UNDEFINED&amp;quot; zusammen mit den Argumenten für einen &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl zurückgeben, welcher ein passendes Gerät in FHEM anlegen würde (durch [[autocreate]]).&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sub X_Parse ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $io_hash, $message) = @_;&lt;br /&gt;
	&lt;br /&gt;
	# Die Stellen 10-15 enthalten die eindeutige Identifikation des Geräts&lt;br /&gt;
	my $address = substr($message, 10, 5); &lt;br /&gt;
&lt;br /&gt;
	# wenn bereits eine Gerätedefinition existiert (via Definition Pointer aus Define-Funktion)&lt;br /&gt;
	if(my $hash = $modules{X}{defptr}{$address}) &lt;br /&gt;
	{&lt;br /&gt;
		...  # Nachricht für $hash verarbeiten&lt;br /&gt;
		&lt;br /&gt;
		# Rückgabe des Gerätenamens, für welches die Nachricht bestimmt ist.&lt;br /&gt;
		return $hash-&amp;gt;{NAME}; &lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
	{&lt;br /&gt;
		# Keine Gerätedefinition verfügbar&lt;br /&gt;
		# Daher Vorschlag define-Befehl: &amp;lt;NAME&amp;gt; &amp;lt;MODULNAME&amp;gt; &amp;lt;ADDRESSE&amp;gt;&lt;br /&gt;
		return &amp;quot;UNDEFINED X_&amp;quot;.$address.&amp;quot; X $address&amp;quot;;&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Write ====&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;u&amp;gt;&#039;&#039;&#039;ACHTUNG&#039;&#039;&#039;:&amp;lt;/u&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
Dieser Abschnitt geht davon aus, dass das Modul mit dem Namen &amp;quot;X&amp;quot; ein &#039;&#039;&#039;physisches Modul&#039;&#039;&#039; im Sinne des zweistufigen Modulkonzepts ist, also Daten mit untergeordneten logischen Modulen austauscht. }}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Write ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, @arguments) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	return $return;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Write-Funktion wird durch die Funktion [[DevelopmentModuleAPI#IOWrite|IOWrite()]] aufgerufen, sobald eine logische Gerätedefinition Daten per IO-Gerät an die Hardware übertragen möchte. Dazu kümmert sich die Write-Funktion um die Übertragung der Nachricht in geeigneter Form an die verbundene Hardware. Als Argumente wird der Hash des physischen Gerätes übertragen, sowie alle weiteren Argumente, die das logische Modul beim Aufruf von IOWrite() mitgegeben hat. Im Normalfall ist das ein Skalar mit der zu sendenden Nachricht in Textform. Es kann aber auch sein, dass weitere Daten zum Versand notwendig sind (evtl. Schlüssel, Session-Key, ...). Daher ist die Parametersyntax einer zu schreibenden Nachricht via IOWrite-/Write-Funktion zwischen logischem und physikalischem Modul abzustimmen.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Write ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $message, $address) = @_;&lt;br /&gt;
	&lt;br /&gt;
	DevIo_SimpleWrite($hash, $address.$message, 2);&lt;br /&gt;
&lt;br /&gt;
	return undef;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Fingerprint ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Fingerprint($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $io_name, $msg ) = @_;&lt;br /&gt;
 &lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return ( $io_name, $fingerprint );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Fingerprint-Funktion dient der Erkennung von Duplikaten empfangener Nachrichten. Diese Funktion kann dabei sowohl im physischen, als auch im logischen Modul implementiert sein - je nachdem auf welcher Ebene man für eine Nachricht einen Fingerprint bilden kann. &lt;br /&gt;
&lt;br /&gt;
Als Parameter wird der Name des IO-Geräts &amp;lt;code&amp;gt;$io_name&amp;lt;/code&amp;gt; übergeben, sowie die Nachricht &amp;lt;code&amp;gt;$msg&amp;lt;/code&amp;gt;, welche empfangen wurde. Nun muss aus dieser Nachricht ein eindeutiger Fingerprint gebildet werden. Dies bedeutet, dass alle variablen Inhalte, die aufgrund des Empfangs dieser Nachricht über unterschiedliche IO-Geräte enthalten sein können, entfernt werden müssen. Dies können bspw. Empfangsadressen von IO-Geräten sein oder Session-ID&#039;s die in der Nachricht enthalten sind. Alle Fingerprints sämtlicher Nachrichten, die innerhalb der letzten 500 Millisekunden (konfigurierbar via &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt; Attribut &amp;lt;code&amp;gt;dupTimeout&amp;lt;/code&amp;gt;) empfangen wurden, werden gegen diesen generierten Fingerprint getestet. Sollte innerhalb dieser Zeit bereits eine Nachricht mit diesem Fingerprint verarbeitet worden sein, so wird sie als Duplikat erkannt und nicht weiter verarbeitet. In diesem Fall gibt [[DevelopmentModuleAPI#Dispatch|Dispatch()]] den Namen der Gerätedefinition zurück, welche eine Nachricht mit dem selben Fingerprint bereits verarbeitet hat. Es erfolgt dann kein Aufruf der [[#X_Parse|Parse]]-Funktion.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Fingerprint($$)&lt;br /&gt;
{&lt;br /&gt;
  my ( $io_name, $msg ) = @_;&lt;br /&gt;
&lt;br /&gt;
  substr( $msg, 2, 2, &amp;quot;--&amp;quot; ); # entferne Empfangsadresse&lt;br /&gt;
  substr( $msg, 4, 1, &amp;quot;-&amp;quot; );  # entferne Hop-Count&lt;br /&gt;
&lt;br /&gt;
  return ( $io_name, $msg );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Es wird zuerst, sofern implementiert, die Fingerprint-Funktion des physischen Moduls aufgerufen. Sollte sich hierdurch kein Duplikat erkennen lassen, wird die Fingerprint-Funktion jedes möglichen geladenen logischen Moduls aufgerufen, sofern implementiert. &lt;br /&gt;
&lt;br /&gt;
Sollte sowohl im physischen, als auch im logischen Modul keine Fingerprint-Funktion implementiert sein, so wird keinerlei Duplikatserkennung durchgeführt.&lt;br /&gt;
&lt;br /&gt;
=== FHEMWEB-spezifische Funktionen ===&lt;br /&gt;
&lt;br /&gt;
FHEMWEB bietet Modul-Autoren die Möglichkeit an durch spezielle Funktionsaufrufe in Modulen, eigene HTML-Inhalte zu verwenden. Dadurch können in Verbindung mit zusätzlichem JavaScript komplexe Dialoge/Inhalte/Steuermöglichkeiten dargestellt werden. &lt;br /&gt;
&lt;br /&gt;
Eine genaue Auflistung aller FHEMWEB-spezifischen Funktionsaufrufe gibt es in dem separaten Artikel [[DevelopmentFHEMWEB]]&lt;br /&gt;
&lt;br /&gt;
=== sonstige Funktionen ===&lt;br /&gt;
&lt;br /&gt;
In diesem Abschnitt werden weitere Funktionen behandelt die zum Teil aus FHEM, aber auch aus anderen Modulen aufgerufen werden. Sie sind dabei nur in speziellen Anwendungsfällen relevant. Hier eine Auflistung aller sonstigen Modulfunktionen:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Funktionsname !! class=&amp;quot;unsortable&amp;quot; | Kurzbeschreibung&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_DbLog_split|X_DbLog_split]] || Wird durch das Modul 93_DbLog.pm aufgerufen. Dient dem korrekten Split eines moduleigenen Events in Name/Wert/Einheit für die Nutzung einer Datenbank.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Except|X_Except]]|| Wird aufgerufen, sobald ein ein geöffneter Filedescriptor in [[#Wichtige_globale_Variablen_aus_fhem.pl|&amp;lt;code&amp;gt;%selectlist&amp;lt;/code&amp;gt;]], der unter &amp;lt;code&amp;gt;$hash-&amp;gt;{EXCEPT_FD}&amp;lt;/code&amp;gt; im Geräte-Hash gesetzt ist, einen Interrupt bzw. Exception auslöst.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Copy|X_Copy]]|| Wird durch das Modul 98_copy.pm aufgerufen im Rahmen des &amp;lt;code&amp;gt;copy&amp;lt;/code&amp;gt;-Befehls sobald ein Gerät kopiert wurde.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_State|X_State]]|| Wird aufgerufen im Rahmen des &amp;lt;code&amp;gt;setstate&amp;lt;/code&amp;gt;-Befehls bevor der Status einer Gerätedefinition bzw. eines zugehörigen Readings gesetzt wird.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_AsyncOutput|X_AsyncOutput]]|| Nur relevant für Module die via [[TcpServerUtils]] eine Client-Verbindung zu FHEM ermöglichen (z.B. FHEMWEB und telnet). Ermöglicht die asynchrone Ausgabe von Daten via [[DevelopmentModuleAPI#asyncOutput|asyncOutput()]] an einen einzelnen verbundenen Client.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_ActivateInform|X_ActivateInform]]|| Nur relevant für Module die via [[TcpServerUtils]] eine Client-Verbindung zu FHEM ermöglichen (z.B. FHEMWEB und telnet). Ermöglicht das Aktivieren des inform-Mechanismus zum Senden von Events für einen einzelnen verbundenen Client.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Authorize|X_Authorize]]|| Wird aufgerufen im Rahmen von [[DevelopmentModuleAPI#Authorized|Authorized()]] um eine gewünschte Vorgangs-Art zu autorisieren.&lt;br /&gt;
|-&lt;br /&gt;
| [[#X_Authenticate|X_Authenticate]]||  Wird aufgerufen im Rahmen von [[DevelopmentModuleAPI#Authenticate|Authenticate()]] um eine Authentifizierung zu prüfen und ggf. zu genehmigen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In der [[#X_Initialize|Initialize]]-Funktion werden diese wie folgt definiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
$hash-&amp;gt;{DbLog_splitFn} = &amp;quot;X_DbLog_split&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{ExceptFn} = &amp;quot;X_Except&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{CopyFn} = &amp;quot;X_Copy&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{AsyncOutputFn} = &amp;quot;X_AsyncOutput&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{ActivateInformFn} = &amp;quot;X_ActivateInform&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{StateFn} = &amp;quot;X_State&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{AuthorizeFn} = &amp;quot;X_Authorize&amp;quot;;&lt;br /&gt;
$hash-&amp;gt;{AuthenticateFn} = &amp;quot;X_Authenticate&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Diese Funktionen werden in diesem Abschnitt genauer beschrieben.&lt;br /&gt;
==== X_DbLog_split ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_DbLog_split ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $event, $device_name ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
    &lt;br /&gt;
	return  ( $reading, $value, $unit );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die DbLog_split-Funktion wird durch das Modul [[DbLog]] aufgerufen, sofern der Nutzer DbLog benutzt. Sofern diese Funktion implementiert ist, kann der Modul-Autor das Auftrennen von Events in den Reading-Namen, -Wert und der Einheit selbst steuern. Andernfalls nimmt DbLog diese Auftrennung selber mittels Trennung durch Leerzeichen sowie vordefinierten Regeln zu verschiedenen Modulen vor. Je nachdem, welche Readings man in seinem Modul implementiert, passt diese standardmäßige Trennung jedoch nicht immer.&lt;br /&gt;
&lt;br /&gt;
Der Funktion werden folgende Eingangsparameter übergeben:&lt;br /&gt;
# Das generierte Event (Bsp: &amp;lt;code&amp;gt;temperature: 20.5 °C&amp;lt;/code&amp;gt;)&lt;br /&gt;
# Der Name des Geräts, welche das Event erzeugt hat (Bsp: &amp;lt;code&amp;gt;Temperatursensor_Wohnzimmer&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
Es ist nicht möglich in der DbLog_split-Funktion auf die verarbeitende DbLog-Definition zu referenzieren.&lt;br /&gt;
&lt;br /&gt;
Als Rückgabewerte muss die Funktion folgende Werte bereitstellen:&lt;br /&gt;
# Name des Readings (Bsp: &amp;lt;code&amp;gt;temperature&amp;lt;/code&amp;gt;)&lt;br /&gt;
# Wert des Readings (Bsp: &amp;lt;code&amp;gt;20.5&amp;lt;/code&amp;gt;)&lt;br /&gt;
# Einheit des Readings (Bsp: &amp;lt;code&amp;gt;°C&amp;lt;/code&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_DbLog_splitFn($$)&lt;br /&gt;
{&lt;br /&gt;
	my ($event, $device) = @_;&lt;br /&gt;
	my ($reading, $value, $unit);&lt;br /&gt;
        my $devhash = $defs{$device}&lt;br /&gt;
&lt;br /&gt;
	if($event =~ m/temperature/) {&lt;br /&gt;
	   $reading = &#039;temperature&#039;;&lt;br /&gt;
	   $value = substr($event,12,4);&lt;br /&gt;
	   $unit = &#039;°C&#039;;&lt;br /&gt;
	}   &lt;br /&gt;
        &lt;br /&gt;
        return ($reading, $value, $unit);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Except ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Except ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die X_Except-Funktion wird durch fhem.pl aufgerufen, wenn die Gerätedefinition &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;[[#Wichtige_globale_Variablen_aus_fhem.pl|%selectlist]]&amp;lt;/code&amp;gt; aufgeführt ist und der Filedeskriptor in &amp;lt;code&amp;gt;$hash-&amp;gt;{EXCEPT_FD}&amp;lt;/code&amp;gt; eine Exception bzw. Interrupt auslöst. &lt;br /&gt;
&lt;br /&gt;
Der Rückgabewert wird nicht ausgewertet und ist daher irrelevant.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
use IO::File;&lt;br /&gt;
&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
sub X_Except ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	# Filehandle aus Filedescriptor erstellen&lt;br /&gt;
	my $filehandle = IO::File-&amp;gt;new_from_fd($hash-&amp;gt;{EXCEPT_FD}, &#039;r&#039;);&lt;br /&gt;
	seek($filehandle,0,0);	&lt;br /&gt;
&lt;br /&gt;
	# aktuellen Inhalt auslesen&lt;br /&gt;
	my $current_value = $filehandle-&amp;gt;getline;&lt;br /&gt;
&lt;br /&gt;
	if($current_value eq &amp;quot;1&amp;quot;)&lt;br /&gt;
	{&lt;br /&gt;
		...&lt;br /&gt;
	}&lt;br /&gt;
	else&lt;br /&gt;
	{&lt;br /&gt;
		...&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Copy ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Copy ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $old_name, $new_name ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die X_Copy-Funktion wird durch das Modul [[copy]] aufgerufen nachdem ein Nutzer eine Gerätedefinition über den Befehl &amp;lt;code&amp;gt;copy&amp;lt;/code&amp;gt; kopiert hat. Dazu werden als Funktionsparameter die Definitionsnamen der alten und neuen Gerätedefinition übergeben. Es dient dazu zusätzliche Daten aus der zu kopierenden Gerätedefinition in die neue Definition zu übernehmen. Der Befehl &amp;lt;code&amp;gt;copy&amp;lt;/code&amp;gt; überträgt lediglich &amp;lt;code&amp;gt;$hash-&amp;gt;{DEF}&amp;lt;/code&amp;gt; in die neue Definition sowie sämtliche gesetzte Attribute. Weitere Daten müssen dann durch die X_Copy-Funktion übertragen werden. &lt;br /&gt;
&lt;br /&gt;
Die X_Copy-Funktion wird erst nach dem erfolgtem Kopiervorgang aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Der Rückgabewert wird nicht ausgewertet und ist daher irrelevant.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
sub X_Copy ($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $old_name, $new_name ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	my $old_hash = $defs{$old_name};&lt;br /&gt;
	my $new_hash = $defs{$new_name};&lt;br /&gt;
&lt;br /&gt;
	# copy also temporary session key&lt;br /&gt;
	$new_hash-&amp;gt;{helper}{SESSION_KEY} = $old_hash-&amp;gt;{helper}{SESSION_KEY};&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_AsyncOutput ====&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=&#039;&#039;&#039;ACHTUNG:&#039;&#039;&#039; Diese Funktion ist nur relevant, wenn man ein Frontend-Modul erstellt über das FHEM von einem Anwender bedient werden kann (FHEMWEB, telnet, yowsup, telegram, alexa-fhem, homebridge-fhem, tabletui, ...).}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_AsyncOutput ($)&lt;br /&gt;
{&lt;br /&gt;
	my ( $client_hash, $text ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion X_AsyncOutput wird durch [[DevelopmentModuleAPI#asyncOutput|asyncOutput()]] von anderen Modulen aufgerufen. Es erlaubt diesen anderen Modulen die Ausgabe von asynchronen Befehlsergebnissen &amp;lt;code&amp;gt;$text&amp;lt;/code&amp;gt; zuvor ausgeführter set-/get-Befehle an den entsprechenden Client (identifiziert durch den Client-Hash &amp;lt;code&amp;gt;$client_hash&amp;lt;/code&amp;gt; der temporären Definition) zurückzugeben. &lt;br /&gt;
&lt;br /&gt;
Wenn ein Client einen set-/get-Befehl ausführt, wird der Client-Hash bei der Ausführung dieser Befehle an die jeweiligen Module übermittelt. Sobald ein Befehl ausgeführt wird, der seine Ausgabe asynchron ausführen möchte und die Client-Verbindung des Server-Moduls dies unterstützt (&amp;lt;code&amp;gt;$client_hash-&amp;gt;{canAsyncOutput}&amp;lt;/code&amp;gt; ist gesetzt), merkt sich das befehlsausführende Modul den Client-Hash und gibt das Ergebnis des Befehls zu späterer Zeit via [[DevelopmentModuleAPI#asyncOutput|asyncOutput()]] an den ursprünglichen Client zurück. Die Funktion X_AsyncOutput des Server-Moduls kümmert sich darum das Ergebnis dem entsprechenden Client in der notwendigen Form zuzustellen.&lt;br /&gt;
&lt;br /&gt;
Der Rückgabewert von X_AsyncOutput() wird als Rückgabewert für asyncOutput() verwendet. Man kann hier im Fehlerfall eine Fehlermeldung angeben und im Erfolgsfall &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt;. Der Rückgabewert wird aber aktuell nicht ausgewertet.&lt;br /&gt;
&lt;br /&gt;
==== X_ActivateInform====&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=&#039;&#039;&#039;ACHTUNG:&#039;&#039;&#039; Diese Funktion ist nur relevant, wenn man ein Frontend-Modul erstellt über das FHEM von einem Anwender bedient werden kann (FHEMWEB, telnet, yowsup, telegram, alexa-fhem, homebridge-fhem, tabletui, ...).}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_ActivateInform($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $client_hash, $arg ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Funktion X_ActivateInform wird aktuell nur durch den [[update]]-Befehl aufgerufen, sofern ein Client eines Frontend-Moduls diesen Befehl aufgerufen hat um den Inform-Mechanismus (Senden von Events) zu aktivieren. Dadurch wird im Falle von [[update]] die umgehende Anzeige der Logmeldungen für den ausführenden Client aktiviert. In [[FHEMWEB]] geschieht das über den Event-Monitor, bei telnet mit der direkten Ausgabe.&lt;br /&gt;
&lt;br /&gt;
Da diese Funktion aktuell nur speziell für den update-Befehl implementiert ist, kann man aktuell keine genaue Angaben zu den möglichen Werten von &amp;lt;code&amp;gt;$arg&amp;lt;/code&amp;gt; geben. Dieser Parameter dient dazu genauer zu spezifizieren was exakt an Events an den entsprechenden Client &amp;lt;code&amp;gt;$client_hash&amp;lt;/code&amp;gt; zu senden ist. Aktuell wird dazu die Parametersyntax des inform-Befehls verwendet (on|off|log|raw|timer|status).&lt;br /&gt;
&lt;br /&gt;
==== X_State ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_State($$$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $time, $readingName, $value ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
&lt;br /&gt;
	return $error;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die X_State-Funktion wird durch fhem.pl aufgerufen, sobald über den Befehl &amp;lt;code&amp;gt;setstate&amp;lt;/code&amp;gt; versucht wird ein Wert für ein Reading oder den Status (&amp;lt;code&amp;gt;$hash-&amp;gt;{STATE}&amp;lt;/code&amp;gt;) einer Gerätedefinition zu setzen. Dieser Befehl wird primär beim Starten von FHEM aufgerufen sobald das State-File eingelesen wird. Je nachdem, ob im gegebenen Fall ein Reading oder der Definitionsstatus gesetzt wird, haben die Übergabeparameter verschiedene Werte:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Funktionsparameter!! Wert beim Setzen eines Readings !! Wert beim Setzen eines Definitionsstatus&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; || colspan=&amp;quot;2&amp;quot; align=&amp;quot;center&amp;quot; | Die Hashreferenz der betreffenden Gerätedefinition&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$time&amp;lt;/code&amp;gt;|| Der Zeitstempel auf welchen das Reading &amp;lt;code&amp;gt;$readingName&amp;lt;/code&amp;gt; gesetzt werden soll. Das Ergebnis entspricht dem Rückgabewert der Funktion || Der aktuelle Zeitstempel zum jetzigen Zeitpunkt.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$readingName&amp;lt;/code&amp;gt;|| Der Name des Readings, welches auf einen neuen Wert gesetzt werden soll. || Statischer Wert &amp;quot;STATE&amp;quot; um anzuzeigen, dass es sich um den Definitionsstatus handelt, welcher gesetzt werden soll (&amp;lt;code&amp;gt;$hash-&amp;gt;{STATE}&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$value&amp;lt;/code&amp;gt; || Den Wert, welchen das Reading &amp;lt;code&amp;gt;$readingName&amp;lt;/code&amp;gt; annehmen soll. || Den Wert, welchen die Gerätedefinition als Status annehmen soll.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Wenn via &amp;lt;code&amp;gt;setstate&amp;lt;/code&amp;gt; ein Reading gesetzt wird, kann die X_State-Funktion das Setzen dieses Readings durch die Rückgabe einer aussagekräftigen Fehlermeldung unterbinden. Sofern &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt; zurückgegeben wird, wird das entsprechende Reading auf den übergebenen Status gesetzt.&lt;br /&gt;
&lt;br /&gt;
Wenn via &amp;lt;code&amp;gt;setstate&amp;lt;/code&amp;gt; der Definitionsstatus gesetzt wird, wird die X_State-Funktion erst nach dem Setzen des Status aufgerufen. Man kann dabei zwar eine Fehlermeldung zurückgeben, der Status wird aber dennoch übernommen. Die Fehlermeldung wird lediglich dem Nutzer angezeigt.&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_State($$$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $time, $readingName, $value ) = @_;&lt;br /&gt;
&lt;br /&gt;
	return undef if($readingName &amp;quot;STATE&amp;quot; || $value ne &amp;quot;inactive&amp;quot;);&lt;br /&gt;
	readingsSingleUpdate($hash, &amp;quot;state&amp;quot;, &amp;quot;inactive&amp;quot;, 1);&lt;br /&gt;
	return undef;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== X_Authorize ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Authorize($$$$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $client_hash, $type, $arg ) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	return $authorized;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Authorize-Funktion wird von fhem.pl aufgerufen um zu erfragen, ob ein bestimmter Client &amp;lt;code&amp;gt;$client_hash&amp;lt;/code&amp;gt; die Aktion &amp;lt;code&amp;gt;$type&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;$arg&amp;lt;/code&amp;gt; ausführen darf. Auf diese Weise können Module Einfluss nehmen, welcher User welche Funktionen in FHEM nutzen darf. Wenn ein Client eine Aktion ausführen möchte, werden alle Module, die eine Authorize-Funktion implementiert haben, gefragt, ob diese Aktion ausgeführt werden darf. Als Rückgabewert wird das Ergebnis der Überprüfung zurückgegeben, wobei &amp;lt;code&amp;gt;0&amp;lt;/code&amp;gt; (unbekannt / nicht zuständig), &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt; (erlaubt) oder &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt; (verboten) zurückgegeben werden können.&lt;br /&gt;
&lt;br /&gt;
Es gibt aktuell folgende &amp;lt;code&amp;gt;$type&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;$arg&amp;lt;/code&amp;gt; Kombinationen, mit denen die Authorize-Funktion aufgerufen werden:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! $type !! $arg !! Überschrift&lt;br /&gt;
|- &lt;br /&gt;
| rowspan=&amp;quot;3&amp;quot; style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&#039;&#039;&#039;$type&#039;&#039;&#039; = &amp;quot;cmd&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Befehlsausführung&#039;&#039;&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&#039;&#039;&#039;$arg&#039;&#039;&#039; = &amp;quot;set Lampe on&amp;quot;&amp;lt;/code&amp;gt; || Jeglicher FHEM-Befehl, der ausgeführt werden soll, wird in &amp;lt;code&amp;gt;$arg&amp;lt;/code&amp;gt; hinterlegt, sodass innerhalb einer Authorize-Funktion der Befehl genauer geparst werden kann um zu entscheiden, ob dieser Befehl erlaubt ist, oder nicht.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&#039;&#039;&#039;$arg&#039;&#039;&#039; = &amp;quot;perl&amp;quot;&amp;lt;/code&amp;gt; || Ausführen von Perl-Befehlen jeglicher Art. Der genaue Befehl wird dabei nicht an die Authorize-Funktion übergeben.&lt;br /&gt;
&lt;br /&gt;
Bsp: &amp;lt;code&amp;gt;{ReadingsVal(&amp;quot;Lampe&amp;quot;, &amp;quot;state&amp;quot;, &amp;quot;off&amp;quot;}&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&#039;&#039;&#039;$arg&#039;&#039;&#039; = &amp;quot;shell&amp;quot;&amp;lt;/code&amp;gt; || Ausführen von Shell-Befehlen jeglicher Art. Der genaue Befehl wird dabei nicht an die Authorize-Funktion übergeben.&lt;br /&gt;
&lt;br /&gt;
Bsp: &amp;lt;code&amp;gt;&amp;quot;/opt/fhem/myScript.sh&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&#039;&#039;&#039;$type&#039;&#039;&#039; = &amp;quot;devicename&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Sichtbarkeit von Geräten/Definitionen&#039;&#039; &lt;br /&gt;
| style=&amp;quot;white-space: nowrap;&amp;quot; |  &amp;lt;code&amp;gt;&#039;&#039;&#039;$arg&#039;&#039;&#039; = &amp;quot;Licht_Wohnzimmer&amp;quot;&amp;lt;/code&amp;gt; || Sichtbarkeit des jeweiligen Gerät/Definition in FHEM. Dies bedeutet konkret die Auffindbarkeit im &amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;-Befehl, sowie der Suche via [[DevelopmentModuleAPI#devspec2array|devspec2array()]]. Wird eine solche Anfrage durch die Authorize-Funktion abgelehnt, ist das entsprechende Gerät bzw. Definition für den jeweiligen Client nicht sichtbar.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== X_Authenticate ====&lt;br /&gt;
{{Link2Forum|Topic=72757|Message=644098}}&lt;br /&gt;
&lt;br /&gt;
== Bereitstellen eines eigenen Befehls (Befehlsmodul) ==&lt;br /&gt;
&lt;br /&gt;
Ein Modul kann primär einen neuen FHEM-Befehl bereitstellen. Man spricht in so einem Fall nicht von einem Gerätemodul, sondern einem Befehlsmodul. Ein solches Befehlsmodul stellt nur einen einzelnen Befehl bereit, der dem Modulnamen entsprechen muss. Nur, wenn der Modulname dem Befehlsname entspricht, kann FHEM das Modul beim ersten Ausführen dieses unbekannten Befehls finden und nachladen.&lt;br /&gt;
&lt;br /&gt;
Der entsprechende Befehl wird dazu in der [[#X_Initialize|Initialize]]-Funktion im globalen Hash &amp;lt;code&amp;gt;[[DevelopmentModuleIntro#Wichtige_globale_Variablen_aus_fhem.pl|%cmds]]&amp;lt;/code&amp;gt; registriert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($$) {&lt;br /&gt;
&lt;br /&gt;
    $cmds{X} = { Fn           =&amp;gt; &amp;quot;CommandX&amp;quot;,&lt;br /&gt;
                 Hlp          =&amp;gt; &amp;quot;&amp;lt;argument1&amp;gt; [optional_argument2], print something very useful&amp;quot;,&lt;br /&gt;
 &lt;br /&gt;
                 # optionaler Filter für Clientmodule als regulärer Ausdruck&lt;br /&gt;
                 ClientFilter =&amp;gt; &amp;quot;FHEMWEB&amp;quot;&lt;br /&gt;
                };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit wird der neue Befehl &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; in FHEM registriert. Die Funktion mit dem Namen &amp;lt;code&amp;gt;CommandX&amp;lt;/code&amp;gt; setzt diesen Befehl innerhalb des Moduls um. Desweiteren wird eine kurze Aufrufsyntax mitgegeben, welche beim Aufruf des &amp;lt;code&amp;gt;help&amp;lt;/code&amp;gt;-Befehls dem Nutzer angezeigt wird um als Gedankenstütze zu dienen. Optional kann man mittels &amp;lt;code&amp;gt;ClientFilter&amp;lt;/code&amp;gt; (regulärer Ausdruck für Modulnamen) die Ausführbarkeit nur auf bestimmte Client-Module (wie FHEMWEB oder telnet) beschränken. &lt;br /&gt;
&lt;br /&gt;
Nun muss noch die Funktion &amp;lt;code&amp;gt;CommandX&amp;lt;/code&amp;gt; im Rahmen des Moduls implementiert werden, welche den Befehl &amp;lt;code&amp;gt;X&amp;lt;/code&amp;gt; umsetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;Perl&amp;quot;&amp;gt;&lt;br /&gt;
sub CommandX($$)&lt;br /&gt;
{&lt;br /&gt;
 	my ($client_hash, $arguments) = @_;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	return $output;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dabei werden der Befehlsfunktion zwei Parameter übergeben. Zuerst die Hash-Referenz des aufrufenden Clients (sofern manuell ausgeführt, ansonsten &amp;lt;code&amp;gt;undef&amp;lt;/code&amp;gt;) zwecks Rechteprüfung via [[allowed|allowed-Definitionen]]. Anschließend folgen die Aufrufparameter als zusammenhängende Zeichenkette. Die Trennung der einzelnen Argumente obligt der Funktion (bspw. via [[DevelopmentModuleAPI#parseParams|parseParams()]]). Als Funktionsrückgabewert wird eine Ausgabemeldung erwartet, die dem Nutzer angezeigt werden soll.&lt;br /&gt;
&lt;br /&gt;
== Pollen von Geräten ==&lt;br /&gt;
Wenn Geräte von sich aus keine Informationen senden sondern abgefragt werden müssen, kann man im Modul die Funktion [[DevelopmentModuleAPI#InternalTimer|InternalTimer()]] verwenden um einen Funktionsaufruf zu einem späteren Zeitpunkt durchführen zu können. Man übergibt dabei den Zeitpunkt für den nächsten Aufruf, den Namen der Funktion, die aufgerufen werden soll, sowie den zu übergebenden Parameter. Als zu übergebender Parameter wird üblicherweise der Hash der betroffenen Geräteinstanz verwendet. Damit hat die aufgerufene Funktion Zugriff auf alle wichtigen Daten der Geräteinstanz. Eventuell zusätzlich benötigte Werte können einfach als weitere Internals über den Hash zugänglich gemacht werden.&lt;br /&gt;
&lt;br /&gt;
Beispielsweise könnte man für das Abfragen eines Geräts in der [[#X_Define|Define]]-Funktion den Timer folgendermaßen setzen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
InternalTimer(gettimeofday()+2, &amp;quot;X_GetUpdate&amp;quot;, $hash);	&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Alternativ kann man auch in der [[#X_Notify|Notify]]-Funktion auf das Event &amp;lt;code&amp;gt;global:INITIALIZED&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;global:REREADCFG&amp;lt;/code&amp;gt; reagieren und erst dort, den Timer anstoßen, sobald die Konfiguration komplett eingelesen wurde. Dies ist insbesondere notwendig, wenn man sicherstellen will, dass alle Attribute aus der Konfiguration gesetzt sind, sobald man einen Status-Update initiiert.&lt;br /&gt;
&lt;br /&gt;
In der Funktion &amp;lt;code&amp;gt;X_GetUpdate&amp;lt;/code&amp;gt; selbst wird dann der Timer neu gesetzt, so dass nach einem Intervall die Funktion erneut aufgerufen wird:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_GetUpdate($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
	my $name = $hash-&amp;gt;{NAME};&lt;br /&gt;
	Log3 $name, 4, &amp;quot;X: GetUpdate called ...&amp;quot;;&lt;br /&gt;
	&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	# neuen Timer starten in einem konfigurierten Interval.&lt;br /&gt;
	InternalTimer(gettimeofday()+$hash-&amp;gt;{Interval}, &amp;quot;X_GetUpdate&amp;quot;, $hash);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Innerhalb der Funktion kann man nun das Gerät abfragen und die abgefragten Werte in Readings speichern. Falls das Abfragen der Werte jedoch zu einer Verzögerung und damit zu einer Blockade von FHEM führen kann, ist es möglich, in der GetUpdate-Funktion nur die Aufforderung zum Senden bestimmter Daten an das angeschlossene Gerät zu senden und dann das Lesen über die oben beschriebene [[#X_Read|Read]]-Funktion zu implementieren.&lt;br /&gt;
&lt;br /&gt;
Eine genaue Beschreibung der Timer-Funktion gibt es [[DevelopmentModuleAPI#Timer|hier im Wiki]]&lt;br /&gt;
&lt;br /&gt;
== Logging / Debugging ==&lt;br /&gt;
Um Innerhalb eines Moduls eine Log-Meldung in die FHEM-Logdatei zu schreiben, wird die Funktion [[DevelopmentModuleAPI#Log3|Log3()]] aufgerufen.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
Log3 $name, 3, &amp;quot;X ($name) - Problem erkannt ...&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Eine genaue Beschreibung zu der Funktion inkl. Aufrufparameter findet man [[DevelopmentModuleAPI#Log3|hier]]. Es ist generell ratsam in der Logmeldung sowohl den Namen des eigenen Moduls zu schreiben, sowie den Namen des Geräts, welche diese Logmeldung produziert, da die Meldung, so wie sie ist, direkt in das Logfile wandert und es für User ohne diese Informationen schwierig ist, die Meldungen korrekt zuzuordnen.&lt;br /&gt;
&lt;br /&gt;
Die Funktion Log3() verwendet den Namen der Geräteinstanz um das &amp;lt;code&amp;gt;verbose&amp;lt;/code&amp;gt;-Attribut zu prüfen. In der Regel wird bei Modulfunktionen jedoch immer nur der Gerätehash &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt; übergeben. Um den Namen der Definition zu ermitteln ist es daher notwendig sich diesen aus dem Hash extrahieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
my $name = $hash-&amp;gt;{NAME};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Um für eine einzelne Geräteinstanz das Verbose-Level zu erhöhen, ohne gleich für das gesamte FHEM den globalen Verbose-Level zu erhöhen und damit alle Meldungen zu erzeugen, kann man den Befehl &lt;br /&gt;
&amp;lt;code&amp;gt;attr &amp;lt;NAME&amp;gt; verbose&amp;lt;/code&amp;gt; verwenden. Beispielsweise &amp;lt;code&amp;gt;attr Lichtschalter_Wohnzimmer verbose 5&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Logmeldungen sollten je nach Art und Wichtigkeit für den Nutzer in unterschiedlichen Loglevels erzeugt werden. Es gibt insgesamt 5 Stufen in denen geloggt werden kann. Standardmäßig steht der systemweite Loglevel (&amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt;-Attribut &amp;lt;code&amp;gt;verbose&amp;lt;/code&amp;gt;) auf der Stufe 3. Die Bedeutung der jeweiligen Stufen ist in der {{Link2CmdRef|Lang=de|Anker=verbose}} beschrieben.&lt;br /&gt;
&lt;br /&gt;
Während der Entwicklung eines Moduls kann man für eigene Debug-Zwecke auch die Funktion [[DevelopmentModuleAPI#Debug|Debug()]] verwenden um schnell und einfach Debug-Ausgaben in das Log zu schreiben. Diese sollten in der endgültigen Fassung jedoch nicht mehr vorhanden sein. Sie dienen ausschließlich zum Debugging während der Entwicklung.&lt;br /&gt;
&lt;br /&gt;
Eine genaue Beschreibung der Log-Funktion gibt es [[DevelopmentModuleAPI#Logging|hier im Wiki]].&lt;br /&gt;
&lt;br /&gt;
== Zweistufiges Modell für Module ==&lt;br /&gt;
[[Datei:Zweistufiges Modulkonzept.jpg|mini|rechts|Schematische Darstellung am Beispiel CUL]]&lt;br /&gt;
Es gibt viele Geräte, welche die Kommunikation mit weiteren Geräten mit tlw. unterschiedlichen Protokollen ermöglichen. Das typischste Beispiel bietet hier der [[CUL]], welcher via Funk mit verschiedenen Protokollen weitere Geräte ansprechen kann (z.B. Aktoren, Sensoren, ...). Hier bildet ein Gerät eine Brücke durch die weitere Geräte in FHEM zugänglich gemacht werden können. Dabei werden über einen Kommunikationsweg (z.B. serielle Schnittstelle, TCP, ...) beliebig viele Geräte gesteuert. Typische Beispiele dazu sind:&lt;br /&gt;
&lt;br /&gt;
* [[CUL]]: stellt Geräte mit verschiedenen Kommunikationsprotokollen via Funk bereit (u.a. [[FS20]], [[HomeMatic]], [[Funk-Heizkörperregler_Kurz-Bedienungsanleitung_FHT|FHT]], [[MAX]], ...)&lt;br /&gt;
* [[HMLAN]]: stellt HomeMatic Geräte via Funk bereit&lt;br /&gt;
* [[MAX#MAXLAN|MAXLAN]]: stellt [[MAX|MAX!]] Geräte via Funk bereit&lt;br /&gt;
* [[PanStamp#panStick.2FShield|panStamp]]: stellt weitere panStamp Geräte via Funk bereit&lt;br /&gt;
&lt;br /&gt;
Dabei wird die Kommunikation in 2 Stufen unterteilt:&lt;br /&gt;
* physisches Modul - z.B. 00_CUL.pm - zuständig für die physikalische Kommunikation mit der Hardware. Empfangene Daten müssen einem logischen Modul zugeordnet werden.&lt;br /&gt;
* logische Modul(e) - z.B. 10_FS20.pm - interpretiert protokollspezifische Nachrichten. Sendet protokollspezifische Daten über das physische Modul an die Hardware.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;physisches Modul&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das physische Modul öffnet die Datenverbindung zum Gerät (z.B. CUL) und verarbeitet sämtliche Daten. Es kümmert sich um den Erhalt der Verbindung (bsp. durch Keep-Alives) und konfiguriert das Gerät so, dass eine Kommunikation mit allen weiteren Geräten möglich ist (bsp. Frequenz, Modulation, Kanal, etc.).&lt;br /&gt;
&lt;br /&gt;
Empfangene Nutzdaten werden als Zeichenkette über die Funktion [[DevelopmentModuleAPI#Dispatch|Dispatch()]] an logische Module weitergegeben.&lt;br /&gt;
&lt;br /&gt;
Das Modul stellt eine [[#Die_Match-Liste|Match-Liste]] bereit, anhand FHEM die Nachricht einem Modul zuordnen kann, sofern dieses noch nicht geladen sein sollte. Die Match-Liste enthält eine Liste von regulären Ausdrücken und ordnet diese einem Modul zu. Wenn eine Nachricht auf einen solchen regulären Ausdruck passt und das Modul noch nicht geladen ist, lädt FHEM dieses automatisch nach, zwecks Verarbeitung der Nachricht. &lt;br /&gt;
&lt;br /&gt;
Anhand einer bereitgestellten [[#Die_Client-Liste|Client-Liste]] (Auflistung von logischen Modulen) kann FHEM feststellen, welche logischen Module mit dem physischen Modul kommunizieren können. Nur die hier aufgelisteten, logischen Module werden beim Aufruf von [[DevelopmentModuleAPI#Dispatch|Dispatch()]] angesprochen.&lt;br /&gt;
&lt;br /&gt;
Das Modul stellt eine [[#X_Write|Write]]-Funktion zur Verfügung, über die logische Module Daten in beliebiger Form an die Hardware übertragen können. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;u&amp;gt;logisches Modul&amp;lt;/u&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das logische Modul interpretiert die via Dispatch() übergebene Nachricht (Zeichenkette) durch eine bereitgestellte [[#X_Parse|Parse]]-Funktion und erzeugt entsprechende Readings/Events. Es stellt über &amp;lt;code&amp;gt;set&amp;lt;/code&amp;gt;-/&amp;lt;code&amp;gt;get&amp;lt;/code&amp;gt;-Kommandos Steuerungsmöglichkeiten dem Nutzer zur Verfügung.&lt;br /&gt;
&lt;br /&gt;
Es stellt FHEM einen [[#Der_Match-Ausdruck|Match-Ausdruck]] (regulärer Ausdruck) zur Verfügung anhand [[DevelopmentModuleAPI#Dispatch|Dispatch()]] ermitteln kann, ob die Nachricht durch das logische Modul verarbeitet werden kann. Nur Nachrichten, welche auf diesen Ausdruck passen, werden an das logische Modul weitergegeben (Aufruf [[#X_Parse|Parse]]-Funktion).&lt;br /&gt;
&lt;br /&gt;
=== Die Client-Liste ===&lt;br /&gt;
&lt;br /&gt;
Die Client-Liste ist eine Auflistung von Modulnamen (genauer: regulären Ausdrücken die auf Modulnamen passen) die in einem physischen Modul gesetzt ist. Damit wird definiert, mit welchen logischen Modulen das physikalische Modul  kommunizieren kann. &lt;br /&gt;
&lt;br /&gt;
Eine Client-Liste ist eine Zeichenkette, welche aus allen logischen Modulnamen besteht. Die einzelnen Namen werden durch einen Doppelpunkt getrennt. Anstatt kompletter Modulnamen können auch reguläre Ausdrücke verwendet werden, die auf mehrere Modulnamen passen (z.B. &amp;lt;code&amp;gt;CUL_.*&amp;lt;/code&amp;gt; um die logischen Module CUL_HM, CUL_MAX, etc. zu verwenden).&lt;br /&gt;
&lt;br /&gt;
Bsp.: Die Client-Liste von dem Modul CUL lautet daher wie folgt:&lt;br /&gt;
{|&lt;br /&gt;
!&lt;br /&gt;
 FS20:FHT.*:KS300:USF1000:BS:HMS:CUL_EM:CUL_WS:CUL_FHTTK:CUL_HOERMANN:ESA2000:CUL_IR:CUL_TX:Revolt:IT:UNIRoll:SOMFY:STACKABLE_CC:CUL_RFR:CUL_TCM97001:CUL_REDIRECT&lt;br /&gt;
|}&lt;br /&gt;
Alle hier aufgelisteten Module können über das Modul CUL Daten empfangen bzw. senden.&lt;br /&gt;
&lt;br /&gt;
Die Client-Liste hat generell folgende Funktion:&lt;br /&gt;
* Die Funktion [[DevelopmentModuleAPI#Dispatch|Dispatch()]] prüft nur Module, welche in der Client-Liste enthalten sind, ob diese die Nachricht verarbeiten können (Prüfung via [[#Der Match-Ausdruck|Match-Ausdruck]])&lt;br /&gt;
* Die Funktion [[DevelopmentModuleAPI#AssignIoPort|AssignIoPort()]] prüft anhand sämtlicher Client-Listen in FHEM, welches IO-Gerät für ein logisches Gerät nutzbar ist.&lt;br /&gt;
&lt;br /&gt;
Üblicherweise wird die Client-Liste in der [[#X_Initialize|Initialize]]-Funktion im Modul-Hash gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
	...&lt;br /&gt;
	$hash-&amp;gt;{Clients} = &amp;quot;FS20:KS300:FHT.*&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man kann die Client-Liste jedoch auch pro physikalisches Gerät setzen. Eine gesetzte Client-Liste in einem Gerät hat immer Vorrang vor der Liste im Modul-Hash. Eine gerätespezifische Client-Liste wird dann verwendet, wenn bspw. ein Gerät je nach Konfiguration nur bestimmte logische Module bedienen kann. Bspw. kann ein CUL je nach RF-Einstellungen FS20, uvm. oder nur HomeMatic bedienen. In einem solchen Fall wird die Client-Liste im Geräte-Hash gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$)&lt;br /&gt;
{&lt;br /&gt;
	my ( $hash, $def ) = @_;&lt;br /&gt;
	...&lt;br /&gt;
	$hash-&amp;gt;{Clients} = &amp;quot;CUL_HM&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In vielen Modulen, welche nach dem zweistufigem Konzept arbeiten, beginnt und endet die Client-Liste mit einem Doppelpunkt. Dies ist ein historisches Überbleibsel, da der Prüfmechanismus die Client-Liste früher auf das Vorhandensein von &amp;lt;code&amp;gt;&#039;&#039;&#039;&amp;lt;u&amp;gt;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;:&amp;lt;/font&amp;gt;&amp;lt;/u&amp;gt;&#039;&#039;&#039;&amp;amp;lt;Modulname&amp;amp;gt;&#039;&#039;&#039;&amp;lt;u&amp;gt;&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;:&amp;lt;/font&amp;gt;&amp;lt;/u&amp;gt;&#039;&#039;&#039;&amp;lt;/code&amp;gt; prüfte. Dies ist nun nicht mehr notwendig. Die einzelnen Modulnamen müssen lediglich durch einen Doppelpunkt getrennt werden.&lt;br /&gt;
&lt;br /&gt;
=== Die Match-Liste ===&lt;br /&gt;
{{Randnotiz|RNTyp=Info|RNText=&amp;lt;font color=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;u&amp;gt;&#039;&#039;&#039;ACHTUNG&#039;&#039;&#039;:&amp;lt;/u&amp;gt;&amp;lt;/font&amp;gt;&lt;br /&gt;
Sämtliche regulären Ausdrücke in der Match-Liste werden &amp;quot;case insensitive&amp;quot; überprüft. Das bedeutet, dass Groß-/Kleinschreibung nicht berücksichtigt wird.&lt;br /&gt;
&lt;br /&gt;
Um dennoch in einem regulären Ausdruck auf Groß-/Kleinschreibung zu prüfen, kann man dieses mit dem Modifizierer &amp;lt;code&amp;gt;(?-i)&amp;lt;/code&amp;gt; wieder aktivieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
my %matchListFHEMduino = (&lt;br /&gt;
    ....&lt;br /&gt;
    &amp;quot;5:FHEMduino_PT2262&amp;quot;   =&amp;gt; &amp;quot;^(?-i)IR.*\$&amp;quot;,&lt;br /&gt;
    ....&lt;br /&gt;
    &amp;quot;13:IT&amp;quot;                =&amp;gt; &amp;quot;^(?-i)i......\$&amp;quot;,&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Siehe dazu Forumsbeitrag: {{Link2Forum|Topic=33422}}&lt;br /&gt;
}}&lt;br /&gt;
Die Match-Liste ordnet eine Nachrichtensyntax (regulärer Ausdruck) einem Modulnamen zu und wird in einem physikalischen Modul gesetzt. Sollte eine Nachricht vom physikalischen Gerät empfangen werden, die durch kein geladenes Modul verarbeitet werden kann ([[DevelopmentModuleAPI#Dispatch|Dispatch()]] prüft nur alle bisher geladenen Module aus der [[#Die Client-Liste|Client-Liste]]), so wird über die Match-Liste geprüft, welches Modul diese Nachricht verarbeiten kann. Dieses Modul wird anschließend geladen und die Nachricht durch dieses direkt durch Aufruf der [[#X_Parse|Parse]]-Funktion verarbeitet. In dieser Liste findet mittels regulärem Ausdruck eine Zuordnung der Nachrichtenstruktur zum verarbeitenden logischen Modul statt.&lt;br /&gt;
&lt;br /&gt;
Diese Liste wird ausschließlich in der [[DevelopmentModuleAPI#Dispatch|Dispatch()]]-Funktion verwendet. Sollte keine passendes Modul, welches bereits geladen ist, zur Verarbeitung einer Nachricht gefunden werden, so wird mithilfe der Match-Liste aufgrund der vorliegenden Nachricht das entsprechende Modul ermittelt. Dieses Modul wird dann direkt geladen und die Nachricht wird via [[#X_Parse|Parse]]-Funktion verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Die Match-Liste ist eine Zuordnung von einem Sortierpräfix + Modulname zu einem regulären Ausdruck:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;1:FS20&amp;quot;  =&amp;gt; &amp;quot;^81..(04|0c)..0101a001&amp;quot;,&lt;br /&gt;
    &amp;quot;2:KS300&amp;quot; =&amp;gt; &amp;quot;^810d04..4027a001&amp;quot;,&lt;br /&gt;
    &amp;quot;3:FHT&amp;quot;   =&amp;gt; &amp;quot;^81..(04|09|0d)..(0909a001|83098301|c409c401)..&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Sortierpräfix (&amp;lt;code&amp;gt;&amp;lt;u&amp;gt;1:&amp;lt;/u&amp;gt;&amp;lt;font color=&amp;quot;grey&amp;quot;&amp;gt;FS20&amp;lt;/font&amp;gt;&amp;lt;/code&amp;gt;) dient als Sortierhilfe um so die Reihenfolge der Prüfung festzulegen. Bei der Prüfung wird die Match-Liste mittels sort() nach dem Schlüssel (Sortierpräfix + Modulname) sortiert und die regulären Ausdrücke werden dann nacheinander getestet. Daher sollten die präzisesten Ausdrücke immer zuerst getestet werden, sofern es weniger präzise Ausdrücke in der Match-Liste gibt. Dabei ist zu beachten, dass der Sortierpräfix nicht nach numerischen Regeln sortiert wird, sondern zeichenbasierend.&lt;br /&gt;
&lt;br /&gt;
Üblicherweise wird die Match-Liste in der [[#X_Initialize|Initialize]]-Funktion im Modul-Hash gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
   my ($hash) = @_;&lt;br /&gt;
&lt;br /&gt;
   ...&lt;br /&gt;
&lt;br /&gt;
   $hash-&amp;gt;{MatchList} = { &amp;quot;1:FS20&amp;quot;      =&amp;gt; &amp;quot;^81..(04|0c)..0101a001&amp;quot;,&lt;br /&gt;
                          &amp;quot;2:KS300&amp;quot;     =&amp;gt; &amp;quot;^810d04..4027a001&amp;quot;,&lt;br /&gt;
                          &amp;quot;3:FHT&amp;quot;       =&amp;gt; &amp;quot;^81..(04|09|0d)..(0909a001|83098301|c409c401)..&amp;quot; };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Man kann die Match-Liste, ähnlich wie bei der Client-Liste, auch pro physikalisches Gerät setzen. Dabei hat auch hier die Match-Liste eines Gerätes immer Vorrang vor der Match-Liste aus dem Modul-Hash:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Define($$)&lt;br /&gt;
{&lt;br /&gt;
   my ($hash, $def) = @_;&lt;br /&gt;
&lt;br /&gt;
   ...&lt;br /&gt;
&lt;br /&gt;
   $hash-&amp;gt;{MatchList} = { &amp;quot;1:CUL_HM&amp;quot; =&amp;gt; &amp;quot;^A....................&amp;quot; };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Der Match-Ausdruck ===&lt;br /&gt;
&lt;br /&gt;
Ein Match-Ausdruck wird in einem logischen Modul gesetzt und dient der Prüfung, ob eine Nachricht durch das eigene Modul via [[#X_Parse|Parse]]-Funktion verarbeitet werden kann. Es handelt sich hierbei um einen einzelnen regulären Ausdruck, den FHEM innerhalb der [[DevelopmentModuleAPI#Dispatch|Dispatch()]]-Funktion prüft. Nur wenn eine Nachricht via Dispatch() auf diesen Audruck matcht, wird die Parse-Funktion des eigenen Moduls aufgerufen um die Nachricht zu verarbeiten. &lt;br /&gt;
&lt;br /&gt;
Der Hintergrund, warum man den Aufruf mit einem solchen Ausdruck vorher abprüft, liegt in der Möglichkeit, dass ein physikalisches Modul mehrere unterschiedliche logische Module ansprechen kann. So kann FHEM jedes geladene Modul durch diesen Match-Ausdruck prüfen, ob es diese Nachricht verarbeiten kann. Erst, wenn alle geladenen Module, aufgrund einer Prüfung des Ausdrucks, die Nachricht nicht verarbeiten können, wird via [[#Die_Match-Liste|Match-Liste]] ermittelt, welches Modul geladen werden muss um die Nachricht zu verarbeiten. &lt;br /&gt;
&lt;br /&gt;
Der Match-Ausdruck wird in der [[#X_Initialize|Initialize]]-Funktion zur Verfügung gestellt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
&lt;br /&gt;
	...&lt;br /&gt;
	&lt;br /&gt;
	# Dieses Modul verarbeitet FS20 Nachrichten&lt;br /&gt;
	$hash-&amp;gt;{Match} = &amp;quot;^81..(04|0c)..0101a001&amp;quot;; &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== Die vollständige Implementierung ===&lt;br /&gt;
&lt;br /&gt;
Hier nun eine Zusammenfassung beim zweistufigen Modulkonzept in der jeweiligen Stufe implementiert werden muss, damit die Kommunikation funktioniert.&lt;br /&gt;
&lt;br /&gt;
==== physisches Modul ====&lt;br /&gt;
&lt;br /&gt;
Das physische Modul, welches als Kommunikationsbrücke zwischen der Hardware und logischen Modulen fungieren wird, sollte mindestens folgende Funktionen implementieren:&lt;br /&gt;
&lt;br /&gt;
* [[#X_Initialize|Initialize]]-Funktion - Zum Registrieren des Moduls in FHEM.&lt;br /&gt;
* [[#X_Define|Define]]-Funktion - Zum öffnen der Datenverbindung zur Hardware (IP-Adresse/serielle Schnittstelle/...).&lt;br /&gt;
* [[#X_Read|Read]]-Funktion - Zum Lesen von Daten, welche die Hardware übermittelt.&lt;br /&gt;
* [[#X_Read|Ready]]-Funktion - Zum Wiederaufbau der Verbindung bei Verbindungsabbruch, bzw. Prüfung auf lesbare Daten bei serieller Schnittstelle unter Windows.&lt;br /&gt;
* [[#X_Write|Write]]-Funktion - Zum Senden von Daten, welche logische Module via [[DevelopmentModuleAPI#IOWrite|IOWrite()]] an die Hardware übertragen möchten.&lt;br /&gt;
* [[#X_Undef|Undef]]-Funktion - Schließen der Verbindung zur Hardware beim Löschen via &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt;.&lt;br /&gt;
* [[#X_Shutdown|Shutdown]]-Funktion - Schließen der Verbindung zur Hardware beim Stopp von FHEM via &amp;lt;code&amp;gt;shutdown&amp;lt;/code&amp;gt;.&lt;br /&gt;
* [[#X_DelayedShutdown | DelayedShutdown]]-Funktion - Verzögertes beenden zum Schließen der Verbindung zur Hardware beim Stopp von FHEM via &amp;lt;code&amp;gt;shutdown&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Desweiteren müssen in der [[#X_Initialize|Initialize]]-Funktion folgende Daten bereitgestellt werden:&lt;br /&gt;
&lt;br /&gt;
* [[#Die_Client-Liste|Client-Liste]] - Auflistung aller logischen Module, die über dieses Modul kommunizieren können&lt;br /&gt;
* [[#Die_Match-Liste|Match-Liste]] - Zuordnung von Nachrichtensyntax zu Modul zwecks Autoload-Funktionalität.&lt;br /&gt;
&lt;br /&gt;
==== logisches Modul ====&lt;br /&gt;
&lt;br /&gt;
Das logische Modul, bildet ein einzelnes Gerät ab, über das mit einem physikalisches Modul kommuniziert werden kann. Es sollte mindestens folgende Funktionen implementieren:&lt;br /&gt;
&lt;br /&gt;
* [[#X_Initialize|Initialize]]-Funktion - Zum Registrieren des Moduls in FHEM.&lt;br /&gt;
* [[#X_Define|Define]]-Funktion - Speichern des Definition Pointers (siehe [[#X_Parse|Parse-Funktion]])&lt;br /&gt;
* [[#X_Parse|Parse]]-Funktion - Zum Lesen von Daten, welche die Hardware übermittelt.&lt;br /&gt;
* [[#X_Undef|Undef]]-Funktion - Löschen des Definition Pointers beim Löschen via &amp;lt;code&amp;gt;delete&amp;lt;/code&amp;gt; bzw. &amp;lt;code&amp;gt;rereadcfg&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Desweiteren müssen in der [[#X_Initialize|Initialize]]-Funktion folgende Daten bereitgestellt werden:&lt;br /&gt;
&lt;br /&gt;
* [[#Der_Match-Ausdruck|Match-Ausdruck]] - Prüfausdruck, ob eine Nachricht durch dieses Modul verarbeitet werden kann.&lt;br /&gt;
&lt;br /&gt;
=== Kommunikation von der Hardware bis zu den logischen Modulen ===&lt;br /&gt;
&lt;br /&gt;
Die Gerätedefinition des physischen Moduls öffnet eine Verbindung zur Hardware (z.B. via [[DevIo]]). Die [[#X_Read|Read]]-Funktion wird bei anstehenden Daten aus der Hauptschleife von fhem.pl aufgerufen.&lt;br /&gt;
&lt;br /&gt;
Die Read-Funktion stellt dabei sicher, dass die Daten&lt;br /&gt;
* komplett (in der Regel über einen internen Puffer in &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;) und&lt;br /&gt;
* korrekt (z.B. via Prüfung mittels regulärem Ausdruck)&lt;br /&gt;
sind und ruft die globale Funktion [[DevelopmentModuleAPI#Dispatch|Dispatch()]] mit einer kompletten Nachricht auf.&lt;br /&gt;
&lt;br /&gt;
Die Funktion Dispatch() prüft alle geladenen Module aus der [[#Die_Client-Liste|Client-Liste]] des physikalischen Moduls nach möglichen logischen Modulen zur Verarbeitung. Alle zum Zeitpunkt geladenen Module, die in der Client-Liste aufgeführt sind, werden über den [[#Der_Match-Ausdruck|Match-Ausdruck]] geprüft, ob sie mit der Nachricht etwas anfangen können. Sollte bei einem logischen Modul der Match-Ausdruck passen, so wird die entsprechende [[#X_Parse|Parse]]-Funktion des logischen Moduls aufgerufen. Sofern keine passendes Modul gefunden wurde, um die Nachricht zu verarbeiten, wird in der [[#Die_Match-Liste|Match-Liste]] im Geräte- bzw. Modul-Hash der physischen Gerätedefinition nach dem passenden Modul gesucht. Sollte es darin ein Modul geben, was diese Art von Nachricht verarbeiten kann, so wird versucht dieses Modul zu laden um nun die Nachricht via Parse-Funktion zu verarbeiten. Es erfolgt in diesem Fall keine Vorprüfung durch den Match-Ausdruck.&lt;br /&gt;
&lt;br /&gt;
Durch Dispatch() wird nun die [[#X_Parse|Parse]]-Funktion des gefundenen logischen Moduls aufgerufen. Diese&lt;br /&gt;
* interpretiert die übergebene Nachricht,&lt;br /&gt;
* versucht eine existierende Gerätedefinition in FHEM zu finden (z.B. mittels Definition Pointer), für welche die Nachricht addressiert ist,&lt;br /&gt;
* setzt alle [[#Readings|Readings]] für die gefundene Gerätedefinition via [[DevelopmentModuleAPI#Readings_.2F_Events|readings*update]]()-Funktionen,&lt;br /&gt;
* gibt den Namen der logischen Definition zurück, welche die Nachricht verarbeitet hat.&lt;br /&gt;
&lt;br /&gt;
Sollte keine passende Gerätedefinition für die entsprechende Nachricht existieren (Adresse/ID/Kanal/...), wird der Gerätename &amp;quot;UNDEFINED&amp;quot; inkl. einem passenden &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Statement zurückgegeben, um die Definition durch [[autocreate]] erzeugen zu lassen.&lt;br /&gt;
&lt;br /&gt;
Es findet während der Verarbeitung einer Nachricht durch Dispatch()/Parse-Funktion keine sofortige Eventverarbeitung (via [[DevelopmentModuleAPI#Dispatch|DoTrigger()]]) statt, wenn die [[DevelopmentModuleAPI#Readings_.2F_Events|readings*update]]()-Funktionen verwendet werden.&lt;br /&gt;
(Im Gegensatz zum direkten Aufrufen der readings*update Funktionen ohne vorhergehendes Dispatch() )&lt;br /&gt;
&lt;br /&gt;
Die Funktion Dispatch() triggert das Event-Handling für das von der Parse-Funktion zurückgegebene logische Device selbstständig nach Abschluss der Parse-Funktion.&lt;br /&gt;
&lt;br /&gt;
Optional führt die Funktion Dispatch() eine Überprüfung auf Nachrichtenduplikate beim Einsatz von mehreren IO-Geräten durch. Dazu wird eine implementierte [[#X_Fingerprint|Fingerprint]]-Funktion im physischen oder logischen Modul benötigt. Sollte der Fingerprint einer Nachricht innerhalb einer bestimmten Zeit (globales Attribut &amp;lt;code&amp;gt;dupTimeout&amp;lt;/code&amp;gt;, standardmäßig 500ms) bereits empfangen worden sein, so wird die Nachricht verworfen. Dies ist insbesondere bei funkbasierter Hardware notwendig, wenn mehrere Empfänger die selbe Nachricht empfangen.&lt;br /&gt;
&lt;br /&gt;
=== Kommunikation von den logischen Modulen bis zur Hardware ===&lt;br /&gt;
&lt;br /&gt;
Um von einem logischen Modul eine Nachricht an die Hardware senden zu können, muss zunächst im logischen Gerät ein passenden IO-Gerät ausgewählt sein. Dazu muss die Funktion [[DevelopmentModuleAPI#AssignIoPort|AssignIoPort()]] ein entsprechendes IO-Gerät auswählen und in &amp;lt;code&amp;gt;$hash-&amp;gt;{IODev}&amp;lt;/code&amp;gt; setzen. Dieser Aufruf wird üblicherweise in der [[#X_Define|Define]]-Funktion des logischen Moduls ausgeführt. Erst, wenn ein IO-Gerät ausgewählt wurde, können Daten über das physikalische Gerät an die Hardware übermittelt werden.&lt;br /&gt;
&lt;br /&gt;
Zum Senden von Daten ruft das logische Modul die Funktion [[DevelopmentModuleAPI#IOWrite|IOWrite()]] samt Daten auf. Diese ruft für das entsprechende IO-Gerät die [[#X_Write|Write]]-Funktion auf und übergibt die Daten zum Schreiben an das physikalische Modul. Die Write-Funktion kümmert sich nun um die Übertragung der Daten an die Hardware. &lt;br /&gt;
&lt;br /&gt;
Keine direkten Zugriffe zwischen dem logischen und dem physischen Gerät gibt (d.h. keine direkten Aufrufe von Funktionen, kein direktes Überprüfen von &amp;lt;code&amp;gt;$hash&amp;lt;/code&amp;gt;-Inhalten, ...), so können die Module hintereinander geschaltet werden (z.B. für Routerfunktionen wie bei der [[RFR_CUL|RFR]]-Funktionalität) oder mittels [[FHEM2FHEM]] im RAW-Modus zwei FHEM-Installationen verbunden werden und die logischen Geräte können dennoch kommunizieren.&lt;br /&gt;
&lt;br /&gt;
=== Automatisches Anlegen von logischen Gerätedefinitionen (autocreate) ===&lt;br /&gt;
&lt;br /&gt;
Das logische Modul kann im Rahmen der [[#X_Parse|Parse]]-Funktion eine neue Gerätedefinition anlegen, sofern eine passende Definition nicht existieren sollte. Die Parse-Funktion gibt generell den Namen der logischen Gerätedefinition zurück, für welche die Nachricht verarbeitet wurde. Sollte keine passende Definition gefunden werden, so muss die Parse-Funktion folgenden Rückgabewert liefern (zusammenhängende Zeichenkette):&lt;br /&gt;
&lt;br /&gt;
 UNDEFINED &#039;&#039;&amp;amp;lt;Namensvorschlag&amp;amp;gt;&#039;&#039; &#039;&#039;&amp;amp;lt;Modulname&amp;amp;gt;&#039;&#039; &#039;&#039;&amp;amp;lt;Define-Parameter...&amp;amp;gt;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sollte also bspw. im Rahmen der Parse-Funktion zu Modul X eine Nachricht nicht einer existierenden Gerätedefinition zugeordnet werden können, so muss ein Namensvorschlag erstellt werden der eine eindeutige Komponente wie bspw. eine Adresse/ID/Kanal-Nr enthält. In der Regel wird hier immer der Modulname zusammen mit der eindeutigen Komponente, durch einen Unterstrich getrennt, verwendet (Bsp: &amp;lt;code&amp;gt;X_4834&amp;lt;/code&amp;gt;). Der Modulname ist in der Regel immer der, des eigenen Moduls. In besonderen Fällen kann man hier auch einen abweichenden Modulnamen angeben. Dies wird bspw. bei den [[PanStamp#FHEM-Module.2FDevice_Definition_Files|SWAP-Modulen]] eingesetzt. Als Define-Parameter müssen alle notwendigen Parameter angegeben werden, die beim Aufruf des &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehls notwendig sind, damit eine neu angelegte Gerätedefinition Nachrichten zu dieser eindeutigen Adresse Daten verarbeitet. Dazu muss mind. die eindeutige Adresse mitgegeben werden.&lt;br /&gt;
&lt;br /&gt;
Beispiel für FS20:&lt;br /&gt;
&lt;br /&gt;
 UNDEFINED FS20_0ae42f8 FS20 0ae42 f8&lt;br /&gt;
&lt;br /&gt;
Sobald [[DevelopmentModuleAPI#Dispatch|Dispatch()]] einen solchen Rückgabewert von einer [[#X_Parse|Parse]]-Funktion erhält, wird diese Zeichenkette so wie sie ist via [[DevelopmentModuleAPI#DoTrigger|DoTrigger()]] als Event für die Definition &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt; getriggert.&lt;br /&gt;
&lt;br /&gt;
Sofern der Nutzer das Modul [[autocreate]] verwendet (definiert hat), kümmert sich dieses nun um das Anlegen einer entsprechenden Gerätedefinition. Es lauscht dabei auf generierte Events der Definition &amp;lt;code&amp;gt;global&amp;lt;/code&amp;gt; via [[#X_Notify|Notify]]-Funktion. Der Nutzer kann dabei das Verhalten von autocreate durch entsprechende Parameter beeinflussen.&lt;br /&gt;
&lt;br /&gt;
Das Modul, für welches autocreate eine neue Definition anlegen möchte, kann das Verhalten durch entsprechende Parameter im Modul-Hash beeinflussen. Dabei gilt, dass gesetzte Attribute durch den Nutzer generell Vorrang haben. Die entsprechenden Parameter werden dabei im Rahmen der [[#X_Initialize|Initialize]]-Funktion im Modul-Hash gesetzt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
sub X_Initialize($)&lt;br /&gt;
{&lt;br /&gt;
	my ($hash) = @_;&lt;br /&gt;
 &lt;br /&gt;
	...&lt;br /&gt;
 &lt;br /&gt;
	$hash-&amp;gt;{AutoCreate} = {&amp;quot;X_.*&amp;quot;  =&amp;gt; { ATTR   =&amp;gt; &amp;quot;event-on-change-reading:.* event-min-interval:.*:300&amp;quot;,&lt;br /&gt;
	                                    FILTER =&amp;gt; &amp;quot;%NAME&amp;quot;,&lt;br /&gt;
	                                    GPLOT  =&amp;gt; &amp;quot;temp4hum4:Temp/Hum,&amp;quot;,&lt;br /&gt;
	                                    autocreateThreshold =&amp;gt; &amp;quot;2:140&amp;quot;&lt;br /&gt;
					  }&lt;br /&gt;
	                      };&lt;br /&gt;
			    &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hierbei wird unterhalb von &amp;lt;code&amp;gt;$hash-&amp;gt;{AutoCreate}&amp;lt;/code&amp;gt; eine Liste angelegt, wo einem regulären Ausdruck für einen anzulegenden Definitionsnamen entsprechende Optionen zugeordnet werden. Sobald durch autocreate eine Gerätedefintion angelegt wird, auf den ein hier gelisteter Ausdruck matcht, so werden die zugeordneten Optionen berücksichtigt.&lt;br /&gt;
&lt;br /&gt;
Hier eine Auflistung aller möglichen Optionen und ihrer Bedeutung:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Optionsname !! Beispiel !! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;ATTR&amp;lt;/code&amp;gt;|| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; |  &amp;lt;code&amp;gt;&amp;quot;event-on-change-reading:.* event-min-interval:.*:300&amp;quot;&amp;lt;/code&amp;gt; || Eine Auflistung von Attributen, die nach dem Anlegen einer Definition zusätzlich gesetzt werden. Es handelt sich hierbei um eine Leerzeichen-separierte Liste von Doppelpunkt-getrennten Tupels mit Attributname und -wert.&lt;br /&gt;
&lt;br /&gt;
Für das dargestellte Beispiel bedeutet dies, dass nach dem Anlegen der Definition folgende FHEM-Befehle zusätzlich ausgeführt werden:&lt;br /&gt;
&lt;br /&gt;
 attr &#039;&#039;&amp;amp;lt;Name&amp;amp;gt;&#039;&#039; event-on-change-reading .*&lt;br /&gt;
 attr &#039;&#039;&amp;amp;lt;Name&amp;amp;gt;&#039;&#039; event-min-interval .*:300&lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;FILTER&amp;lt;/code&amp;gt; || style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; |  &amp;lt;code&amp;gt;&amp;quot;%NAME&amp;quot;&amp;lt;/code&amp;gt;|| Sofern in der autocreate-Definiton das Attribut &amp;lt;code&amp;gt;filelog&amp;lt;/code&amp;gt; entsprechend durch den Nutzer gesetzt ist, wird eine zugehörige FileLog-Definition angelegt. Diese Option setzt den dabei benutzten Filter-Regexp, der beim Anlegen der FileLog-Definition gesetzt wird. &lt;br /&gt;
&lt;br /&gt;
Dabei werden folgende Platzhalter durch die entsprechenden Werte der neu angelegten Gerätedefinition ersetzt:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;%NAME&amp;lt;/code&amp;gt; - wird ersetzt durch den Definitionsnamen&lt;br /&gt;
* &amp;lt;code&amp;gt;%TYPE&amp;lt;/code&amp;gt; - wird ersetzt durch den Modulnamen&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; |  &amp;lt;code&amp;gt;GPLOT&amp;lt;/code&amp;gt; || style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&amp;quot;temp4hum4:Temp/Hum,&amp;quot;&amp;lt;/code&amp;gt; || Sofern eine FileLog-Definition angelegt wurde, kann man weiterführend dazu eine passende SVG-Definition erzeugen um Daten aus dem erzeugten FileLog zu visualisieren. Ein typischer Fall sind hierbei Temperatursensoren, wo es sinnvoll sein kann, einen passenden SVG-Plot mit Temperatur/Luftfeuchtigkeit direkt anzulegen.&lt;br /&gt;
&lt;br /&gt;
Es handelt sich hierbei um eine kommaseparierte Auflistung von gplot-Dateinamen und optionalen Label-Texten durch einen Doppelpunkt getrennt. Im genannten Beispiel entspricht &amp;lt;code&amp;gt;temp4hum4&amp;lt;/code&amp;gt; der zu verwendenden GnuPlot-Datei und &amp;lt;code&amp;gt;Temp/Hum&amp;lt;/code&amp;gt; dem zu verwendenden Label ([[SVG]] Attribut &amp;lt;code&amp;gt;label&amp;lt;/code&amp;gt;). Das Label wird auch durch FileLog verwendet als Link-Text zum entsprechenden SVG Plot. Alternativ kann auch nur die entsprechende GnuPlot-Datei anegeben werden ohne Label. Für jede angegebene GnuPlot-Datei wird anschließend eine entsprechende SVG-Definition erzeugt mit der vorher erzeugten FileLog-Definition als Datenquelle.&lt;br /&gt;
&lt;br /&gt;
Der gesamte Inhalt der &amp;lt;code&amp;gt;GPLOT&amp;lt;/code&amp;gt;-Option wird beim Anlegen einer FileLog-Definition dem Attribut &amp;lt;code&amp;gt;logtype&amp;lt;/code&amp;gt; als Wert plus dem Text &amp;lt;code&amp;gt;text&amp;lt;/code&amp;gt; zugewiesen. Daher muss der Inhalt der Option &amp;lt;code&amp;gt;GPLOT&amp;lt;/code&amp;gt; immer mit einem Komma enden. &lt;br /&gt;
&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;autocreateThreshold&amp;lt;/code&amp;gt; || style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;&amp;quot;2:10&amp;quot;&amp;lt;/code&amp;gt; || Definiert, wie viele Aufrufe (im Bsp: &amp;lt;code&amp;gt;2&amp;lt;/code&amp;gt;) von autocreate innerhalb welcher Zeit (im Bsp: &amp;lt;code&amp;gt;10&amp;lt;/code&amp;gt; Sek.) stattfinden müssen, bevor die Gerätedefinition tatsächlich durch autocreate angelegt wird. Dadurch kann das ungewollte Anlegen von Geräten verhindert werden die tatsächlich nicht in Echt existieren. Aufgrund von Funkstörungen kann es durchaus zum ungewollten Anlegen einer Definition kommen. Diese Funktion lässt eine Definition erst zu wenn innerhalb einer vorgegeben Zeit eine Mindestzahl an Nachrichten eintrifft.&lt;br /&gt;
&lt;br /&gt;
Die erste Zahl stellt dabei die Mindestanzahl an Nachrichten dar. Die Zweite Zahl stellt die Zeit in Sekunden dar, in der die Mindestanzahl an Nachrichten erreicht werden muss um eine entsprechende Gerätedefinition anzulegen. &lt;br /&gt;
&lt;br /&gt;
Sofern diese Option nicht gesetzt ist, wird standardmäßig &amp;lt;code&amp;gt;2:60&amp;lt;/code&amp;gt; verwendet.&lt;br /&gt;
&lt;br /&gt;
Diese Option kann durch den Anwender über das Attribut &amp;lt;code&amp;gt;autocreateThreshold&amp;lt;/code&amp;gt; übersteuert werden.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; | &amp;lt;code&amp;gt;noAutocreatedFilelog&amp;lt;/code&amp;gt;|| style=&amp;quot;vertical-align:top; white-space: nowrap;&amp;quot; |  &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;|| Flag. Sofern gesetzt, wird keine FileLog- und ggf. SVG-Definition erzeugt. Selbst wenn der Nutzer durch entsprechende Attribute das Anlegen wünscht. Diese Option ist sinnvoll für Module bzw. Geräte die keine Readings erzeugen.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Ergänzende Hinweise ==&lt;br /&gt;
Die Wahl der vorangestellten Nummer für den Dateinamen eines neuen Moduls hat keine Bedeutung mehr, es sei denn die Nummer ist 99. Module, die mit 99_ beginnen, werden von FHEM automatisch geladen. Module mit einer anderen Nummer nur wenn ein &amp;lt;code&amp;gt;define&amp;lt;/code&amp;gt;-Befehl dafür sorgt, dass das Modul geladen wird.&lt;br /&gt;
&lt;br /&gt;
Wenn ein Modul Initialisierungsdaten benötigt, sollten diese im Modul selbst enthalten sein. Eine zusätzliche Datei oder sogar ein Unterverzeichnis mit mehreren Dateien ist bei FHEM nicht üblich und sollte bei Modulen, die mit FHEM ausgeliefert werden nur in Rücksprache mit Rudolf König angelegt werden, da sie sonst bei einem Update nicht verteilt werden.&lt;br /&gt;
&lt;br /&gt;
== Weitere Informationen ==&lt;br /&gt;
Wenn man weitere Details wissen möchte, ist ein erster sinnvoller Schritt ein Blick in die Datei fhem.pl. Dort sieht man im Perl-Code wie die Module aufgerufen werden, was vorher passiert und was danach. Am Anfang der Datei (ca. ab Zeile 130) findet man beispielsweise eine Liste der globalen Variablen, die den Modulen zur Verfügung stehen sowie Details zu den wichtigen Hashes %modules und %defs. Wer mit Perl noch nicht so gut klar kommt, dem hilft eventuell ein Blick auf die Perldoc Website[http://perldoc.perl.org/] oder in das Perl-Buch seiner Wahl. Auch die FHEM {{Link2CmdRef}} sollte nicht unterschätzt werden. Es stehen oft mehr interessante Details auch für Modulentwickler darin als man zunächst vermuten könnte.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Hello World&amp;quot; Beispiel ==&lt;br /&gt;
&lt;br /&gt;
98_Hello.pm&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;perl&amp;quot;&amp;gt;&lt;br /&gt;
package main;&lt;br /&gt;
use strict;&lt;br /&gt;
use warnings;&lt;br /&gt;
&lt;br /&gt;
my %Hello_gets = (&lt;br /&gt;
	&amp;quot;whatyouwant&amp;quot;	=&amp;gt; &amp;quot;can&#039;t&amp;quot;,&lt;br /&gt;
	&amp;quot;whatyouneed&amp;quot;	=&amp;gt; &amp;quot;try sometimes&amp;quot;,&lt;br /&gt;
	&amp;quot;satisfaction&amp;quot;  =&amp;gt; &amp;quot;no&amp;quot;&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
sub Hello_Initialize($) {&lt;br /&gt;
    my ($hash) = @_;&lt;br /&gt;
&lt;br /&gt;
    $hash-&amp;gt;{DefFn}      = &#039;Hello_Define&#039;;&lt;br /&gt;
    $hash-&amp;gt;{UndefFn}    = &#039;Hello_Undef&#039;;&lt;br /&gt;
    $hash-&amp;gt;{SetFn}      = &#039;Hello_Set&#039;;&lt;br /&gt;
    $hash-&amp;gt;{GetFn}      = &#039;Hello_Get&#039;;&lt;br /&gt;
    $hash-&amp;gt;{AttrFn}     = &#039;Hello_Attr&#039;;&lt;br /&gt;
    $hash-&amp;gt;{ReadFn}     = &#039;Hello_Read&#039;;&lt;br /&gt;
&lt;br /&gt;
    $hash-&amp;gt;{AttrList} =&lt;br /&gt;
          &amp;quot;formal:yes,no &amp;quot;&lt;br /&gt;
        . $readingFnAttributes;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub Hello_Define($$) {&lt;br /&gt;
    my ($hash, $def) = @_;&lt;br /&gt;
    my @param = split(&#039;[ \t]+&#039;, $def);&lt;br /&gt;
    &lt;br /&gt;
    if(int(@param) &amp;lt; 3) {&lt;br /&gt;
        return &amp;quot;too few parameters: define &amp;lt;name&amp;gt; Hello &amp;lt;greet&amp;gt;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    my $hash-&amp;gt;{name}  = $param[0];&lt;br /&gt;
    my $hash-&amp;gt;{greet} = $param[2];&lt;br /&gt;
    &lt;br /&gt;
    return undef;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub Hello_Undef($$) {&lt;br /&gt;
    my ($hash, $arg) = @_; &lt;br /&gt;
    # nothing to do&lt;br /&gt;
    return undef;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub Hello_Get($@) {&lt;br /&gt;
	my ($hash, @param) = @_;&lt;br /&gt;
	&lt;br /&gt;
	return &#039;&amp;quot;get Hello&amp;quot; needs at least one argument&#039; if (int(@param) &amp;lt; 2);&lt;br /&gt;
	&lt;br /&gt;
	my $name = shift @param;&lt;br /&gt;
	my $opt = shift @param;&lt;br /&gt;
	if(!$Hello_gets{$opt}) {&lt;br /&gt;
		my @cList = keys %Hello_gets;&lt;br /&gt;
		return &amp;quot;Unknown argument $opt, choose one of &amp;quot; . join(&amp;quot; &amp;quot;, @cList);&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	if($attr{$name}{formal} eq &#039;yes&#039;) {&lt;br /&gt;
	    return $Hello_gets{$opt}.&#039;, sir&#039;;&lt;br /&gt;
    }&lt;br /&gt;
	return $Hello_gets{$opt};&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub Hello_Set($@) {&lt;br /&gt;
	my ($hash, @param) = @_;&lt;br /&gt;
	&lt;br /&gt;
	return &#039;&amp;quot;set Hello&amp;quot; needs at least one argument&#039; if (int(@param) &amp;lt; 2);&lt;br /&gt;
	&lt;br /&gt;
	my $name = shift @param;&lt;br /&gt;
	my $opt = shift @param;&lt;br /&gt;
	my $value = join(&amp;quot;&amp;quot;, @param);&lt;br /&gt;
	&lt;br /&gt;
	if(!defined($Hello_gets{$opt})) {&lt;br /&gt;
		my @cList = keys %Hello_gets;&lt;br /&gt;
		return &amp;quot;Unknown argument $opt, choose one of &amp;quot; . join(&amp;quot; &amp;quot;, @cList);&lt;br /&gt;
	}&lt;br /&gt;
    $hash-&amp;gt;{STATE} = $Hello_gets{$opt} = $value;&lt;br /&gt;
    &lt;br /&gt;
	return &amp;quot;$opt set to $value. Try to get it.&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub Hello_Attr(@) {&lt;br /&gt;
	my ($cmd,$name,$attr_name,$attr_value) = @_;&lt;br /&gt;
	if($cmd eq &amp;quot;set&amp;quot;) {&lt;br /&gt;
        if($attr_name eq &amp;quot;formal&amp;quot;) {&lt;br /&gt;
			if($attr_value !~ /^yes|no$/) {&lt;br /&gt;
			    my $err = &amp;quot;Invalid argument $attr_value to $attr_name. Must be yes or no.&amp;quot;;&lt;br /&gt;
			    Log 3, &amp;quot;Hello: &amp;quot;.$err;&lt;br /&gt;
			    return $err;&lt;br /&gt;
			}&lt;br /&gt;
		} else {&lt;br /&gt;
		    return &amp;quot;Unknown attr $attr_name&amp;quot;;&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	return undef;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
1;&lt;br /&gt;
&lt;br /&gt;
=pod&lt;br /&gt;
=begin html&lt;br /&gt;
&lt;br /&gt;
&amp;lt;a name=&amp;quot;Hello&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Hello&amp;lt;/h3&amp;gt;&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
    &amp;lt;i&amp;gt;Hello&amp;lt;/i&amp;gt; implements the classical &amp;quot;Hello World&amp;quot; as a starting point for module development. &lt;br /&gt;
    You may want to copy 98_Hello.pm to start implementing a module of your very own. See &lt;br /&gt;
    &amp;lt;a href=&amp;quot;http://wiki.fhem.de/wiki/DevelopmentModuleIntro&amp;quot;&amp;gt;DevelopmentModuleIntro&amp;lt;/a&amp;gt; for an &lt;br /&gt;
    in-depth instruction to your first module.&lt;br /&gt;
    &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
    &amp;lt;a name=&amp;quot;Hellodefine&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
    &amp;lt;b&amp;gt;Define&amp;lt;/b&amp;gt;&lt;br /&gt;
    &amp;lt;ul&amp;gt;&lt;br /&gt;
        &amp;lt;code&amp;gt;define &amp;amp;lt;name&amp;amp;gt; Hello &amp;amp;lt;greet&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        Example: &amp;lt;code&amp;gt;define HELLO Hello TurnUrRadioOn&amp;lt;/code&amp;gt;&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        The &amp;quot;greet&amp;quot; parameter has no further meaning, it just demonstrates&lt;br /&gt;
        how to set a so called &amp;quot;Internal&amp;quot; value. See &amp;lt;a href=&amp;quot;http://fhem.de/commandref.html#define&amp;quot;&amp;gt;commandref#define&amp;lt;/a&amp;gt; &lt;br /&gt;
        for more info about the define command.&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;br&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;a name=&amp;quot;Helloset&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
    &amp;lt;b&amp;gt;Set&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
    &amp;lt;ul&amp;gt;&lt;br /&gt;
        &amp;lt;code&amp;gt;set &amp;amp;lt;name&amp;amp;gt; &amp;amp;lt;option&amp;amp;gt; &amp;amp;lt;value&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        You can &amp;lt;i&amp;gt;set&amp;lt;/i&amp;gt; any value to any of the following options. They&#039;re just there to &lt;br /&gt;
        &amp;lt;i&amp;gt;get&amp;lt;/i&amp;gt; them. See &amp;lt;a href=&amp;quot;http://fhem.de/commandref.html#set&amp;quot;&amp;gt;commandref#set&amp;lt;/a&amp;gt; &lt;br /&gt;
        for more info about the set command.&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        Options:&lt;br /&gt;
        &amp;lt;ul&amp;gt;&lt;br /&gt;
              &amp;lt;li&amp;gt;&amp;lt;i&amp;gt;satisfaction&amp;lt;/i&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
                  Defaults to &amp;quot;no&amp;quot;&amp;lt;/li&amp;gt;&lt;br /&gt;
              &amp;lt;li&amp;gt;&amp;lt;i&amp;gt;whatyouwant&amp;lt;/i&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
                  Defaults to &amp;quot;can&#039;t&amp;quot;&amp;lt;/li&amp;gt;&lt;br /&gt;
              &amp;lt;li&amp;gt;&amp;lt;i&amp;gt;whatyouneed&amp;lt;/i&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
                  Defaults to &amp;quot;try sometimes&amp;quot;&amp;lt;/li&amp;gt;&lt;br /&gt;
        &amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;a name=&amp;quot;Helloget&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
    &amp;lt;b&amp;gt;Get&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
    &amp;lt;ul&amp;gt;&lt;br /&gt;
        &amp;lt;code&amp;gt;get &amp;amp;lt;name&amp;amp;gt; &amp;amp;lt;option&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        You can &amp;lt;i&amp;gt;get&amp;lt;/i&amp;gt; the value of any of the options described in &lt;br /&gt;
        &amp;lt;a href=&amp;quot;#Helloset&amp;quot;&amp;gt;paragraph &amp;quot;Set&amp;quot; above&amp;lt;/a&amp;gt;. See &lt;br /&gt;
        &amp;lt;a href=&amp;quot;http://fhem.de/commandref.html#get&amp;quot;&amp;gt;commandref#get&amp;lt;/a&amp;gt; for more info about &lt;br /&gt;
        the get command.&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;br&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    &amp;lt;a name=&amp;quot;Helloattr&amp;quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;br /&gt;
    &amp;lt;b&amp;gt;Attributes&amp;lt;/b&amp;gt;&lt;br /&gt;
    &amp;lt;ul&amp;gt;&lt;br /&gt;
        &amp;lt;code&amp;gt;attr &amp;amp;lt;name&amp;amp;gt; &amp;amp;lt;attribute&amp;amp;gt; &amp;amp;lt;value&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        See &amp;lt;a href=&amp;quot;http://fhem.de/commandref.html#attr&amp;quot;&amp;gt;commandref#attr&amp;lt;/a&amp;gt; for more info about &lt;br /&gt;
        the attr command.&lt;br /&gt;
        &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
        Attributes:&lt;br /&gt;
        &amp;lt;ul&amp;gt;&lt;br /&gt;
            &amp;lt;li&amp;gt;&amp;lt;i&amp;gt;formal&amp;lt;/i&amp;gt; no|yes&amp;lt;br&amp;gt;&lt;br /&gt;
                When you set formal to &amp;quot;yes&amp;quot;, all output of &amp;lt;i&amp;gt;get&amp;lt;/i&amp;gt; will be in a&lt;br /&gt;
                more formal language. Default is &amp;quot;no&amp;quot;.&lt;br /&gt;
            &amp;lt;/li&amp;gt;&lt;br /&gt;
        &amp;lt;/ul&amp;gt;&lt;br /&gt;
    &amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=end html&lt;br /&gt;
&lt;br /&gt;
=cut&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der HTML-Code zwischen den Tags &amp;lt;code&amp;gt;=pod&amp;lt;/code&amp;gt; und &amp;lt;code&amp;gt;=cut&amp;lt;/code&amp;gt; dient zur Generierung der commandref.html. Der HTML-Inhalt wird automatisch beim Verteilen des Moduls im Rahmen des Update-Mechanismus aus jedem Modul extrahiert und daraus die Commandref in verschiedenen Sprachen erstellt. Eine detaillierte Beschreibung wie ein Commandref-Abschnitt in einem Modul definiert wird, siehe: [[Guidelines zur Dokumentation]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Development]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=33079</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=33079"/>
		<updated>2020-04-19T15:39:18Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* PIUSV+ und Raspberry Pi 4 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben (https://www.reichelt.de/raspberry-pi-usv-rpi-usv-p169883.html).&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung, Akku-Spannung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss das I2C-Interface Modul „RPII2C“ zuvor definiert werden (siehe Commandref).&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;pl&amp;quot;&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $s_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung=&amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	if ($usv_meldung ne &amp;quot;&amp;quot;) {&lt;br /&gt;
		fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+) |/is;&lt;br /&gt;
$s_pi = $1;&lt;br /&gt;
if ($s_pi != 0xFF)&lt;br /&gt;
	{&lt;br /&gt;
	$status=$s_pi &amp;amp; 0x3F;&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&amp;lt;br&amp;gt;&lt;br /&gt;
Der Wert des Statusregister wird hier als Dezimalzahl dargestellt und muss zur weiteren Verarbeitung ggf. noch binär ausdekodiert werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== PIUSV+ und Raspberry Pi 4 ==&lt;br /&gt;
Obwohl die PIUSV+ nur 2 A liefern kann, ist der Betrieb mit einem Raspberry Pi 4 durchaus möglich, sofern auf dem Raspberry hauptsächlich der FHEM-Server und keine sonstige hochperformante Software installiert ist.&lt;br /&gt;
Bei einer FHEM-Beispielinstallation (Raspian Buster, FHEM 6.0) mit USB-SSD-Platte (32GB), 3x USB/232-Konverter, einem Homematic-Sender/Empfängermodul (HM-MOD-PRI-PCB) und Nutzung der 1-Wire-, I²C- und 2xGPIO-Schnittstellen am 40pol. Pfostenverbinder beträgt der 5V-Versorgungsstrom ca. 0,9A (entspricht 4,5W).&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;br /&gt;
[[Kategorie:Raspberry Pi]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=33078</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=33078"/>
		<updated>2020-04-19T14:30:22Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* PIUSV+ und Raspberry Pi 4 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben (https://www.reichelt.de/raspberry-pi-usv-rpi-usv-p169883.html).&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung, Akku-Spannung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss das I2C-Interface Modul „RPII2C“ zuvor definiert werden (siehe Commandref).&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;pl&amp;quot;&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $s_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung=&amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	if ($usv_meldung ne &amp;quot;&amp;quot;) {&lt;br /&gt;
		fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+) |/is;&lt;br /&gt;
$s_pi = $1;&lt;br /&gt;
if ($s_pi != 0xFF)&lt;br /&gt;
	{&lt;br /&gt;
	$status=$s_pi &amp;amp; 0x3F;&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&amp;lt;br&amp;gt;&lt;br /&gt;
Der Wert des Statusregister wird hier als Dezimalzahl dargestellt und muss zur weiteren Verarbeitung ggf. noch binär ausdekodiert werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== PIUSV+ und Raspberry Pi 4 ==&lt;br /&gt;
Obwohl die PIUSV+ nur 2 A liefern kann ist der Betrieb mit einem Raspberry Pi 4 durchaus möglich, sofern auf dem Raspberry hauptsächlich der FHEM-Server und keine sonstige hochperformante Software läuft.&amp;lt;br&amp;gt;&lt;br /&gt;
Bei einer FHEM-Beispielinstallation (Raspian Buster, FHEM 6.0) mit USB-SSD-Platte (32GB), 3x USB/232-Konverter, ein Homematic-Sender/Empfängermodul (HM-MOD-PRI-PCB) und ein paar Schnittstellen über den 40pol. Pfostenverbinder (1-Wire, I²C- und 2 GPIOs) beträgt der 5V-Versorgungsstrom ca. 0,9A (entspricht 4,5W).&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;br /&gt;
[[Kategorie:Raspberry Pi]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=33077</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=33077"/>
		<updated>2020-04-19T14:23:07Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben (https://www.reichelt.de/raspberry-pi-usv-rpi-usv-p169883.html).&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung, Akku-Spannung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss das I2C-Interface Modul „RPII2C“ zuvor definiert werden (siehe Commandref).&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $s_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung=&amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	if ($usv_meldung ne &amp;quot;&amp;quot;) {&lt;br /&gt;
		fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+) |/is;&lt;br /&gt;
$s_pi = $1;&lt;br /&gt;
if ($s_pi != 0xFF)&lt;br /&gt;
	{&lt;br /&gt;
	$status=$s_pi &amp;amp; 0x3F;&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&amp;lt;br&amp;gt;&lt;br /&gt;
Der Wert des Statusregister wird hier als Dezimalzahl dargestellt und muss zur weiteren Verarbeitung ggf. noch binär ausdekodiert werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== PIUSV+ und Raspberry Pi 4 ==&lt;br /&gt;
Obwohl die PIUSV+ nur 2 A liefern kann ist der Betrieb mit einem Raspberry Pi 4 durchaus möglich, sofern auf dem Raspberry hauptsächlich der FHEM-Server und keine sonstige hochperformante-Software läuft.&amp;lt;br&amp;gt;&lt;br /&gt;
Eine FHEM-Beispielinstallation (Raspian Buster, FHEM 6.0) mit USB-SSD-Platte (32GB), 3x USB/232-Konverter, ein Homematic-Sender/Empfängermodul (HM-MOD-PRI-PCB) und ein paar Schnittstellen über den 40pol. Pfostenverbinder (1-Wire, I²C- und 2 GPIOs) beträg der 5V-Versorgungsstrom ca. 0,9A (entspricht 4,5W).&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;br /&gt;
[[Kategorie:Raspberry Pi]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=HMinfo&amp;diff=33072</id>
		<title>HMinfo</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=HMinfo&amp;diff=33072"/>
		<updated>2020-04-15T20:26:38Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Integritätsprüfungen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Modul&lt;br /&gt;
|ModPurpose=Übersicht über alle HomeMatic Geräte&lt;br /&gt;
|ModType=h&lt;br /&gt;
|ModCmdRef=HMinfo&lt;br /&gt;
|ModForumArea=HomeMatic&lt;br /&gt;
|ModTechName=98_HMinfo.pm&lt;br /&gt;
|ModOwner=martinp876 ({{Link2FU|251|martinp876}} / [[Benutzer Diskussion:Martinp876|Wiki]])&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;HMInfo&#039;&#039;&#039; ist ein Modul, das einen Überblick über alle definierten [[HomeMatic]] Geräte gibt. Es bietet Funktionen zur Übersicht, Kontrolle, Archivierung  und, begrenzt, zur Programmierung der HomeMatic Komponenten. Somit soll es eine Hilfestellung bei Konfiguration und Fehlerbehandlung geben. &lt;br /&gt;
 &lt;br /&gt;
== Definition == &lt;br /&gt;
HMInfo wird erstellt / angelegt mit dem Befehl&lt;br /&gt;
:&amp;lt;code&amp;gt;define hm HMinfo&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Danach können alle Funktionen aufgelistet werden mit&lt;br /&gt;
:&amp;lt;code&amp;gt;get hm help&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Integritätsprüfungen ==&lt;br /&gt;
Zu berücksichtigen bei allen Funktionen von HMInfo ist die Tatsache, dass die Prüfung jeweils auf den innerhalb von FHEM vorliegenden Informationen passiert. Erste Korrekturmaßnahme ist daher immer von den betroffenen Devices die Informationen mit einem set &amp;lt;Device&amp;gt; getConfig zu aktualisieren. Dabei ist darüber hinaus zu berücksichtigen, dass entsprechend der konfigurierten Kommunikationsmethode (z.B. config) einige Devices erst nach einer gewissen Zeit oder nach Betätigen der Anlerntaste die Informationen als Antwort zurückliefern.&lt;br /&gt;
&lt;br /&gt;
Befehle, um die Gültigkeit von verschiedenen HomeMatic Eigenschaften zu überprüfen:&lt;br /&gt;
&lt;br /&gt;
=== peerCheck ===&lt;br /&gt;
Mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;get hm peerCheck&amp;lt;/code&amp;gt;&lt;br /&gt;
wird der Zustand der Peerings überprüft, d.h., ob alle [[Peering (HomeMatic)|Peerings]] auch beidseitig sind. Mögliche Meldungen, die eine Überarbeitung und/oder Korrektur von Definitionen erforderlich machen können:&lt;br /&gt;
;peer not verified. Check that peer is set on both sides &lt;br /&gt;
:ausgegebener Wert (z.B.): actorChan p:switchChan&lt;br /&gt;
:erforderliche Korrekturmaßnahme: Erneutes setzen des Links und Sicherstellen, dass das Kommando das entsprechende Device auch erreicht hat (s.o., ggf. bei Bedarf die Anlerntaste betätigen).&lt;br /&gt;
&lt;br /&gt;
=== regCheck ===&lt;br /&gt;
Mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;get hm regCheck&amp;lt;/code&amp;gt;&lt;br /&gt;
wird überprüft, ob alle Register korrekt gelesen wurden. Mögliche Meldungen:&lt;br /&gt;
;missing register list &lt;br /&gt;
:ausgegebener Wert (z.B.): &amp;lt;code&amp;gt;dev01Ch01:  RegL_01: &amp;lt;/code&amp;gt;&lt;br /&gt;
:erforderliche Korrekturmaßnahme: &amp;lt;code&amp;gt;set dev01Ch01 getConfig&amp;lt;/code&amp;gt;&lt;br /&gt;
:oder &amp;lt;code&amp;gt;device01Ch01:	.RegL_03:sensor01Ch01,.RegL_03:sensor01Ch02&amp;lt;/code&amp;gt;&lt;br /&gt;
:erforderliche Korrekturmaßnahme: Deutet darauf hin, dass nicht alle Informationen aus einem Device gelesen wurden. Ein set &amp;lt;Device&amp;gt; getConfig sollte alle Register auslesen. Sicherstellen, dass das Kommando zum Auslesen das entsprechende Device auch erreicht und eine Antwort geliefert hat (s.o., ggf. bei Bedarf die Anlerntaste betätigen).&lt;br /&gt;
;Register changes pending &lt;br /&gt;
:ausgegebener Wert (z.B.): &amp;lt;code&amp;gt;sensor01Ch01&amp;lt;/code&amp;gt;&lt;br /&gt;
:erforderliche Korrekturmaßnahme: Ein set &amp;lt;Device&amp;gt; getConfig sollte alle Register auslesen. Sicherstellen, dass das Kommando das entsprechende Device auch erreicht und eine Antwort geliefert hat (s.o., ggf. bei Bedarf die Anlerntaste betätigen).&lt;br /&gt;
&lt;br /&gt;
=== configCheck ===&lt;br /&gt;
Mit dem Befehl &lt;br /&gt;
:&amp;lt;code&amp;gt;get hm configCheck&amp;lt;/code&amp;gt; werden die Befehle &#039;&#039;&#039;peerCheck&#039;&#039;&#039; und &#039;&#039;&#039;regCheck&#039;&#039;&#039; ausgeführt. Zusätzlich können noch Ergebnisse auftauchen wie&lt;br /&gt;
;PairedTo mismatch to IODev&lt;br /&gt;
:ausgegebener Wert (z.B.): &amp;lt;code&amp;gt;sensor01Ch01 paired:0x000000 IO attr: xxxxxx.&amp;lt;/code&amp;gt;&lt;br /&gt;
:erforderliche Korrekturmaßnahme: IODevice in den hmPairForSec Modus versetzen, Pairing-Modus am Device aktivieren und dadurch das pairing wiederholen. Ein Anschließendes set &amp;lt;Device&amp;gt; getConfig kann nicht schaden. Sicherstellen, dass das Kommando zum Auslesen das entsprechende Device auch erreicht und eine Antwort geliefert hat (s.o., ggf. bei Bedarf die Anlerntaste betätigen).&lt;br /&gt;
&lt;br /&gt;
== Anzeigen zur Übertragungssituation ==&lt;br /&gt;
===RSSI ===&lt;br /&gt;
;&amp;lt;code&amp;gt;get hm rssi [&amp;lt;filter&amp;gt;]&amp;lt;/code&amp;gt;&lt;br /&gt;
:Erzeugt eine Tabelle aller RSSI Werte.&lt;br /&gt;
;&amp;lt;code&amp;gt;set hm clear [&amp;lt;filter&amp;gt;] rssi&amp;lt;/code&amp;gt;&lt;br /&gt;
:setzt die RSSI Werte aller devices gemäß filter zurück. Eine neue Messung kann beginnen&lt;br /&gt;
&lt;br /&gt;
===protoEvents ===&lt;br /&gt;
;&amp;lt;code&amp;gt;get hm protoEvents [&amp;lt;filter&amp;gt;][short|long] &amp;lt;/code&amp;gt;&lt;br /&gt;
Siehe [[HMinfo Protokoll]]&lt;br /&gt;
:Es wird eine Tabelle mit allen wichtigen Ereignissen zur Datenübertragung erzeugt. Dies beinhaltet Wiederholungen sowie Übertragungsfehler. &lt;br /&gt;
&amp;lt;code&amp;gt;short&amp;lt;/code&amp;gt; ist eine Fassung ohne Zeitstempel und lässt sich besser am Bildschirm darstellen.&lt;br /&gt;
Ausserdem kann man sehen, welche Abfragen noch in der Queue sind, z.B. durch &amp;lt;code&amp;gt;autoReadReg&amp;lt;/code&amp;gt; erzeugt. &lt;br /&gt;
Die Zustände aller für HM zuständigen IOs sind beinhaltet. &lt;br /&gt;
Alles in allem ist hier ein kompletter Überblick zur Kommunikation zu sehen. Der Befehl&lt;br /&gt;
 set hm clear [&amp;lt;filter&amp;gt;] Protocol&lt;br /&gt;
setzt die Protokoleinträge aller HomeMatic-Geräte gemäß Filter zurück. Das kann gut vor einer Konfigurationsaktion genutzt werden um zu kontrollieren, ob Fehler aufgetreten sind.&amp;lt;br&amp;gt;&lt;br /&gt;
Für tieferes Verständnis siehe [[HMinfo Protokoll]]&lt;br /&gt;
&lt;br /&gt;
===msgStat===&lt;br /&gt;
;&amp;lt;code&amp;gt;set hm msgStat &amp;lt;/code&amp;gt;&lt;br /&gt;
:Statistic der Übertragenen Messages insgesamt. Es gibt eine Tabelle über die letzten 24h und eine über die letzte Woche. &lt;br /&gt;
&lt;br /&gt;
== Speichern von Konfigurationen==&lt;br /&gt;
HMInfo speichert Konfigurationen der Geräte in Files. Mit dem Attribut configDir kann man ein Verzeichnis festlegen, in das alles geschrieben wird.&lt;br /&gt;
&lt;br /&gt;
=== saveConfig===&lt;br /&gt;
[[Peering (HomeMatic)|Peers]] und Register werden in eine Datei geschrieben. Die Daten kann man ggf. wieder in ein Gerät oder ein Austauschgerät schreiben. Die Speicherung erfolgt kumulativ, man kann alles in eine Datei schreiben. &lt;br /&gt;
:&amp;lt;code&amp;gt;set hm saveConfig [&amp;lt;filter&amp;gt;] [&amp;lt;file&amp;gt;] &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== archConfig ===&lt;br /&gt;
Arbeitet prinzipiell wie saveConfig. Es werden jedoch nur vollständige Registersätze gespeichert, was einen höheren Level an Sicherheit der Dateninhalte gewährt.  &lt;br /&gt;
:&amp;lt;code&amp;gt;set hm archConfig [-a] [&amp;lt;file&amp;gt;] &amp;lt;/code&amp;gt;&lt;br /&gt;
Mit dem &#039;&#039;&#039;Attribut autoArchive&#039;&#039;&#039; kann man einstellen, dass automatisch nach erfolgreichem Lesen einer Device-Konfiguration diese archiviert wird. &lt;br /&gt;
Das Speichern erfolgt kumulativ. Ab einer Dateigröße von 1MB wird gepurged, also alles bis auf den neusten Eintrag jeder Entity gelöscht.  &lt;br /&gt;
&lt;br /&gt;
Um eine Konfiguration zu sichern, sollte eine Kopie des Archivs gemacht werden. Das Archiv wird bei Gelegenheit überschrieben. &lt;br /&gt;
&lt;br /&gt;
Template erstellen:&lt;br /&gt;
:&amp;lt;code&amp;gt;set hm saveConfig -f ^meinDevice$ &amp;lt;myTemplateFile&amp;gt; &amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== loadConfig ===&lt;br /&gt;
;&amp;lt;code&amp;gt;set hm loadConfig [&amp;lt;filter&amp;gt;] [&amp;lt;filename&amp;gt;] &amp;lt;/code&amp;gt;&lt;br /&gt;
:Liest die Registerwerte, die für eine Entity in einem File gespeichert sind, zurück in die Readings. Sollten die Register schon in FHEM vorhanden sein, wird &#039;&#039;&#039;nicht&#039;&#039;&#039; überschrieben. &lt;br /&gt;
Sinn macht dies beispielsweise für remotes, die nicht automatisch gelesen werden sollen. Man kann somit nach einem system-reboot die Register &amp;quot;rekonstruieren&amp;quot; und wieder darstellen. &lt;br /&gt;
Es liegt im ermessen des User, eine bekannt aktuelle Version der Register einzulesen. &lt;br /&gt;
&lt;br /&gt;
=== purgeConfig===&lt;br /&gt;
;&amp;lt;code&amp;gt;set hm purgeConfig [&amp;lt;filename&amp;gt;] &amp;lt;/code&amp;gt;&lt;br /&gt;
:Löscht alle älteren Datensätze in einem File.&lt;br /&gt;
&lt;br /&gt;
== Konfigurationen bearbeiten ==&lt;br /&gt;
=== Templates ===&lt;br /&gt;
HMInfo erlaubt das Erstellen und Nutzen von Templates. Das sind Schablonen, die das Setzen von Registern abstrahieren und auf eine höhere Ebene heben. So kann man das Setzen der Konfiguration eines Aktors beispielsweise um mit einem Bewegungsmelder zusammen zu arbeiten in einem Kommando zusammenfassen.&lt;br /&gt;
Faktisch setzt das Template also eine Gruppe von Registern auf einmal.&lt;br /&gt;
&lt;br /&gt;
====templateList ====&lt;br /&gt;
Die vorhandenen templates kann man mit templateList sehen. &lt;br /&gt;
  get hm templateList&lt;br /&gt;
  &lt;br /&gt;
  SwOnCond         params:level cond               Info:switch: execute only if condition [geLo|ltLo] level is below limit&lt;br /&gt;
  SwToggle         params:                         Info:Switch: toggle on trigger&lt;br /&gt;
  autoOff          params:time                     Info:staircase - auto off after &amp;lt;time&amp;gt;, extend time with each trigger&lt;br /&gt;
  motionOnDim      params:ontime brightness        Info:Dimmer: on for time if MDIR-brightness below level&lt;br /&gt;
  motionOnSw       params:ontime brightness        Info:Switch: on for time if MDIR-brightness below level&lt;br /&gt;
Die Liste der verfügbaren Tempaltes, deren Parameter falls nötig und eine kurze Info, was das Template bewirken soll&lt;br /&gt;
&lt;br /&gt;
  get hm templateList autoOff&lt;br /&gt;
&lt;br /&gt;
  autoOff          params:time                     Info:staircase - auto off after &amp;lt;time&amp;gt;, extend time with each trigger&lt;br /&gt;
    ActionType       :jmpToTarget&lt;br /&gt;
    OffTime          :111600&lt;br /&gt;
    OnTime           :time&lt;br /&gt;
    SwJtDlyOff       :dlyOn&lt;br /&gt;
    SwJtDlyOn        :no&lt;br /&gt;
    SwJtOff          :dlyOn&lt;br /&gt;
    SwJtOn           :on&lt;br /&gt;
Ein templateList auf ein einzelnes Template zeigt im Detail, was das Template verändern wird.&lt;br /&gt;
&lt;br /&gt;
====templateSet ====&lt;br /&gt;
Um ein Template auf einen Aktor anzuwenden,muss man den Bereich wählen, auf den er angewendet werden soll. Je nach template kann das die Gruppe der Register zu einem [[Peering (HomeMatic)|Peer]], zu short oder long eines Peer oder Register ohne peer sein. &lt;br /&gt;
  set hm templateSet &amp;lt;entity&amp;gt; &amp;lt;templateName&amp;gt; &amp;lt;peer:[long|short]&amp;gt; [&amp;lt;param1&amp;gt; ...] &lt;br /&gt;
  set hm templateSet Licht1 autoOff FB1_Btn2:short 10&lt;br /&gt;
  set hm templateSet Licht1 SwOn FB1_Btn2:long&lt;br /&gt;
  set hm templateSet Licht1 SwOff FB1_Btn2:short&lt;br /&gt;
  set hm templateSet Licht1 SwOnOff FB1_Btn2:both&lt;br /&gt;
  set hm templateSet LichtDev setHost 0&lt;br /&gt;
Licht1 soll, wenn ein kurzer Trigger von FB1_Btn2 kommt für 10 sec eingeschaltet werden, dann ausgehen (Treppenhausfunktion). Kommt aber ein langer Tastendruck wird das Licht dauerhaft eingeschaltet. &lt;br /&gt;
  set hm templateSet Licht1 motionOnSw MD1:short 30 20&lt;br /&gt;
Der Switch Aktor Licht1 soll mit einem Bewegungsmelder betrieben werden. Der Bewegungsmelder sendet keine &#039;langen&#039; Trigger sondern nur kurze. Im Beispiel wird Licht1 für 30 Sekunden eingeschaltet, wenn der Bewegungsmelder einen Trigger sendet UND es dunkler ist als &amp;quot;20&amp;quot; (Brightness level).&lt;br /&gt;
&lt;br /&gt;
====templateDef ====&lt;br /&gt;
Neben den vorbereiteten Templates kann der User eigene definieren oder von anderen Usern sich Templates geben lassen. Die Definition von Templates ist für erfahrene User gedacht, im Gegensatz zur Nutzung eines Templates mit set - das ist für Anfänger gedacht. Man kann sein template manuell definieren oder ein bekanntes Device als Muster nutzen (fromMaster). Ein Template kann nur Gruppen von Registern setzen, nicht alle Register eines Device. Um die Gruppen anzusprechen muss man &amp;quot;peer&amp;quot; wie folgt setzen:&lt;br /&gt;
  0            Register ohne peer&lt;br /&gt;
  &amp;lt;peer&amp;gt;:both  Register eines peers&lt;br /&gt;
  &amp;lt;peer&amp;gt;:short Register eines peers nur Short&lt;br /&gt;
  &amp;lt;peer&amp;gt;:long  Register eines peers nur Long&lt;br /&gt;
setzen.&lt;br /&gt;
Man kann das template &amp;quot;dynamisch&amp;quot; gestalten, indem man einzelne Register beim templateSet übergibt. &lt;br /&gt;
Erst einmal statische Templates. Param ist hier &amp;quot;0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
  set hm templateDef &amp;lt;templateName&amp;gt; &amp;lt;param1[:&amp;lt;param2&amp;gt;...]&amp;gt; &amp;lt;description&amp;gt; &amp;lt;reg1&amp;gt;:&amp;lt;val1&amp;gt; [&amp;lt;reg2&amp;gt;:&amp;lt;val2&amp;gt;] ... &lt;br /&gt;
&lt;br /&gt;
  set hm templateDef t1 0 &amp;quot;TP1&amp;quot; OnTime:10 OffTime:20 OnDly:0 &lt;br /&gt;
&lt;br /&gt;
  set hm templateDef t1 fromMaster &amp;lt;entity&amp;gt; 0 &lt;br /&gt;
  set hm templateDef t2 fromMaster &amp;lt;entity&amp;gt; &amp;lt;peer&amp;gt;:both &lt;br /&gt;
  set hm templateDef t3 fromMaster &amp;lt;entity&amp;gt; &amp;lt;peer&amp;gt;:short&lt;br /&gt;
  set hm templateDef t4 fromMaster &amp;lt;entity&amp;gt; &amp;lt;peer&amp;gt;:long&lt;br /&gt;
&lt;br /&gt;
  set hm templateDef t4 fromMaster LichtWz remoteBtn1:long&lt;br /&gt;
&lt;br /&gt;
Dynamische Templates haben eine Parameterliste (bis zu 9) &amp;lt;param1[:&amp;lt;param2&amp;gt;...]&amp;gt;. Diese werden als p0 bis p8 genutzt - der Name ist dabei egal, er dient dem User also Hilfe beim templateList&lt;br /&gt;
 &lt;br /&gt;
  set hm templateDef myTemplate anzeit:auszeit &amp;quot;licht schaltet ständig an und aus&amp;quot; OnTime:p0 OffTime:p1 OnDly:0&lt;br /&gt;
&lt;br /&gt;
  set hm templateDef myAutoOff AnZeit &amp;quot;treppenhausschalter&amp;quot; ActionType:jmpToTarget OffTime:unused OnTime:p0 SwJtDlyOff:dlyOn SwJtDlyOn:no SwJtOff:dlyOn SwJtOn:on&lt;br /&gt;
&lt;br /&gt;
Die &amp;quot;Anzeit&amp;quot; ist der erste Parameter, also p0. Der Wert, den man bei Set einträgt wird in OnTime geschrieben. OnTime:p0&lt;br /&gt;
&lt;br /&gt;
Beim Definieren eines Templates wird die Registergültigkeit nicht geprüft. Das kommt beim Set.&lt;br /&gt;
&lt;br /&gt;
Mit dem Parameter del kann ein (fehlerhaftes) Template (hier myTemplate) wieder gelöscht werden. &lt;br /&gt;
&lt;br /&gt;
  set hm templateDef myTemplate del&lt;br /&gt;
&lt;br /&gt;
====templateChk ====&lt;br /&gt;
Template definitionen und zuweisungen (set) kann man mit &lt;br /&gt;
  set hm archConfig&lt;br /&gt;
speichern und mit &lt;br /&gt;
  set hm loadConfig&lt;br /&gt;
mach einem reboot laden. Welche templates einer entity zugewiesen sind kann man mit &lt;br /&gt;
  attr &amp;lt;entity&amp;gt; expert 12&lt;br /&gt;
in den Readings sichtbar machen. Siehe auch templateUsg.&lt;br /&gt;
&lt;br /&gt;
Man kann prüfen, ob ein Aktor/[[Peering (HomeMatic)|Peer]] gemäss einem Template programmiert ist. Sinnvoll ist eine komplette Prüfung aller zugewiesenen templates. Man kann aber auch filtern. &lt;br /&gt;
  get hm templateChk &lt;br /&gt;
  get hm templateChk [&amp;lt;filter&amp;gt;] &lt;br /&gt;
  get hm templateChk [&amp;lt;filter&amp;gt;] &amp;lt;templateName&amp;gt; &amp;lt;peer:[long|short]&amp;gt; [&amp;lt;param1&amp;gt; ...] &lt;br /&gt;
  get hm templateChk -f Rollo RolloHoch self01 5&lt;br /&gt;
Es wird geprüft für alle HM-Komponenten, die &amp;quot;Rollo&amp;quot; im Namen haben (siehe [[Homematic HMInfo#Filter|Filter]]) dem (hoffentlich vorhandenen) template &amp;quot;RolloHoch&amp;quot; verglichen. Geprüft wird nur der Peer &amp;quot;self01&amp;quot;, aber für long UND short.&lt;br /&gt;
  get hm templateChk -f Rollo RolloHoch self01:sort 5&lt;br /&gt;
das selbe, nur für short Einträge&lt;br /&gt;
&lt;br /&gt;
====templateUsg ====&lt;br /&gt;
Gibt eine Liste der zugewiesenen templates zurück&lt;br /&gt;
  get hm templateUsg  &lt;br /&gt;
  get hm templateUsg sortTemplate&lt;br /&gt;
  get hm templateUsg sortPeer&lt;br /&gt;
&lt;br /&gt;
====templateExe ====&lt;br /&gt;
Nach einem loadConfig oder einem templateChk können Fehler erkannt worden sein, die Register entspreche nicht dem Template. Mit diesem Kommando werden alle nicht korrekten Register in die Devices geschrieben. Sollte die Werte stimmen wird nichts gemacht. &lt;br /&gt;
  set hm templateExe&lt;br /&gt;
&lt;br /&gt;
Das Kommando kann also bedenkenlos eingesetzt werden, wenn die templates schon stimmen. Es wird nichts gesendet, keine Funklast erzeugt.&lt;br /&gt;
&lt;br /&gt;
====templateDel ====&lt;br /&gt;
eine zuweisung des Templates kann gelöscht werden&lt;br /&gt;
  set hm templateDel &amp;lt;entity&amp;gt; &amp;lt;template&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Temperaturlisten===&lt;br /&gt;
HMInfo bietet verschiedene Methoden, Temperaturlisten für Thermostate (CC-TC, TC-IT oder RT) zu verwalten und zu nutzen. Siehe hierzu [[HomeMatic HMInfo TempList/Weekplan|Homematic Weekplan]]&lt;br /&gt;
&lt;br /&gt;
=== Registersätze kopieren ===&lt;br /&gt;
HMInfo erlaubt das Kopieren von Register-Listen. Über Register wird ein HM-Gerät eingestellt und die Register sind in Listen gruppiert. Die Reaktion und das Verhalten eines Aktors auf einen Trigger eines Sensors wird in dem Registersatz zu diesem [[Peering (HomeMatic)|Peer]] komplett beschrieben. &lt;br /&gt;
Durch die Möglichkeit einen solchen Registersatz im Device zu kopieren kann man das Verhalten, das man für einen Knopf/Sensor festgelegt hat identisch in einen zweiten kopieren. &lt;br /&gt;
HMInfo geht davon aus, dass die vom Gerät gelesene Konfiguration vor dem Kommando aktuell und komplett ist. &lt;br /&gt;
 set hm cpRegs Licht1:FB3_Btn2 Licht3:FB1_Btn4&lt;br /&gt;
 set hm cpRegs Licht2:FB3_Btn2 Licht2:FB1_Btn4&lt;br /&gt;
 set hm cpRegs Licht4:FB3_Btn2 Licht4:FB5_Btn2&lt;br /&gt;
Die obigen Beispiele bewirken der Reihe nach:&lt;br /&gt;
Duplizieren das Verhalten, das Fernbedienungsknopf 2 der Fernbedienung 3 bei Aktor Licht1 hervorruft auch nach Licht3 für Fernbedienungsknopf4 der Fernbedienung 1.&lt;br /&gt;
Duplizieren das Verhalten, das Fernbedienungsknopf 2 der Fernbedienung 3 bei Aktor Licht2 hervorruft auch nach Licht2 (selber Aktor) für Fernbedienungsknopf4 der Fernbedienung 1.&lt;br /&gt;
&lt;br /&gt;
== Web Einträge und Readings ==&lt;br /&gt;
Readings und Internals von HMInfo bieten eine Zusammenfassung des Zustands aller HM Komponenten. Diese sind in Fehler &#039;&#039;&#039;ERR&#039; , Warnungen &#039;&#039;&#039;W_&#039;&#039;&#039; und Information &#039;&#039;&#039;I_&#039;&#039;&#039; untergliedert. Die Prüfung und Erneuerung der Zähler und Werte wird mit:&#039;&#039;&#039;&lt;br /&gt;
:&amp;lt;code&amp;gt;set hm update &amp;lt;/code&amp;gt;&lt;br /&gt;
erreicht. Mit dem Attribut autoUpdate kann man es automatisch regelmäßig starten.&lt;br /&gt;
&lt;br /&gt;
=== Fehlermeldungen ===&lt;br /&gt;
Als Fehler erkannte Zustände werden in Variablen beginnend mit &#039;&#039;&#039;ERR&#039;&#039;&#039; dargestellt. Erfasste Fehler sind kritische RSSI Werte und Protokoll-/Übertragungsfehler. Ausserdem kann man im Attribut sumERROR eintragen, welche Readings zu einer Fehlermeldung führen sollen. Eingetragen werden:&lt;br /&gt;
Reading:&amp;lt;gutwert&amp;gt;. Wenn ein Reading mit einen anderen als dem &amp;quot;gutwert&amp;quot; gefunden wird, wird dies alarmiert. &lt;br /&gt;
Beispiel: &lt;br /&gt;
:&amp;lt;code&amp;gt;battery:ok &amp;lt;/code&amp;gt;&lt;br /&gt;
hat eine HM Komponente ein Reading &amp;quot;battery&amp;quot; und dieses hat einen anderen Wert als &amp;quot;ok&amp;quot; wird dies alarmiert. &lt;br /&gt;
In den Readings von HMInfo würde im Feherfall&lt;br /&gt;
  internal:&lt;br /&gt;
    ERR_names &amp;lt;devicename1&amp;gt;,&amp;lt;devicename2&amp;gt;&lt;br /&gt;
  Readings:&lt;br /&gt;
    ERR_battery low:2&lt;br /&gt;
&lt;br /&gt;
Der default aller Error-meldungen ist&lt;br /&gt;
battery:ok,sabotageError:off,powerError:ok,overload:off,overheat:off,reduced:off,motorError:no,error:none,uncertain:yes,smoke_detect:none,cover:closed&lt;br /&gt;
&lt;br /&gt;
Diese Zusammenfassung der Fehlermeldungen könnte man nutzen, um über notify einen Alarm auszulösen oder eine E-Mail zu senden. &lt;br /&gt;
&lt;br /&gt;
=== Warnungen===&lt;br /&gt;
Hierzu gehören Wiederholungen von Nachrichten (nicht aber Abbrüche, das sind Fehler). Es wird auch ausstehendes Lesen der Konfiguration, das durch autoReadReg getriggert wird, hier angezeigt. &lt;br /&gt;
&lt;br /&gt;
=== Statusmeldungen ===&lt;br /&gt;
Analog zu den Fehlermeldungen kann man mit dem Attribut sumStatus gewisse Readings zählen lassen. Beipiel wäre &lt;br /&gt;
  attr HM sumStatus motor&lt;br /&gt;
HMInfo zeigt in dem Reading I_sum_motor dann an, welcher Inhalt des Readings &amp;quot;motor&amp;quot;  wie oft gefunden wurde. Es könnte so aussehen&lt;br /&gt;
  stop:on:4;stop:1;&lt;br /&gt;
Vier Komponenten stehen auf motor: stop:on und eine steht auf motor: stop&lt;br /&gt;
&lt;br /&gt;
Das Internal &#039;&#039;&#039;I_HM_IOdevices&#039;&#039;&#039; zeigt die von HM Komponenten genutzten IOs und deren State. &lt;br /&gt;
&lt;br /&gt;
== Infos ==&lt;br /&gt;
  get hm models [-f &amp;lt;regexp&amp;gt;]&lt;br /&gt;
  get hm models&lt;br /&gt;
  get hm models -f remote&lt;br /&gt;
  get hm models -f HM_RC&lt;br /&gt;
Zeigt alle in FHEM unterstützten Modelle und deren wesentliche Parameter. Man kann mittels regexp die Liste filtern.&lt;br /&gt;
&lt;br /&gt;
  get hm param [&amp;lt;typefilter&amp;gt;] [-f &amp;lt;nameFilter&amp;gt;] parameter1 parameter2&lt;br /&gt;
  get hm param -d IODev DEF model&lt;br /&gt;
  get hm param -c -f Rollo peerList&lt;br /&gt;
man kann sich listen von Parametern anzeigen lassen  &lt;br /&gt;
&lt;br /&gt;
  get hm register [&amp;lt;typefilter&amp;gt;] [-f &amp;lt;nameFilter&amp;gt;]&lt;br /&gt;
zeigt Register in tabellarischer Form. &lt;br /&gt;
&lt;br /&gt;
  get hm peerXref[&amp;lt;typefilter&amp;gt;] [-f &amp;lt;nameFilter&amp;gt;]&lt;br /&gt;
gibt an, wer mit wem [[Peering (HomeMatic)|gepeert]] ist&lt;br /&gt;
&lt;br /&gt;
== Rücksetzen von Variablen und Zählern ==&lt;br /&gt;
 set HM clear [&amp;lt;typeFilter&amp;gt;] [Protocol|readings|msgStat|register|rssi]&lt;br /&gt;
*register löscht alle Register-readings&lt;br /&gt;
*readings löscht &#039;&#039;&#039;alle&#039;&#039;&#039; readings&lt;br /&gt;
*Protocol löscht alle Protokol-einträge, pending Kommandos und Protokoll-fehler. &lt;br /&gt;
*rssi löscht alle ermittelten RSSI Werte&lt;br /&gt;
*msgStat setzt die Message Statistik zurück&lt;br /&gt;
&lt;br /&gt;
== Filter ==&lt;br /&gt;
Kommandos in HMInfo wirken auf alle HM Komponenten. Man kann dies mit Hilfe der Filter einschränken. Zum einen gibt es &#039;&#039;&#039;modelsFilter&#039;&#039;&#039;, womit man nur devices, nur channels, nur virtuelle Entities bearbeiten kann&lt;br /&gt;
     set &amp;lt;name&amp;gt; &amp;lt;cmd&amp;gt; &#039;&#039;&#039;[-dcasevi]&#039;&#039;&#039;  [params]&lt;br /&gt;
        entities according to list will be processed&amp;quot;&lt;br /&gt;
          d - device   :include devices&amp;quot;&lt;br /&gt;
          c - channels :include channels&amp;quot;&lt;br /&gt;
          i - ignore   :include devices marked as ignore&amp;quot;&lt;br /&gt;
          v - virtual  :supress fhem virtual&amp;quot;&lt;br /&gt;
          p - physical :supress physical&amp;quot;&lt;br /&gt;
          a - aktor    :supress actor&amp;quot;&lt;br /&gt;
          s - sensor   :supress sensor&amp;quot;&lt;br /&gt;
          e - empty    :include results even if requested fields are empty&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Ein auf &#039;&#039;&#039;-d&#039;&#039;&#039; gefiltertes Kommando wird nur auf devices, nicht aber auf channels angewendet. &lt;br /&gt;
&lt;br /&gt;
Dann gibt es noch den &#039;&#039;&#039;nameFilter&#039;&#039;&#039;, mit dem mittels regexp auf den Namen der Entity gefiltert werden kann&lt;br /&gt;
  -f Rollo # alle Entities mit Rollo im Namen&lt;br /&gt;
  -f ^Rollo$ # nur Entity mit Namen &amp;quot;Rollo&amp;quot;&lt;br /&gt;
  -f Rollo$ # nur Entity deren Name auf Rollo endet&lt;br /&gt;
&lt;br /&gt;
Die Filter kann man kombinieren mit &lt;br /&gt;
  -c -f Rollo # alle Kanäle mit Rollo im Namen&lt;br /&gt;
&lt;br /&gt;
Beispiel: &lt;br /&gt;
Zeige mir die Parameter IODev und room der Devices mit Rollo im Namen&lt;br /&gt;
  set hm param -d -f Rollo IODev room&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Attribute ==&lt;br /&gt;
* &#039;&#039;&#039;autoArchive &#039;&#039;&#039; automatisch archivieren von vollständigen Konfigurationen.&lt;br /&gt;
* &#039;&#039;&#039;autoUpdate&#039;&#039;&#039; startet regelmäßig das Komamndo &amp;quot;update&amp;quot;. Die Wiederholzeit wird eingestellt mit hh:mm. Sinnvoll erscheint z.B. alle 5 Minuten, also 00:05.&lt;br /&gt;
* &#039;&#039;&#039;configDir&#039;&#039;&#039; bietet die Möglichkeit, ein Verzeichnis zu definieren, in das HMInfo Dateien ablegen und von dem es die Dateien lesen wird. Default ist fhem_root.&lt;br /&gt;
* &#039;&#039;&#039;configFilename&#039;&#039;&#039; legt einen default Namen fest, der bei save und archive genutzt wird. Default ist regSave.cfg.&lt;br /&gt;
* &#039;&#039;&#039;hmAutoReadScan&#039;&#039;&#039; zeitinterval in Minuten, in denen CUL_HM prüft, ob offene autoRead bereitstehen und die IOs die Kapazität haben. Default ist 4 min.&lt;br /&gt;
== Weiterführende Links ==&lt;br /&gt;
* [[HomeMatic Templates]]&lt;br /&gt;
&lt;br /&gt;
== Quellen == &lt;br /&gt;
* Thread [http://forum.fhem.de/index.php?topic=11035.0 HMinfo] im FHEM Forum&lt;br /&gt;
* Thread {{Link2Forum|Topic=20119|LinkText=HMINfo, Intention, Sinn und Zweck}} im FHEM Forum&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:HomeMatic supportDevice]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=32343</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=32343"/>
		<updated>2020-01-09T08:29:56Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Idee */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben (https://www.reichelt.de/raspberry-pi-usv-rpi-usv-p169883.html).&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung, Akku-Spannung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss das I2C-Interface Modul „RPII2C“ zuvor definiert werden (siehe Commandref).&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $s_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung=&amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	if ($usv_meldung ne &amp;quot;&amp;quot;) {&lt;br /&gt;
		fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+) |/is;&lt;br /&gt;
$s_pi = $1;&lt;br /&gt;
if ($s_pi != 0xFF)&lt;br /&gt;
	{&lt;br /&gt;
	$status=$s_pi &amp;amp; 0x3F;&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&amp;lt;br&amp;gt;&lt;br /&gt;
Der Wert des Statusregister wird hier als Dezimalzahl dargestellt und muss zur weiteren Verarbeitung ggf. noch binär ausdekodiert werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;br /&gt;
[[Kategorie:Raspberry Pi]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=32336</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=32336"/>
		<updated>2020-01-07T20:56:32Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Umsetzung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben (https://www.reichelt.de/raspberry-pi-usv-rpi-usv-p169883.html).&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss das I2C-Interface Modul „RPII2C“ zuvor definiert werden (siehe Commandref).&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $s_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung=&amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	if ($usv_meldung ne &amp;quot;&amp;quot;) {&lt;br /&gt;
		fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+) |/is;&lt;br /&gt;
$s_pi = $1;&lt;br /&gt;
if ($s_pi != 0xFF)&lt;br /&gt;
	{&lt;br /&gt;
	$status=$s_pi &amp;amp; 0x3F;&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&amp;lt;br&amp;gt;&lt;br /&gt;
Der Wert des Statusregister wird hier als Dezimalzahl dargestellt und muss zur weiteren Verarbeitung ggf. noch binär ausdekodiert werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;br /&gt;
[[Kategorie:Raspberry Pi]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Raspberry_Pi:_FHEM_starten/stoppen&amp;diff=32331</id>
		<title>Raspberry Pi: FHEM starten/stoppen</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Raspberry_Pi:_FHEM_starten/stoppen&amp;diff=32331"/>
		<updated>2020-01-06T16:03:52Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Links */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein auf einem &#039;&#039;&#039;[[Raspberry Pi]]&#039;&#039;&#039; laufendes &#039;&#039;&#039;FHEM starten und stoppen&#039;&#039;&#039; (ein Neustart des Raspberry ist so nicht erforderlich).&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen ==&lt;br /&gt;
* Funktionierender SSH Consolen Client&lt;br /&gt;
** MacOS X: Terminal.app &lt;br /&gt;
** Windows: openssh mit mingw (Putty kann auch genutzt werden, dabei funktioniert in den Beispielen Schritt 2 anders)&lt;br /&gt;
** Linux: ssh in der Shell&lt;br /&gt;
&lt;br /&gt;
== FHEM starten ==&lt;br /&gt;
# Starten des SSH Clients&lt;br /&gt;
# Mit dem RPi verbinden mittels &#039;&#039;ssh pi@192.168.2.50&#039;&#039; (Hier muss natürlich der eigene User und IP eingegeben werden.)&lt;br /&gt;
# Passwort des Benutzers (in diesem Beispiel &amp;quot;pi&amp;quot;) eingeben.&lt;br /&gt;
# Den Befehl &#039;&#039;sudo systemctl start fhem&#039;&#039; (bei älteren Rasbian-Versionen: &#039;&#039;sudo /etc/init.d/fhem start&#039;&#039;) ausführen&lt;br /&gt;
Als Rückmeldung wird auf der Konsole &amp;quot;Starting fhem ...&amp;quot; ausgegeben. Damit ist FHEM gestartet. Als Gegenprüfung kann der Status abgefragt werden. Siehe &amp;quot;FHEM Status&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== FHEM stoppen ==&lt;br /&gt;
# Starten des SSH Clients&lt;br /&gt;
# Mit dem RPi verbinden mittels &#039;&#039;ssh pi@192.168.2.50&#039;&#039; (Hier muss natürlich der eigene User und IP eingegeben werden.)&lt;br /&gt;
# Passwort des Benutzers (in diesem Beispiel &amp;quot;pi&amp;quot;) eingeben.&lt;br /&gt;
# Den Befehl &#039;&#039;sudo systemctl stop fhem&#039;&#039; (bei älteren Rasbian-Versionen: &#039;&#039;sudo /etc/init.d/fhem stop&#039;&#039;) ausführen&lt;br /&gt;
Als Rückmeldung wird auf der Konsole &amp;quot;Stopping fhem ...&amp;quot; ausgegeben. Damit ist FHEM beendet. Als Gegenprüfung kann der Status abgefragt werden. Siehe &amp;quot;FHEM Status&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== FHEM Status ==&lt;br /&gt;
# Starten des SSH Clients&lt;br /&gt;
# Mit dem RPi verbinden mittels &#039;&#039;ssh pi@192.168.2.50&#039;&#039; (Hier muss natürlich der eigene User und IP eingegeben werden.)&lt;br /&gt;
# Passwort des Benutzers (in diesem Beispiel &amp;quot;pi&amp;quot;) eingeben.&lt;br /&gt;
# Den Befehl &#039;&#039;sudo systemctl status fhem&#039;&#039; (bei älteren Rasbian-Versionen: &#039;&#039;sudo /etc/init.d/fhem status&#039;&#039;) ausführen&lt;br /&gt;
Als Antwort wird auf der Konsole der aktuelle Status von FHEM ausgegeben. z.B. fhem is running&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Ausführlichere Anleitung, die auch für Raspberry hilfreich sein kann: [[FritzBox: FHEM per Telnet starten]]&lt;br /&gt;
* Auswahl sinnvoller [[Kommandozeilentools]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:FAQ]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;br /&gt;
[[Kategorie:Raspberry Pi]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Raspberry_Pi:_FHEM_starten/stoppen&amp;diff=32319</id>
		<title>Raspberry Pi: FHEM starten/stoppen</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Raspberry_Pi:_FHEM_starten/stoppen&amp;diff=32319"/>
		<updated>2020-01-05T20:52:36Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* FHEM Status */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein auf einem &#039;&#039;&#039;[[Raspberry Pi]]&#039;&#039;&#039; laufendes &#039;&#039;&#039;FHEM starten und stoppen&#039;&#039;&#039; (ein Neustart des Raspberry ist so nicht erforderlich).&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen ==&lt;br /&gt;
* Funktionierender SSH Consolen Client&lt;br /&gt;
** MacOS X: Terminal.app &lt;br /&gt;
** Windows: openssh mit mingw (Putty kann auch genutzt werden, dabei funktioniert in den Beispielen Schritt 2 anders)&lt;br /&gt;
** Linux: ssh in der Shell&lt;br /&gt;
&lt;br /&gt;
== FHEM starten ==&lt;br /&gt;
# Starten des SSH Clients&lt;br /&gt;
# Mit dem RPi verbinden mittels &#039;&#039;ssh pi@192.168.2.50&#039;&#039; (Hier muss natürlich der eigene User und IP eingegeben werden.)&lt;br /&gt;
# Passwort des Benutzers (in diesem Beispiel &amp;quot;pi&amp;quot;) eingeben.&lt;br /&gt;
# Den Befehl &#039;&#039;sudo systemctl start fhem&#039;&#039; (bei älteren Rasbian-Versionen: &#039;&#039;sudo /etc/init.d/fhem start&#039;&#039;) ausführen&lt;br /&gt;
Als Rückmeldung wird auf der Konsole &amp;quot;Starting fhem ...&amp;quot; ausgegeben. Damit ist FHEM gestartet. Als Gegenprüfung kann der Status abgefragt werden. Siehe &amp;quot;FHEM Status&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== FHEM stoppen ==&lt;br /&gt;
# Starten des SSH Clients&lt;br /&gt;
# Mit dem RPi verbinden mittels &#039;&#039;ssh pi@192.168.2.50&#039;&#039; (Hier muss natürlich der eigene User und IP eingegeben werden.)&lt;br /&gt;
# Passwort des Benutzers (in diesem Beispiel &amp;quot;pi&amp;quot;) eingeben.&lt;br /&gt;
# Den Befehl &#039;&#039;sudo systemctl stop fhem&#039;&#039; (bei älteren Rasbian-Versionen: &#039;&#039;sudo /etc/init.d/fhem stop&#039;&#039;) ausführen&lt;br /&gt;
Als Rückmeldung wird auf der Konsole &amp;quot;Stopping fhem ...&amp;quot; ausgegeben. Damit ist FHEM beendet. Als Gegenprüfung kann der Status abgefragt werden. Siehe &amp;quot;FHEM Status&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== FHEM Status ==&lt;br /&gt;
# Starten des SSH Clients&lt;br /&gt;
# Mit dem RPi verbinden mittels &#039;&#039;ssh pi@192.168.2.50&#039;&#039; (Hier muss natürlich der eigene User und IP eingegeben werden.)&lt;br /&gt;
# Passwort des Benutzers (in diesem Beispiel &amp;quot;pi&amp;quot;) eingeben.&lt;br /&gt;
# Den Befehl &#039;&#039;sudo systemctl status fhem&#039;&#039; (bei älteren Rasbian-Versionen: &#039;&#039;sudo /etc/init.d/fhem status&#039;&#039;) ausführen&lt;br /&gt;
Als Antwort wird auf der Konsole der aktuelle Status von FHEM ausgegeben. z.B. fhem is running&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Ausführlichere Anleitung, die auch für Raspberry hilfreich sein kann: [[FritzBox: FHEM per Telnet starten]]&lt;br /&gt;
* Auswahl sinnvoller [[Kommandozeilentools]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:FAQ]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Raspberry_Pi:_FHEM_starten/stoppen&amp;diff=32318</id>
		<title>Raspberry Pi: FHEM starten/stoppen</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Raspberry_Pi:_FHEM_starten/stoppen&amp;diff=32318"/>
		<updated>2020-01-05T20:51:44Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* FHEM stoppen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein auf einem &#039;&#039;&#039;[[Raspberry Pi]]&#039;&#039;&#039; laufendes &#039;&#039;&#039;FHEM starten und stoppen&#039;&#039;&#039; (ein Neustart des Raspberry ist so nicht erforderlich).&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen ==&lt;br /&gt;
* Funktionierender SSH Consolen Client&lt;br /&gt;
** MacOS X: Terminal.app &lt;br /&gt;
** Windows: openssh mit mingw (Putty kann auch genutzt werden, dabei funktioniert in den Beispielen Schritt 2 anders)&lt;br /&gt;
** Linux: ssh in der Shell&lt;br /&gt;
&lt;br /&gt;
== FHEM starten ==&lt;br /&gt;
# Starten des SSH Clients&lt;br /&gt;
# Mit dem RPi verbinden mittels &#039;&#039;ssh pi@192.168.2.50&#039;&#039; (Hier muss natürlich der eigene User und IP eingegeben werden.)&lt;br /&gt;
# Passwort des Benutzers (in diesem Beispiel &amp;quot;pi&amp;quot;) eingeben.&lt;br /&gt;
# Den Befehl &#039;&#039;sudo systemctl start fhem&#039;&#039; (bei älteren Rasbian-Versionen: &#039;&#039;sudo /etc/init.d/fhem start&#039;&#039;) ausführen&lt;br /&gt;
Als Rückmeldung wird auf der Konsole &amp;quot;Starting fhem ...&amp;quot; ausgegeben. Damit ist FHEM gestartet. Als Gegenprüfung kann der Status abgefragt werden. Siehe &amp;quot;FHEM Status&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== FHEM stoppen ==&lt;br /&gt;
# Starten des SSH Clients&lt;br /&gt;
# Mit dem RPi verbinden mittels &#039;&#039;ssh pi@192.168.2.50&#039;&#039; (Hier muss natürlich der eigene User und IP eingegeben werden.)&lt;br /&gt;
# Passwort des Benutzers (in diesem Beispiel &amp;quot;pi&amp;quot;) eingeben.&lt;br /&gt;
# Den Befehl &#039;&#039;sudo systemctl stop fhem&#039;&#039; (bei älteren Rasbian-Versionen: &#039;&#039;sudo /etc/init.d/fhem stop&#039;&#039;) ausführen&lt;br /&gt;
Als Rückmeldung wird auf der Konsole &amp;quot;Stopping fhem ...&amp;quot; ausgegeben. Damit ist FHEM beendet. Als Gegenprüfung kann der Status abgefragt werden. Siehe &amp;quot;FHEM Status&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== FHEM Status ==&lt;br /&gt;
# Starten des SSH Clients&lt;br /&gt;
# Mit dem RPi verbinden mittels &#039;&#039;ssh pi@192.168.2.50&#039;&#039; (Hier muss natürlich der eigene User und IP eingegeben werden.)&lt;br /&gt;
# Passwort des Benutzers (in diesem Beispiel &amp;quot;pi&amp;quot;) eingeben.&lt;br /&gt;
# Den Befehl &#039;&#039;sudo /etc/init.d/fhem status&#039;&#039; ausführen&lt;br /&gt;
Als Antwort wird auf der Konsole der aktuelle Status von FHEM ausgegeben. z.B. fhem is running&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Ausführlichere Anleitung, die auch für Raspberry hilfreich sein kann: [[FritzBox: FHEM per Telnet starten]]&lt;br /&gt;
* Auswahl sinnvoller [[Kommandozeilentools]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:FAQ]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Raspberry_Pi:_FHEM_starten/stoppen&amp;diff=32317</id>
		<title>Raspberry Pi: FHEM starten/stoppen</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Raspberry_Pi:_FHEM_starten/stoppen&amp;diff=32317"/>
		<updated>2020-01-05T20:50:31Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* FHEM starten */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein auf einem &#039;&#039;&#039;[[Raspberry Pi]]&#039;&#039;&#039; laufendes &#039;&#039;&#039;FHEM starten und stoppen&#039;&#039;&#039; (ein Neustart des Raspberry ist so nicht erforderlich).&lt;br /&gt;
&lt;br /&gt;
== Voraussetzungen ==&lt;br /&gt;
* Funktionierender SSH Consolen Client&lt;br /&gt;
** MacOS X: Terminal.app &lt;br /&gt;
** Windows: openssh mit mingw (Putty kann auch genutzt werden, dabei funktioniert in den Beispielen Schritt 2 anders)&lt;br /&gt;
** Linux: ssh in der Shell&lt;br /&gt;
&lt;br /&gt;
== FHEM starten ==&lt;br /&gt;
# Starten des SSH Clients&lt;br /&gt;
# Mit dem RPi verbinden mittels &#039;&#039;ssh pi@192.168.2.50&#039;&#039; (Hier muss natürlich der eigene User und IP eingegeben werden.)&lt;br /&gt;
# Passwort des Benutzers (in diesem Beispiel &amp;quot;pi&amp;quot;) eingeben.&lt;br /&gt;
# Den Befehl &#039;&#039;sudo systemctl start fhem&#039;&#039; (bei älteren Rasbian-Versionen: &#039;&#039;sudo /etc/init.d/fhem start&#039;&#039;) ausführen&lt;br /&gt;
Als Rückmeldung wird auf der Konsole &amp;quot;Starting fhem ...&amp;quot; ausgegeben. Damit ist FHEM gestartet. Als Gegenprüfung kann der Status abgefragt werden. Siehe &amp;quot;FHEM Status&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== FHEM stoppen ==&lt;br /&gt;
# Starten des SSH Clients&lt;br /&gt;
# Mit dem RPi verbinden mittels &#039;&#039;ssh pi@192.168.2.50&#039;&#039; (Hier muss natürlich der eigene User und IP eingegeben werden.)&lt;br /&gt;
# Passwort des Benutzers (in diesem Beispiel &amp;quot;pi&amp;quot;) eingeben.&lt;br /&gt;
# Den Befehl &#039;&#039;sudo /etc/init.d/fhem stop&#039;&#039; ausführen&lt;br /&gt;
Als Rückmeldung wird auf der Konsole &amp;quot;Stopping fhem ...&amp;quot; ausgegeben. Damit ist FHEM beendet. Als Gegenprüfung kann der Status abgefragt werden. Siehe &amp;quot;FHEM Status&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== FHEM Status ==&lt;br /&gt;
# Starten des SSH Clients&lt;br /&gt;
# Mit dem RPi verbinden mittels &#039;&#039;ssh pi@192.168.2.50&#039;&#039; (Hier muss natürlich der eigene User und IP eingegeben werden.)&lt;br /&gt;
# Passwort des Benutzers (in diesem Beispiel &amp;quot;pi&amp;quot;) eingeben.&lt;br /&gt;
# Den Befehl &#039;&#039;sudo /etc/init.d/fhem status&#039;&#039; ausführen&lt;br /&gt;
Als Antwort wird auf der Konsole der aktuelle Status von FHEM ausgegeben. z.B. fhem is running&lt;br /&gt;
&lt;br /&gt;
== Links ==&lt;br /&gt;
* Ausführlichere Anleitung, die auch für Raspberry hilfreich sein kann: [[FritzBox: FHEM per Telnet starten]]&lt;br /&gt;
* Auswahl sinnvoller [[Kommandozeilentools]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:FAQ]]&lt;br /&gt;
[[Kategorie:HOWTOS]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=32254</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=32254"/>
		<updated>2020-01-01T18:26:34Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Umsetzung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben (https://www.reichelt.de/raspberry-pi-usv-rpi-usv-p169883.html).&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss das I2C-Interface Modul „RPII2C“ zuvor definiert werden (siehe Commandref).&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $s_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung=&amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	if ($usv_meldung ne &amp;quot;&amp;quot;) {&lt;br /&gt;
		fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+) |/is;&lt;br /&gt;
$s_pi = $1;&lt;br /&gt;
if ($s_pi != 0xFF)&lt;br /&gt;
	{&lt;br /&gt;
	$status=$s_pi &amp;amp; 0x3F;&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&amp;lt;br&amp;gt;&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Der Wert des Statusregister wird hier als Dezimalzahl dargestellt und muss zur weiteren Verarbeitung ggf. noch binär ausdekodiert werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;br /&gt;
[[Kategorie:Raspberry Pi]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=32253</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=32253"/>
		<updated>2020-01-01T18:24:35Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Umsetzung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben (https://www.reichelt.de/raspberry-pi-usv-rpi-usv-p169883.html).&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss das I2C-Interface Modul „RPII2C“ zuvor definiert werden (siehe Commandref).&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $s_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung=&amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	if ($usv_meldung ne &amp;quot;&amp;quot;) {&lt;br /&gt;
		fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;)&lt;br /&gt;
		};&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+) |/is;&lt;br /&gt;
$s_pi = $1;&lt;br /&gt;
if ($s_pi != 0xFF)&lt;br /&gt;
	{&lt;br /&gt;
	$status=$s_pi &amp;amp; 0x3F;&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&amp;lt;br&amp;gt;&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Der Wert des Statusregister wird hier als Dezimalzahl dargestellt und muss zur weiteren Verarbeitung ggf. noch binär ausdekodiert werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;br /&gt;
[[Kategorie:Raspberry Pi]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30965</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30965"/>
		<updated>2019-07-11T21:43:36Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Ausblick */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben (https://www.reichelt.de/raspberry-pi-usv-rpi-usv-p169883.html).&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss das I2C-Interface Modul „RPII2C“ zuvor definiert werden (siehe Commandref).&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $s_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+) |/is;&lt;br /&gt;
$s_pi = $1;&lt;br /&gt;
if ($s_pi != 0xFF)&lt;br /&gt;
	{&lt;br /&gt;
	$status=$s_pi &amp;amp; 0x3F;&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&amp;lt;br&amp;gt;&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Der Wert des Statusregister wird hier als Dezimalzahl dargestellt und muss zur weiteren Verarbeitung ggf. noch binär ausdekodiert werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;br /&gt;
[[Kategorie:Raspberry Pi]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30964</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30964"/>
		<updated>2019-07-11T21:43:00Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Ausblick */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben (https://www.reichelt.de/raspberry-pi-usv-rpi-usv-p169883.html).&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss das I2C-Interface Modul „RPII2C“ zuvor definiert werden (siehe Commandref).&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $s_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+) |/is;&lt;br /&gt;
$s_pi = $1;&lt;br /&gt;
if ($s_pi != 0xFF)&lt;br /&gt;
	{&lt;br /&gt;
	$status=$s_pi &amp;amp; 0x3F;&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&amp;lt;br&amp;gt;&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Der Wert des Statusregister wird hier als Dezimalzahl dargestellt und muss zur weiteren Verarbeitung ggf. noch binär ausdekodiert werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;br /&gt;
[[Raspberry Pi]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30881</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30881"/>
		<updated>2019-07-02T06:22:09Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Umsetzung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben (https://www.reichelt.de/raspberry-pi-usv-rpi-usv-p169883.html).&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss das I2C-Interface Modul „RPII2C“ zuvor definiert werden (siehe Commandref).&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $s_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+) |/is;&lt;br /&gt;
$s_pi = $1;&lt;br /&gt;
if ($s_pi != 0xFF)&lt;br /&gt;
	{&lt;br /&gt;
	$status=$s_pi &amp;amp; 0x3F;&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&amp;lt;br&amp;gt;&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Der Wert des Statusregister wird hier als Dezimalzahl dargestellt und muss zur weiteren Verarbeitung ggf. noch binär ausdekodiert werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30875</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30875"/>
		<updated>2019-06-30T19:48:05Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Umsetzung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben (https://www.reichelt.de/raspberry-pi-usv-rpi-usv-p169883.html).&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss ein geeignetes I2C Interface Modul (z.B. RPII2C, FRM oder NetzerI2C) zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Nachfolgend wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $s_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+) |/is;&lt;br /&gt;
$s_pi = $1;&lt;br /&gt;
if ($s_pi != 0xFF)&lt;br /&gt;
	{&lt;br /&gt;
	$status=$s_pi &amp;amp; 0x3F;&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&amp;lt;br&amp;gt;&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Der Wert des Statusregister wird hier als Dezimalzahl dargestellt und muss zur weiteren Verarbeitung ggf. noch binär ausdekodiert werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30846</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30846"/>
		<updated>2019-06-28T05:40:08Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Umsetzung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben (https://www.reichelt.de/raspberry-pi-usv-rpi-usv-p169883.html).&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss ein geeignetes I2C Interface Modul (z.B. RPII2C, FRM oder NetzerI2C) zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Nachfolgend wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $s_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
	$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
	$content=~ m/received : (\d+) |/is;&lt;br /&gt;
	$s_pi = $1;&lt;br /&gt;
   	if ($s_pi != 0xFF)&lt;br /&gt;
		{&lt;br /&gt;
		$status=$s_pi &amp;amp; 0x3F;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&amp;lt;br&amp;gt;&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Der Wert des Statusregister wird hier als Dezimalzahl dargestellt und muss zur weiteren Verarbeitung ggf. noch binär ausdekodiert werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30844</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30844"/>
		<updated>2019-06-28T05:34:10Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Umsetzung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben (https://www.reichelt.de/raspberry-pi-usv-rpi-usv-p169883.html).&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss ein geeignetes I2C Interface Modul (z.B. RPII2C, FRM oder NetzerI2C) zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Nachfolgend wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $s_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
	$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
	$content=~ m/received : (\d+) |/is;&lt;br /&gt;
	$s_pi = $1;&lt;br /&gt;
   	if ($s_pi!=255)&lt;br /&gt;
		{&lt;br /&gt;
 		status=$s_pi &amp;amp; 63;&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&amp;lt;br&amp;gt;&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Der Wert des Statusregister wird hier als Dezimalzahl dargestellt und muss zur weiteren Verarbeitung ggf. noch binär ausdekodiert werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30778</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30778"/>
		<updated>2019-06-19T19:53:59Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Idee */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben (https://www.reichelt.de/raspberry-pi-usv-rpi-usv-p169883.html).&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss ein geeignetes I2C Interface Modul (z.B. RPII2C, FRM oder NetzerI2C) zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Nachfolgend wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
	$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
	$content=~ m/received : (\d+) |/is;&lt;br /&gt;
	$status = $1;&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&amp;lt;br&amp;gt;&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Der Wert des Statusregister wird hier als Dezimalzahl dargestellt und muss zur weiteren Verarbeitung ggf. noch binär ausdekodiert werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30777</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30777"/>
		<updated>2019-06-19T19:43:51Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Umsetzung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben.&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss ein geeignetes I2C Interface Modul (z.B. RPII2C, FRM oder NetzerI2C) zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Nachfolgend wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
	$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
	$content=~ m/received : (\d+) |/is;&lt;br /&gt;
	$status = $1;&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&amp;lt;br&amp;gt;&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&amp;lt;br&amp;gt;&lt;br /&gt;
Der Wert des Statusregister wird hier als Dezimalzahl dargestellt und muss zur weiteren Verarbeitung ggf. noch binär ausdekodiert werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Homematic-Register_von_A-Z_(Namen,_Erkl%C3%A4rung)&amp;diff=30749</id>
		<title>Homematic-Register von A-Z (Namen, Erklärung)</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Homematic-Register_von_A-Z_(Namen,_Erkl%C3%A4rung)&amp;diff=30749"/>
		<updated>2019-06-12T21:53:41Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* energyOpt */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Bitte noch an geeigneten Stellen Links auf diese Seite einfügen --&amp;gt;&lt;br /&gt;
{{Baustelle}}&lt;br /&gt;
Dieser Artikel soll die Namensgebung der Homematic-Register erklären und einen Index aller bekannten Register mit einer kurzen Funktionserklärung liefern. Der Index folgt dabei den Registerklassen, da sich die Namensgebung diesbezüglich ebenfalls unterscheidet.&lt;br /&gt;
&lt;br /&gt;
Zur grundsätzlichen Anwendung von Registerprogrammierung mit einigen Beispielen siehe u.a. den Artikel [[HomeMatic Register programmieren]] und [[HomeMatic HmInfo Templates erstellen]].&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
&lt;br /&gt;
Die Namenskonvention der Homematic-Register ist für den Neuling verwirrend, folgt jedoch fast durchgängig einer einfachen Logik&lt;br /&gt;
* er setzt sich aus einem oder mehreren Bestandteilen zusammen&lt;br /&gt;
* er beginnt immer mit einem Kleinbuchstaben&lt;br /&gt;
* jeder weitere Namensbestandteil beginnt mit einem Großbuchstaben&lt;br /&gt;
* die Bezeichnungen der Bestandteile sind englisch, kurze Begriffe werden ausgeschrieben, längere abgekürzt&lt;br /&gt;
&lt;br /&gt;
Die möglichen Bestandteile werden in den jeweiligen Registergruppen (Listen) erläutert. &lt;br /&gt;
&lt;br /&gt;
Details zu den Wertebereichen sowie eine kurze englische Beschreibung liefert der Befehl &#039;&#039;&#039;reglist&#039;&#039;&#039; in Geräten und Kanälen.&lt;br /&gt;
&lt;br /&gt;
== Die Registerklassen (Listen) eines Homematic-Gerätes ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Designvorschlag 1: Unterkapitel mit Inhaltsverzeichniseintrag&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Jedes Homematic-Gerät besitzt prinzipiell geräte-, kanal- und verknüpfungsbezogene Register. Bei Geräten, die nur einen sogenannten Kanal besitzen, erscheinen alle drei Register gemeinsam in der Definitionsansicht und den Listings in FHEM, bei Geräten mit mehreren Kanälen findet man die verknüfungs- und kanalbezogenen Register in den jeweiligen Kanälen.&lt;br /&gt;
&lt;br /&gt;
=== Gerätebezogene Register ===&lt;br /&gt;
Gerätebezogene Register existieren für jedes HomeMatic-Gerät nur einmal und werden in der sogenannten &#039;&#039;&#039;List0&#039;&#039;&#039; gespeichert (in der FHEM-Oberfläche als Hexbytefolge unter &#039;&#039;RegL_00.&#039;&#039; zu finden).&lt;br /&gt;
&lt;br /&gt;
==== brightness====&lt;br /&gt;
brightness = Helligkeit. Wertebereich: 0-15. Steuert die Helligkeit der LED-Anzeige. Verwendet in: [[HM-OU-LED16]]. &lt;br /&gt;
&lt;br /&gt;
==== energyOpt ====&lt;br /&gt;
energy option = Energieoptionen. Wertebereich: 0 to 127 (Sekunden), zusätzlich &amp;quot;permanent&amp;quot; (dauerhaft). Einschaltdauer des Displays [[HM-OU-LED16]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Designvorschlag 2: Tabelle&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Register !! Erläuterungen&lt;br /&gt;
|-&lt;br /&gt;
| brightness || brightness = Helligkeit. Wertebereich: 0-15. Steuert die Helligkeit der LED-Anzeige. Verwendet in: [[HM-OU-LED16]].&lt;br /&gt;
|-&lt;br /&gt;
| confBtnTime || configuration button timeout. Wertangabe in Minuten (!) oder &#039;&#039;permanent&#039;&#039;&amp;lt;br&amp;gt;Nicht immer sind die internen Tasten eines Gerätes ohne weiteres mit Aktionen für kurzen und langen Tastendruck programmierbar. Bei allen Hutschienen-Aktoren sowie den Zwischensteckern (mit nur einem Bedienknopf) versetzt ein langer Tastendruck (4 Sekunden) den Schalter normalerweise in den Konfigurations- bzw. Anlern-Modus, bei den in Unterputzdosen versenkbaren Schalt- und Dimmaktoren (-FM ohne PBU in der Bezeichnung) ohne eigenen Konfigurations-Button gilt dies sogar für die zur normalen Funktion extern angeschlossenen Taster. Dieses Verhalten kann man mit dem Register &#039;&#039;confBtnTime&#039;&#039; beeinflussen. Bis zum Ablauf der dort einstellbaren Zeit (in Minuten) nach dem Versorgen mit Strom (&#039;&#039;powerUp&#039;&#039;) erreicht man den Konfigurationsmodus wie bisher, danach interpretiert der Aktor die Tastendrücke stets als kurz (short) oder lang (long).&lt;br /&gt;
|- &lt;br /&gt;
| energyOpt || energy option = Energieoptionen. Wertebereich: 0 to 127 (Sekunden), zusätzlich &#039;&#039;permanent&#039;&#039; (dauerhaft). Einschaltdauer des Displays [[HM-OU-LED16]]. &lt;br /&gt;
|-&lt;br /&gt;
| intKeyVisib || internal key(s) visible = interne Taste(n) sichtbar. Werte: &#039;&#039;visib&#039;&#039; = sichtbar bzw. &#039;&#039;invisib&#039;&#039; = unsichtbar (voreingestellt).&amp;lt;br&amp;gt;Die internen &amp;quot;Tasten&amp;quot; eines Aktors (z.B. die Schaltwippe bei Wandschaltern/-tastern, der Bedienknopf bei Zwischensteckern, aber auch die angeschlossenen externen Taster bei Aktoren für Unterputzdosen oder die von außen zugängliche &amp;quot;Notbedientaste&amp;quot; etwa bei Zwischendecken-Dimmern) sind logisch ebenso mit dem Aktor verknüpft wie externe Bedienelemente wie Funkfernbedienungen oder per Funk verknüpfte Wandtaster. Ihre Betätigung wird (außer mit präparierter Firmware) zwar nicht gesendet (und kann daher von FHEM nicht &amp;quot;gelesen&amp;quot; werden), die vom Hersteller vorgesehenen Funktionen lassen sich aber genauso frei programmieren. Allerdings sind diese internen Verknüpfungen zur Vermeidung versehentlicher Programmierungen zunächst verborgen und müssen daher vor einer Manipulation explizit sichtbar gemacht werden. &lt;br /&gt;
|-&lt;br /&gt;
| ledMode || led modus = LED-Betriebsart, &#039;&#039;on&#039;&#039; bzw. &#039;&#039;off&#039;&#039;.&amp;lt;br&amp;gt;Die (batteriebetriebenen) -PCB-Aktoren und die 8-Kanal-Module haben kleine LED an Bord, die für Diagnosezwecke hilfreich sind, einem sparsamen Betrieb aber in der Regel entgegenstehen. Sie werden daher nur bei außergewöhnlichen Zuständen wie dem Anlernmodus, einem Reset, oder auch bei niedriger Batteriespannung als Hinweis an den Anwender benutzt und sind ansonsten ab Werk deaktiviert. Bei einer Dauerstromversorgung kann aber eine Schaltzustandsanzeige oder eine Quittung über eine Befehlsaussendung nicht nur zur Diagnose hilfreich sein. Die LED(s)zeigen dann bei Aktoren, ob der Aktor eingeschaltet ist (blinkend, wenn eine Einschaltzeitbegrenzung aktiv ist), und bei den Sensormodulen [[HM-MOD-EM-8_8-Kanal-Sendemodul|HM-Mod-EM-8]] und [[HM-MOD-EM-8bit_3-Kanal-Sendemodul_mit_8-Bit-Datenkanal|HM-Mod-EM-8bit]] zeigt die zweifarbige LED den von Fernbedienungen bekannten Sendezustand mit gelb, dem dann ein grün oder rot folgt - je nachdem ob eine Quittung angefordert ist und ob sie erfolgreich empfangen wurde.&lt;br /&gt;
|-&lt;br /&gt;
| localResDis || local reset disabled = Zurücksetzen am Gerät unmöglich. &#039;&#039;&#039;on&#039;&#039;&#039; bedeutet, dass das Gerät nicht mehr mit der Konfigurationstaste zurückgesetzt werden kann. &#039;&#039;&#039;off&#039;&#039; = Reset möglich (voreingestellt)&lt;br /&gt;
|-&lt;br /&gt;
| pairCentral || pairing to cental = angelernt an Zentrale. Wert wird hexadezimal dargestellt (000000 bis FFFFFF). 0 bedeutet, dass das Gerät nicht gepairt ist, anderenfalls ist der Wert die [[hmId]] der Zentrale.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalbezogene Register ===&lt;br /&gt;
Kanalbezogene Register existieren für jeden Kanal eines Gerätes einmal und werden in der sogenannten &#039;&#039;&#039;List1&#039;&#039;&#039; gespeichert (in der FHEM-Oberfläche als Hexbytefolge unter &#039;&#039;RegL_01.&#039;&#039; zu finden). &lt;br /&gt;
&lt;br /&gt;
(to be continued). Beispiele: sign, dblPress, longPress, expectAES, peerNeedsBurst, ...&lt;br /&gt;
&lt;br /&gt;
=== Platzhalter für Erklärung der List2 ===&lt;br /&gt;
&lt;br /&gt;
=== Verknüpfungsbezogene Register ===&lt;br /&gt;
Diese Register sind am umfangreichsten und werden für jeden Verknüpfungspartner (peer) einzeln separat angelegt in der &#039;&#039;&#039;List3&#039;&#039;&#039; (&#039;&#039;RegL_03.&amp;lt;peer&amp;gt;&#039;&#039;). Die grundsätzlichen Funktionen und ihre Zusammenhänge sind auch ausführlich in der Einsteigerdokumentation erklärt, inklusive Skizzen für die sogenannte &#039;&#039;state machine&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Diese Register regeln das Verhalten eines Aktors beim Erhalt eines sog. Triggers. Tastensensoren senden &#039;&#039;short&#039;&#039;- und (automatisch wiederholte) &#039;&#039;long&#039;&#039;-Trigger bei kurzen bzw. längeren Tastendrücken. Für beide Arten gibt es relativ ähnliche Registergruppen, die genau festlegen, in welchem Zustand welcher Trigger welche Aktion auslöst. Einen Sonderfall stellen Zustandsmelder dar (Fensterkontakte, Schaltkontaktinterfaces, aber auch Bewegungsmelder), die einmalige Trigger mit einem Wert zwischen 0 und 200 senden. Für diese gelten ebenfalls die short-Registersätze.&lt;br /&gt;
&lt;br /&gt;
Jedes Register setzt sich prinzipiell also zusammen&lt;br /&gt;
* aus einer Unterscheidung, ob sie für short- oder long-Trigger gelten (sh bzw. lg)&lt;br /&gt;
* Aktionswunsch (action) / Bedingung (condition, ct) / Sprungquelle (DimJt bzw. SwJt bei Dimmer/Schaltern) oder Zustand (Off, OnDly, RampOn, On, OffDly, RampOff)&lt;br /&gt;
* der eigentlichen Einstellungsmöglichkeit (Variable)&lt;br /&gt;
Der zugewiesene Registerwert steuert dann die Aktion entsprechend.&lt;br /&gt;
&lt;br /&gt;
=== Platzhalter für weitere Listen ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TEXTBAUSTEINSPEICHER (wird entfernt)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Mögliche Aktionstypen bei Tastendruck:&lt;br /&gt;
- off: Es erfolgt keine Aktion&lt;br /&gt;
- downDim: Herunterdimmen bei langem Tastendruck (peer dual)&lt;br /&gt;
- upDim: Hochdimmen bei langem Tastendruck (peer dual&lt;br /&gt;
- toggleDim:  Herunter.oder Hochdimmen bei langem Tastendruck, wechselt (Eintastenb, peer single)&lt;br /&gt;
- jmpToTarget: Springe zum definierten Sprungziel&lt;br /&gt;
- toggleDimToCntInv?&lt;br /&gt;
- toggleDimToCnt?&lt;br /&gt;
- toggleToCntInv?&lt;br /&gt;
- toggleToCnt?&lt;br /&gt;
Triggerschwellen für Werte (jeweils zwei für short und long-Trigger)&lt;br /&gt;
- [sh|lg]CtValHi: hoher Triggerwert (High) für Short/Long (0-255, normal 100)&lt;br /&gt;
- [sh|lg]CtValLo: niedriger Triggerwert (Low) für Short/Long (0-255, normal 50)&lt;br /&gt;
Mögliche Bedingungen für einen Trigger (Trigger ist erfüllt, wenn bereitgestellter Wert …)&lt;br /&gt;
- ltLo/ltHi (less than low/high): niedriger als Low/High&lt;br /&gt;
- geLo/geHi (greater than or equal low/high) gleich oder höher als High&lt;br /&gt;
- between: zwischen Low und High, also über/gleich Low und kleiner/gleich High&lt;br /&gt;
- outside: kleiner als Low und größer als High&lt;br /&gt;
Die Triggerbedingungen gibt es getrennt für jeden aktuellen Zustand des Dimm-Aktors:&lt;br /&gt;
- [sh|lg]Ct[Off|DlyOn|RampOn|On|DlyOff|RampOff|Off], insgesamt 12&lt;br /&gt;
Sprungquellen und Sprungziele: Bei Eintreffen eines gültigen Triggers wird von einem Zustand in einen anderen Zustand gesprungen. Hier gibt es&lt;br /&gt;
- DimJt...&lt;br /&gt;
&lt;br /&gt;
Relevante ähnliche Informationen / Details hier: [https://homematic-forum.de/forum/viewtopic.php?t=7508 Expertenmode: Aktionstypen bei einer Direktverknüpfung]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:HomeMatic Components]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Homematic-Register_von_A-Z_(Namen,_Erkl%C3%A4rung)&amp;diff=30748</id>
		<title>Homematic-Register von A-Z (Namen, Erklärung)</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Homematic-Register_von_A-Z_(Namen,_Erkl%C3%A4rung)&amp;diff=30748"/>
		<updated>2019-06-12T21:52:52Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* energyOpt */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Bitte noch an geeigneten Stellen Links auf diese Seite einfügen --&amp;gt;&lt;br /&gt;
{{Baustelle}}&lt;br /&gt;
Dieser Artikel soll die Namensgebung der Homematic-Register erklären und einen Index aller bekannten Register mit einer kurzen Funktionserklärung liefern. Der Index folgt dabei den Registerklassen, da sich die Namensgebung diesbezüglich ebenfalls unterscheidet.&lt;br /&gt;
&lt;br /&gt;
Zur grundsätzlichen Anwendung von Registerprogrammierung mit einigen Beispielen siehe u.a. den Artikel [[HomeMatic Register programmieren]] und [[HomeMatic HmInfo Templates erstellen]].&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
&lt;br /&gt;
Die Namenskonvention der Homematic-Register ist für den Neuling verwirrend, folgt jedoch fast durchgängig einer einfachen Logik&lt;br /&gt;
* er setzt sich aus einem oder mehreren Bestandteilen zusammen&lt;br /&gt;
* er beginnt immer mit einem Kleinbuchstaben&lt;br /&gt;
* jeder weitere Namensbestandteil beginnt mit einem Großbuchstaben&lt;br /&gt;
* die Bezeichnungen der Bestandteile sind englisch, kurze Begriffe werden ausgeschrieben, längere abgekürzt&lt;br /&gt;
&lt;br /&gt;
Die möglichen Bestandteile werden in den jeweiligen Registergruppen (Listen) erläutert. &lt;br /&gt;
&lt;br /&gt;
Details zu den Wertebereichen sowie eine kurze englische Beschreibung liefert der Befehl &#039;&#039;&#039;reglist&#039;&#039;&#039; in Geräten und Kanälen.&lt;br /&gt;
&lt;br /&gt;
== Die Registerklassen (Listen) eines Homematic-Gerätes ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Designvorschlag 1: Unterkapitel mit Inhaltsverzeichniseintrag&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Jedes Homematic-Gerät besitzt prinzipiell geräte-, kanal- und verknüpfungsbezogene Register. Bei Geräten, die nur einen sogenannten Kanal besitzen, erscheinen alle drei Register gemeinsam in der Definitionsansicht und den Listings in FHEM, bei Geräten mit mehreren Kanälen findet man die verknüfungs- und kanalbezogenen Register in den jeweiligen Kanälen.&lt;br /&gt;
&lt;br /&gt;
=== Gerätebezogene Register ===&lt;br /&gt;
Gerätebezogene Register existieren für jedes HomeMatic-Gerät nur einmal und werden in der sogenannten &#039;&#039;&#039;List0&#039;&#039;&#039; gespeichert (in der FHEM-Oberfläche als Hexbytefolge unter &#039;&#039;RegL_00.&#039;&#039; zu finden).&lt;br /&gt;
&lt;br /&gt;
==== brightness====&lt;br /&gt;
brightness = Helligkeit. Wertebereich: 0-15. Steuert die Helligkeit der LED-Anzeige. Verwendet in: [[HM-OU-LED16]]. &lt;br /&gt;
&lt;br /&gt;
==== energyOpt ====&lt;br /&gt;
energy option = Energieoptionen. Wertebereich: 0 to 127 (Sekunden), zusätzlich &amp;quot;permanent&amp;quot; (dauerhaft). Einschaltdauer des Displays [[HM-OU-LED16]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Designvorschlag 2: Tabelle&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Register !! Erläuterungen&lt;br /&gt;
|-&lt;br /&gt;
| brightness || brightness = Helligkeit. Wertebereich: 0-15. Steuert die Helligkeit der LED-Anzeige. Verwendet in: [[HM-OU-LED16]].&lt;br /&gt;
|-&lt;br /&gt;
| confBtnTime || configuration button timeout. Wertangabe in Minuten (!) oder &#039;&#039;permanent&#039;&#039;&amp;lt;br&amp;gt;Nicht immer sind die internen Tasten eines Gerätes ohne weiteres mit Aktionen für kurzen und langen Tastendruck programmierbar. Bei allen Hutschienen-Aktoren sowie den Zwischensteckern (mit nur einem Bedienknopf) versetzt ein langer Tastendruck (4 Sekunden) den Schalter normalerweise in den Konfigurations- bzw. Anlern-Modus, bei den in Unterputzdosen versenkbaren Schalt- und Dimmaktoren (-FM ohne PBU in der Bezeichnung) ohne eigenen Konfigurations-Button gilt dies sogar für die zur normalen Funktion extern angeschlossenen Taster. Dieses Verhalten kann man mit dem Register &#039;&#039;confBtnTime&#039;&#039; beeinflussen. Bis zum Ablauf der dort einstellbaren Zeit (in Minuten) nach dem Versorgen mit Strom (&#039;&#039;powerUp&#039;&#039;) erreicht man den Konfigurationsmodus wie bisher, danach interpretiert der Aktor die Tastendrücke stets als kurz (short) oder lang (long).&lt;br /&gt;
|- &lt;br /&gt;
| energyOpt || energy option = Energieoptionen. Wertebereich: 0 to 127 (Sekunden), zusätzlich &#039;&#039;permanent&#039;&#039; (dauerhaft). Einschaltdauer des Displays [[HM-OU-LED16]]. &lt;br /&gt;
|-&lt;br /&gt;
| intKeyVisib || internal key(s) visible = interne Taste(n) sichtbar. Werte: &#039;&#039;visib&#039;&#039; = sichtbar bzw. &#039;&#039;invisib&#039;&#039; = unsichtbar (voreingestellt).&amp;lt;br&amp;gt;Die internen &amp;quot;Tasten&amp;quot; eines Aktors (z.B. die Schaltwippe bei Wandschaltern/-tastern, der Bedienknopf bei Zwischensteckern, aber auch die angeschlossenen externen Taster bei Aktoren für Unterputzdosen oder die von außen zugängliche &amp;quot;Notbedientaste&amp;quot; etwa bei Zwischendecken-Dimmern) sind logisch ebenso mit dem Aktor verknüpft wie externe Bedienelemente wie Funkfernbedienungen oder per Funk verknüpfte Wandtaster. Ihre Betätigung wird (außer mit präparierter Firmware) zwar nicht gesendet (und kann daher von FHEM nicht &amp;quot;gelesen&amp;quot; werden), die vom Hersteller vorgesehenen Funktionen lassen sich aber genauso frei programmieren. Allerdings sind diese internen Verknüpfungen zur Vermeidung versehentlicher Programmierungen zunächst verborgen und müssen daher vor einer Manipulation explizit sichtbar gemacht werden. &lt;br /&gt;
|-&lt;br /&gt;
| ledMode || led modus = LED-Betriebsart, &#039;&#039;on&#039;&#039; bzw. &#039;&#039;off&#039;&#039;.&amp;lt;br&amp;gt;Die (batteriebetriebenen) -PCB-Aktoren und die 8-Kanal-Module haben kleine LED an Bord, die für Diagnosezwecke hilfreich sind, einem sparsamen Betrieb aber in der Regel entgegenstehen. Sie werden daher nur bei außergewöhnlichen Zuständen wie dem Anlernmodus, einem Reset, oder auch bei niedriger Batteriespannung als Hinweis an den Anwender benutzt und sind ansonsten ab Werk deaktiviert. Bei einer Dauerstromversorgung kann aber eine Schaltzustandsanzeige oder eine Quittung über eine Befehlsaussendung nicht nur zur Diagnose hilfreich sein. Die LED(s)zeigen dann bei Aktoren, ob der Aktor eingeschaltet ist (blinkend, wenn eine Einschaltzeitbegrenzung aktiv ist), und bei den Sensormodulen [[HM-MOD-EM-8_8-Kanal-Sendemodul|HM-Mod-EM-8]] und [[HM-MOD-EM-8bit_3-Kanal-Sendemodul_mit_8-Bit-Datenkanal|HM-Mod-EM8bit]] zeigt die zweifarbige LED den von Fernbedienungen bekannten Sendezustand mit gelb, dem dann ein grün oder rot folgt - je nachdem ob eine Quittung angefordert ist und ob sie erfolgreich empfangen wurde.&lt;br /&gt;
|-&lt;br /&gt;
| localResDis || local reset disabled = Zurücksetzen am Gerät unmöglich. &#039;&#039;&#039;on&#039;&#039;&#039; bedeutet, dass das Gerät nicht mehr mit der Konfigurationstaste zurückgesetzt werden kann. &#039;&#039;&#039;off&#039;&#039; = Reset möglich (voreingestellt)&lt;br /&gt;
|-&lt;br /&gt;
| pairCentral || pairing to cental = angelernt an Zentrale. Wert wird hexadezimal dargestellt (000000 bis FFFFFF). 0 bedeutet, dass das Gerät nicht gepairt ist, anderenfalls ist der Wert die [[hmId]] der Zentrale.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalbezogene Register ===&lt;br /&gt;
Kanalbezogene Register existieren für jeden Kanal eines Gerätes einmal und werden in der sogenannten &#039;&#039;&#039;List1&#039;&#039;&#039; gespeichert (in der FHEM-Oberfläche als Hexbytefolge unter &#039;&#039;RegL_01.&#039;&#039; zu finden). &lt;br /&gt;
&lt;br /&gt;
(to be continued). Beispiele: sign, dblPress, longPress, expectAES, peerNeedsBurst, ...&lt;br /&gt;
&lt;br /&gt;
=== Platzhalter für Erklärung der List2 ===&lt;br /&gt;
&lt;br /&gt;
=== Verknüpfungsbezogene Register ===&lt;br /&gt;
Diese Register sind am umfangreichsten und werden für jeden Verknüpfungspartner (peer) einzeln separat angelegt in der &#039;&#039;&#039;List3&#039;&#039;&#039; (&#039;&#039;RegL_03.&amp;lt;peer&amp;gt;&#039;&#039;). Die grundsätzlichen Funktionen und ihre Zusammenhänge sind auch ausführlich in der Einsteigerdokumentation erklärt, inklusive Skizzen für die sogenannte &#039;&#039;state machine&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Diese Register regeln das Verhalten eines Aktors beim Erhalt eines sog. Triggers. Tastensensoren senden &#039;&#039;short&#039;&#039;- und (automatisch wiederholte) &#039;&#039;long&#039;&#039;-Trigger bei kurzen bzw. längeren Tastendrücken. Für beide Arten gibt es relativ ähnliche Registergruppen, die genau festlegen, in welchem Zustand welcher Trigger welche Aktion auslöst. Einen Sonderfall stellen Zustandsmelder dar (Fensterkontakte, Schaltkontaktinterfaces, aber auch Bewegungsmelder), die einmalige Trigger mit einem Wert zwischen 0 und 200 senden. Für diese gelten ebenfalls die short-Registersätze.&lt;br /&gt;
&lt;br /&gt;
Jedes Register setzt sich prinzipiell also zusammen&lt;br /&gt;
* aus einer Unterscheidung, ob sie für short- oder long-Trigger gelten (sh bzw. lg)&lt;br /&gt;
* Aktionswunsch (action) / Bedingung (condition, ct) / Sprungquelle (DimJt bzw. SwJt bei Dimmer/Schaltern) oder Zustand (Off, OnDly, RampOn, On, OffDly, RampOff)&lt;br /&gt;
* der eigentlichen Einstellungsmöglichkeit (Variable)&lt;br /&gt;
Der zugewiesene Registerwert steuert dann die Aktion entsprechend.&lt;br /&gt;
&lt;br /&gt;
=== Platzhalter für weitere Listen ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TEXTBAUSTEINSPEICHER (wird entfernt)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Mögliche Aktionstypen bei Tastendruck:&lt;br /&gt;
- off: Es erfolgt keine Aktion&lt;br /&gt;
- downDim: Herunterdimmen bei langem Tastendruck (peer dual)&lt;br /&gt;
- upDim: Hochdimmen bei langem Tastendruck (peer dual&lt;br /&gt;
- toggleDim:  Herunter.oder Hochdimmen bei langem Tastendruck, wechselt (Eintastenb, peer single)&lt;br /&gt;
- jmpToTarget: Springe zum definierten Sprungziel&lt;br /&gt;
- toggleDimToCntInv?&lt;br /&gt;
- toggleDimToCnt?&lt;br /&gt;
- toggleToCntInv?&lt;br /&gt;
- toggleToCnt?&lt;br /&gt;
Triggerschwellen für Werte (jeweils zwei für short und long-Trigger)&lt;br /&gt;
- [sh|lg]CtValHi: hoher Triggerwert (High) für Short/Long (0-255, normal 100)&lt;br /&gt;
- [sh|lg]CtValLo: niedriger Triggerwert (Low) für Short/Long (0-255, normal 50)&lt;br /&gt;
Mögliche Bedingungen für einen Trigger (Trigger ist erfüllt, wenn bereitgestellter Wert …)&lt;br /&gt;
- ltLo/ltHi (less than low/high): niedriger als Low/High&lt;br /&gt;
- geLo/geHi (greater than or equal low/high) gleich oder höher als High&lt;br /&gt;
- between: zwischen Low und High, also über/gleich Low und kleiner/gleich High&lt;br /&gt;
- outside: kleiner als Low und größer als High&lt;br /&gt;
Die Triggerbedingungen gibt es getrennt für jeden aktuellen Zustand des Dimm-Aktors:&lt;br /&gt;
- [sh|lg]Ct[Off|DlyOn|RampOn|On|DlyOff|RampOff|Off], insgesamt 12&lt;br /&gt;
Sprungquellen und Sprungziele: Bei Eintreffen eines gültigen Triggers wird von einem Zustand in einen anderen Zustand gesprungen. Hier gibt es&lt;br /&gt;
- DimJt...&lt;br /&gt;
&lt;br /&gt;
Relevante ähnliche Informationen / Details hier: [https://homematic-forum.de/forum/viewtopic.php?t=7508 Expertenmode: Aktionstypen bei einer Direktverknüpfung]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:HomeMatic Components]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Homematic-Register_von_A-Z_(Namen,_Erkl%C3%A4rung)&amp;diff=30747</id>
		<title>Homematic-Register von A-Z (Namen, Erklärung)</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Homematic-Register_von_A-Z_(Namen,_Erkl%C3%A4rung)&amp;diff=30747"/>
		<updated>2019-06-12T21:51:24Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* energyOpt */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Bitte noch an geeigneten Stellen Links auf diese Seite einfügen --&amp;gt;&lt;br /&gt;
{{Baustelle}}&lt;br /&gt;
Dieser Artikel soll die Namensgebung der Homematic-Register erklären und einen Index aller bekannten Register mit einer kurzen Funktionserklärung liefern. Der Index folgt dabei den Registerklassen, da sich die Namensgebung diesbezüglich ebenfalls unterscheidet.&lt;br /&gt;
&lt;br /&gt;
Zur grundsätzlichen Anwendung von Registerprogrammierung mit einigen Beispielen siehe u.a. den Artikel [[HomeMatic Register programmieren]] und [[HomeMatic HmInfo Templates erstellen]].&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
&lt;br /&gt;
Die Namenskonvention der Homematic-Register ist für den Neuling verwirrend, folgt jedoch fast durchgängig einer einfachen Logik&lt;br /&gt;
* er setzt sich aus einem oder mehreren Bestandteilen zusammen&lt;br /&gt;
* er beginnt immer mit einem Kleinbuchstaben&lt;br /&gt;
* jeder weitere Namensbestandteil beginnt mit einem Großbuchstaben&lt;br /&gt;
* die Bezeichnungen der Bestandteile sind englisch, kurze Begriffe werden ausgeschrieben, längere abgekürzt&lt;br /&gt;
&lt;br /&gt;
Die möglichen Bestandteile werden in den jeweiligen Registergruppen (Listen) erläutert. &lt;br /&gt;
&lt;br /&gt;
Details zu den Wertebereichen sowie eine kurze englische Beschreibung liefert der Befehl &#039;&#039;&#039;reglist&#039;&#039;&#039; in Geräten und Kanälen.&lt;br /&gt;
&lt;br /&gt;
== Die Registerklassen (Listen) eines Homematic-Gerätes ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Designvorschlag 1: Unterkapitel mit Inhaltsverzeichniseintrag&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Jedes Homematic-Gerät besitzt prinzipiell geräte-, kanal- und verknüpfungsbezogene Register. Bei Geräten, die nur einen sogenannten Kanal besitzen, erscheinen alle drei Register gemeinsam in der Definitionsansicht und den Listings in FHEM, bei Geräten mit mehreren Kanälen findet man die verknüfungs- und kanalbezogenen Register in den jeweiligen Kanälen.&lt;br /&gt;
&lt;br /&gt;
=== Gerätebezogene Register ===&lt;br /&gt;
Gerätebezogene Register existieren für jedes HomeMatic-Gerät nur einmal und werden in der sogenannten &#039;&#039;&#039;List0&#039;&#039;&#039; gespeichert (in der FHEM-Oberfläche als Hexbytefolge unter &#039;&#039;RegL_00.&#039;&#039; zu finden).&lt;br /&gt;
&lt;br /&gt;
==== brightness====&lt;br /&gt;
brightness = Helligkeit. Wertebereich: 0-15. Steuert die Helligkeit der LED-Anzeige. Verwendet in: [[HM-OU-LED16]]. &lt;br /&gt;
&lt;br /&gt;
==== energyOpt ====&lt;br /&gt;
energy option = Energieoptionen. Wertebereich: 0 to 127 (Sekunden), zusätzlich &amp;quot;permanent&amp;quot; (dauerhaft). Einschaltdauer des Displays [[HM-OU-LED16]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Designvorschlag 2: Tabelle&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Register !! Erläuterungen&lt;br /&gt;
|-&lt;br /&gt;
| brightness || brightness = Helligkeit. Wertebereich: 0-15. Steuert die Helligkeit der LED-Anzeige. Verwendet in: [[HM-OU-LED16]].&lt;br /&gt;
|-&lt;br /&gt;
| confBtnTime || configuration button timeout. Wertangabe in Minuten (!) oder &#039;&#039;permanent&#039;&#039;&amp;lt;br&amp;gt;Nicht immer sind die internen Tasten eines Gerätes ohne weiteres mit Aktionen für kurzen und langen Tastendruck programmierbar. Bei allen Hutschienen-Aktoren sowie den Zwischensteckern (mit nur einem Bedienknopf) versetzt ein langer Tastendruck (4 Sekunden) den Schalter normalerweise in den Konfigurations- bzw. Anlern-Modus, bei den in Unterputzdosen versenkbaren Schalt- und Dimmaktoren (-FM ohne PBU in der Bezeichnung) ohne eigenen Konfigurations-Button gilt dies sogar für die zur normalen Funktion extern angeschlossenen Taster. Dieses Verhalten kann man mit dem Register &#039;&#039;confBtnTime&#039;&#039; beeinflussen. Bis zum Ablauf der dort einstellbaren Zeit (in Minuten) nach dem Versorgen mit Strom (&#039;&#039;powerUp&#039;&#039;) erreicht man den Konfigurationsmodus wie bisher, danach interpretiert der Aktor die Tastendrücke stets als kurz (short) oder lang (long).&lt;br /&gt;
|- &lt;br /&gt;
| energyOpt || energy option = Energieoptionen. Wertebereich: 0 to 127 (Sekunden), zusätzlich &#039;&#039;permanent&#039;&#039; (dauerhaft). Einschaltdauer des Displays [[HM-OU-LED16]]. &lt;br /&gt;
|-&lt;br /&gt;
| intKeyVisib || internal key(s) visible = interne Taste(n) sichtbar. Werte: &#039;&#039;visib&#039;&#039; = sichtbar bzw. &#039;&#039;invisib&#039;&#039; = unsichtbar (voreingestellt).&amp;lt;br&amp;gt;Die internen &amp;quot;Tasten&amp;quot; eines Aktors (z.B. die Schaltwippe bei Wandschaltern/-tastern, der Bedienknopf bei Zwischensteckern, aber auch die angeschlossenen externen Taster bei Aktoren für Unterputzdosen oder die von außen zugängliche &amp;quot;Notbedientaste&amp;quot; etwa bei Zwischendecken-Dimmern) sind logisch ebenso mit dem Aktor verknüpft wie externe Bedienelemente wie Funkfernbedienungen oder per Funk verknüpfte Wandtaster. Ihre Betätigung wird (außer mit präparierter Firmware) zwar nicht gesendet (und kann daher von FHEM nicht &amp;quot;gelesen&amp;quot; werden), die vom Hersteller vorgesehenen Funktionen lassen sich aber genauso frei programmieren. Allerdings sind diese internen Verknüpfungen zur Vermeidung versehentlicher Programmierungen zunächst verborgen und müssen daher vor einer Manipulation explizit sichtbar gemacht werden. &lt;br /&gt;
|-&lt;br /&gt;
| ledMode || led modus = LED-Betriebsart, &#039;&#039;on&#039;&#039; bzw. &#039;&#039;off&#039;&#039;.&amp;lt;br&amp;gt;Die (batteriebetriebenen) -PCB-Aktoren und die 8-Kanal-Module haben kleine LED an Bord, die für Diagnosezwecke hilfreich sind, einem sparsamen Betrieb aber in der Regel entgegenstehen. Sie werden daher nur bei außergewöhnlichen Zuständen wie dem Anlernmodus, einem Reset, oder auch bei niedriger Batteriespannung als Hinweis an den Anwender benutzt und sind ansonsten ab Werk deaktiviert. Bei einer Dauerstromversorgung kann aber eine Schaltzustandsanzeige oder eine Quittung über eine Befehlsaussendung nicht nur zur Diagnose hilfreich sein. Die LED(s)zeigen dann bei Aktoren, ob der Aktor eingeschaltet ist (blinkend, wenn eine Einschaltzeitbegrenzung aktiv ist), und bei den Sensormodulen [[HM-MOD-EM-8_8-Kanal-Sendemodul|HM-Mod-EM8]] und [[HM-MOD-EM-8bit_3-Kanal-Sendemodul_mit_8-Bit-Datenkanal|HM-Mod-EM8bit]] zeigt die zweifarbige LED den von Fernbedienungen bekannten Sendezustand mit gelb, dem dann ein grün oder rot folgt - je nachdem ob eine Quittung angefordert ist und ob sie erfolgreich empfangen wurde.&lt;br /&gt;
|-&lt;br /&gt;
| localResDis || local reset disabled = Zurücksetzen am Gerät unmöglich. &#039;&#039;&#039;on&#039;&#039;&#039; bedeutet, dass das Gerät nicht mehr mit der Konfigurationstaste zurückgesetzt werden kann. &#039;&#039;&#039;off&#039;&#039; = Reset möglich (voreingestellt)&lt;br /&gt;
|-&lt;br /&gt;
| pairCentral || pairing to cental = angelernt an Zentrale. Wert wird hexadezimal dargestellt (000000 bis FFFFFF). 0 bedeutet, dass das Gerät nicht gepairt ist, anderenfalls ist der Wert die [[hmId]] der Zentrale.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalbezogene Register ===&lt;br /&gt;
Kanalbezogene Register existieren für jeden Kanal eines Gerätes einmal und werden in der sogenannten &#039;&#039;&#039;List1&#039;&#039;&#039; gespeichert (in der FHEM-Oberfläche als Hexbytefolge unter &#039;&#039;RegL_01.&#039;&#039; zu finden). &lt;br /&gt;
&lt;br /&gt;
(to be continued). Beispiele: sign, dblPress, longPress, expectAES, peerNeedsBurst, ...&lt;br /&gt;
&lt;br /&gt;
=== Platzhalter für Erklärung der List2 ===&lt;br /&gt;
&lt;br /&gt;
=== Verknüpfungsbezogene Register ===&lt;br /&gt;
Diese Register sind am umfangreichsten und werden für jeden Verknüpfungspartner (peer) einzeln separat angelegt in der &#039;&#039;&#039;List3&#039;&#039;&#039; (&#039;&#039;RegL_03.&amp;lt;peer&amp;gt;&#039;&#039;). Die grundsätzlichen Funktionen und ihre Zusammenhänge sind auch ausführlich in der Einsteigerdokumentation erklärt, inklusive Skizzen für die sogenannte &#039;&#039;state machine&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Diese Register regeln das Verhalten eines Aktors beim Erhalt eines sog. Triggers. Tastensensoren senden &#039;&#039;short&#039;&#039;- und (automatisch wiederholte) &#039;&#039;long&#039;&#039;-Trigger bei kurzen bzw. längeren Tastendrücken. Für beide Arten gibt es relativ ähnliche Registergruppen, die genau festlegen, in welchem Zustand welcher Trigger welche Aktion auslöst. Einen Sonderfall stellen Zustandsmelder dar (Fensterkontakte, Schaltkontaktinterfaces, aber auch Bewegungsmelder), die einmalige Trigger mit einem Wert zwischen 0 und 200 senden. Für diese gelten ebenfalls die short-Registersätze.&lt;br /&gt;
&lt;br /&gt;
Jedes Register setzt sich prinzipiell also zusammen&lt;br /&gt;
* aus einer Unterscheidung, ob sie für short- oder long-Trigger gelten (sh bzw. lg)&lt;br /&gt;
* Aktionswunsch (action) / Bedingung (condition, ct) / Sprungquelle (DimJt bzw. SwJt bei Dimmer/Schaltern) oder Zustand (Off, OnDly, RampOn, On, OffDly, RampOff)&lt;br /&gt;
* der eigentlichen Einstellungsmöglichkeit (Variable)&lt;br /&gt;
Der zugewiesene Registerwert steuert dann die Aktion entsprechend.&lt;br /&gt;
&lt;br /&gt;
=== Platzhalter für weitere Listen ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TEXTBAUSTEINSPEICHER (wird entfernt)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Mögliche Aktionstypen bei Tastendruck:&lt;br /&gt;
- off: Es erfolgt keine Aktion&lt;br /&gt;
- downDim: Herunterdimmen bei langem Tastendruck (peer dual)&lt;br /&gt;
- upDim: Hochdimmen bei langem Tastendruck (peer dual&lt;br /&gt;
- toggleDim:  Herunter.oder Hochdimmen bei langem Tastendruck, wechselt (Eintastenb, peer single)&lt;br /&gt;
- jmpToTarget: Springe zum definierten Sprungziel&lt;br /&gt;
- toggleDimToCntInv?&lt;br /&gt;
- toggleDimToCnt?&lt;br /&gt;
- toggleToCntInv?&lt;br /&gt;
- toggleToCnt?&lt;br /&gt;
Triggerschwellen für Werte (jeweils zwei für short und long-Trigger)&lt;br /&gt;
- [sh|lg]CtValHi: hoher Triggerwert (High) für Short/Long (0-255, normal 100)&lt;br /&gt;
- [sh|lg]CtValLo: niedriger Triggerwert (Low) für Short/Long (0-255, normal 50)&lt;br /&gt;
Mögliche Bedingungen für einen Trigger (Trigger ist erfüllt, wenn bereitgestellter Wert …)&lt;br /&gt;
- ltLo/ltHi (less than low/high): niedriger als Low/High&lt;br /&gt;
- geLo/geHi (greater than or equal low/high) gleich oder höher als High&lt;br /&gt;
- between: zwischen Low und High, also über/gleich Low und kleiner/gleich High&lt;br /&gt;
- outside: kleiner als Low und größer als High&lt;br /&gt;
Die Triggerbedingungen gibt es getrennt für jeden aktuellen Zustand des Dimm-Aktors:&lt;br /&gt;
- [sh|lg]Ct[Off|DlyOn|RampOn|On|DlyOff|RampOff|Off], insgesamt 12&lt;br /&gt;
Sprungquellen und Sprungziele: Bei Eintreffen eines gültigen Triggers wird von einem Zustand in einen anderen Zustand gesprungen. Hier gibt es&lt;br /&gt;
- DimJt...&lt;br /&gt;
&lt;br /&gt;
Relevante ähnliche Informationen / Details hier: [https://homematic-forum.de/forum/viewtopic.php?t=7508 Expertenmode: Aktionstypen bei einer Direktverknüpfung]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:HomeMatic Components]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Homematic-Register_von_A-Z_(Namen,_Erkl%C3%A4rung)&amp;diff=30746</id>
		<title>Homematic-Register von A-Z (Namen, Erklärung)</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Homematic-Register_von_A-Z_(Namen,_Erkl%C3%A4rung)&amp;diff=30746"/>
		<updated>2019-06-12T21:49:38Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* energyOpt */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Bitte noch an geeigneten Stellen Links auf diese Seite einfügen --&amp;gt;&lt;br /&gt;
{{Baustelle}}&lt;br /&gt;
Dieser Artikel soll die Namensgebung der Homematic-Register erklären und einen Index aller bekannten Register mit einer kurzen Funktionserklärung liefern. Der Index folgt dabei den Registerklassen, da sich die Namensgebung diesbezüglich ebenfalls unterscheidet.&lt;br /&gt;
&lt;br /&gt;
Zur grundsätzlichen Anwendung von Registerprogrammierung mit einigen Beispielen siehe u.a. den Artikel [[HomeMatic Register programmieren]] und [[HomeMatic HmInfo Templates erstellen]].&lt;br /&gt;
&lt;br /&gt;
== Einführung ==&lt;br /&gt;
&lt;br /&gt;
Die Namenskonvention der Homematic-Register ist für den Neuling verwirrend, folgt jedoch fast durchgängig einer einfachen Logik&lt;br /&gt;
* er setzt sich aus einem oder mehreren Bestandteilen zusammen&lt;br /&gt;
* er beginnt immer mit einem Kleinbuchstaben&lt;br /&gt;
* jeder weitere Namensbestandteil beginnt mit einem Großbuchstaben&lt;br /&gt;
* die Bezeichnungen der Bestandteile sind englisch, kurze Begriffe werden ausgeschrieben, längere abgekürzt&lt;br /&gt;
&lt;br /&gt;
Die möglichen Bestandteile werden in den jeweiligen Registergruppen (Listen) erläutert. &lt;br /&gt;
&lt;br /&gt;
Details zu den Wertebereichen sowie eine kurze englische Beschreibung liefert der Befehl &#039;&#039;&#039;reglist&#039;&#039;&#039; in Geräten und Kanälen.&lt;br /&gt;
&lt;br /&gt;
== Die Registerklassen (Listen) eines Homematic-Gerätes ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Designvorschlag 1: Unterkapitel mit Inhaltsverzeichniseintrag&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Jedes Homematic-Gerät besitzt prinzipiell geräte-, kanal- und verknüpfungsbezogene Register. Bei Geräten, die nur einen sogenannten Kanal besitzen, erscheinen alle drei Register gemeinsam in der Definitionsansicht und den Listings in FHEM, bei Geräten mit mehreren Kanälen findet man die verknüfungs- und kanalbezogenen Register in den jeweiligen Kanälen.&lt;br /&gt;
&lt;br /&gt;
=== Gerätebezogene Register ===&lt;br /&gt;
Gerätebezogene Register existieren für jedes HomeMatic-Gerät nur einmal und werden in der sogenannten &#039;&#039;&#039;List0&#039;&#039;&#039; gespeichert (in der FHEM-Oberfläche als Hexbytefolge unter &#039;&#039;RegL_00.&#039;&#039; zu finden).&lt;br /&gt;
&lt;br /&gt;
==== brightness====&lt;br /&gt;
brightness = Helligkeit. Wertebereich: 0-15. Steuert die Helligkeit der LED-Anzeige. Verwendet in: [[HM-OU-LED16]]. &lt;br /&gt;
&lt;br /&gt;
==== energyOpt ====&lt;br /&gt;
energy option = Energieoptionen. Wertebereich: 0 to 127 (Sekunden), zusätzlich &amp;quot;permanent&amp;quot; (dauerhaft). Einschaltdauer des Displays [[HM-OU-LED16]]. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Designvorschlag 2: Tabelle&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Register !! Erläuterungen&lt;br /&gt;
|-&lt;br /&gt;
| brightness || brightness = Helligkeit. Wertebereich: 0-15. Steuert die Helligkeit der LED-Anzeige. Verwendet in: [[HM-OU-LED16]].&lt;br /&gt;
|-&lt;br /&gt;
| confBtnTime || configuration button timeout. Wertangabe in Minuten (!) oder &#039;&#039;permanent&#039;&#039;&amp;lt;br&amp;gt;Nicht immer sind die internen Tasten eines Gerätes ohne weiteres mit Aktionen für kurzen und langen Tastendruck programmierbar. Bei allen Hutschienen-Aktoren sowie den Zwischensteckern (mit nur einem Bedienknopf) versetzt ein langer Tastendruck (4 Sekunden) den Schalter normalerweise in den Konfigurations- bzw. Anlern-Modus, bei den in Unterputzdosen versenkbaren Schalt- und Dimmaktoren (-FM ohne PBU in der Bezeichnung) ohne eigenen Konfigurations-Button gilt dies sogar für die zur normalen Funktion extern angeschlossenen Taster. Dieses Verhalten kann man mit dem Register &#039;&#039;confBtnTime&#039;&#039; beeinflussen. Bis zum Ablauf der dort einstellbaren Zeit (in Minuten) nach dem Versorgen mit Strom (&#039;&#039;powerUp&#039;&#039;) erreicht man den Konfigurationsmodus wie bisher, danach interpretiert der Aktor die Tastendrücke stets als kurz (short) oder lang (long).&lt;br /&gt;
|- &lt;br /&gt;
| energyOpt || energy option = Energieoptionen. Wertebereich: 0 to 127 (Sekunden), zusätzlich &#039;&#039;permanent&#039;&#039; (dauerhaft). Einschaltdauer des Displays [[HM-OU-LED16]]. &lt;br /&gt;
|-&lt;br /&gt;
| intKeyVisib || internal key(s) visible = interne Taste(n) sichtbar. Werte: &#039;&#039;visib&#039;&#039; = sichtbar bzw. &#039;&#039;invisib&#039;&#039; = unsichtbar (voreingestellt).&amp;lt;br&amp;gt;Die internen &amp;quot;Tasten&amp;quot; eines Aktors (z.B. die Schaltwippe bei Wandschaltern/-tastern, der Bedienknopf bei Zwischensteckern, aber auch die angeschlossenen externen Taster bei Aktoren für Unterputzdosen oder die von außen zugängliche &amp;quot;Notbedientaste&amp;quot; etwa bei Zwischendecken-Dimmern) sind logisch ebenso mit dem Aktor verknüpft wie externe Bedienelemente wie Funkfernbedienungen oder per Funk verknüpfte Wandtaster. Ihre Betätigung wird (außer mit präparierter Firmware) zwar nicht gesendet (und kann daher von FHEM nicht &amp;quot;gelesen&amp;quot; werden), die vom Hersteller vorgesehenen Funktionen lassen sich aber genauso frei programmieren. Allerdings sind diese internen Verknüpfungen zur Vermeidung versehentlicher Programmierungen zunächst verborgen und müssen daher vor einer Manipulation explizit sichtbar gemacht werden. &lt;br /&gt;
|-&lt;br /&gt;
| ledMode || led modus = LED-Betriebsart, &#039;&#039;on&#039;&#039; bzw. &#039;&#039;off&#039;&#039;.&amp;lt;br&amp;gt;Die (batteriebetriebenen) -PCB-Aktoren und die 8-Kanal-Module haben kleine LED an Bord, die für Diagnosezwecke hilfreich sind, einem sparsamen Betrieb aber in der Regel entgegenstehen. Sie werden daher nur bei außergewöhnlichen Zuständen wie dem Anlernmodus, einem Reset, oder auch bei niedriger Batteriespannung als Hinweis an den Anwender benutzt und sind ansonsten ab Werk deaktiviert. Bei einer Dauerstromversorgung kann aber eine Schaltzustandsanzeige oder eine Quittung über eine Befehlsaussendung nicht nur zur Diagnose hilfreich sein. Die LED(s)zeigen dann bei Aktoren, ob der Aktor eingeschaltet ist (blinkend, wenn eine Einschaltzeitbegrenzung aktiv ist), und bei den Sensormodulen [[HM-MOD-EM-8_8-Kanal-Sendemodul|HM-Mod-EM8]] und [HM-Mod-EM8bit]] zeigt die zweifarbige LED den von Fernbedienungen bekannten Sendezustand mit gelb, dem dann ein grün oder rot folgt - je nachdem ob eine Quittung angefordert ist und ob sie erfolgreich empfangen wurde.&lt;br /&gt;
|-&lt;br /&gt;
| localResDis || local reset disabled = Zurücksetzen am Gerät unmöglich. &#039;&#039;&#039;on&#039;&#039;&#039; bedeutet, dass das Gerät nicht mehr mit der Konfigurationstaste zurückgesetzt werden kann. &#039;&#039;&#039;off&#039;&#039; = Reset möglich (voreingestellt)&lt;br /&gt;
|-&lt;br /&gt;
| pairCentral || pairing to cental = angelernt an Zentrale. Wert wird hexadezimal dargestellt (000000 bis FFFFFF). 0 bedeutet, dass das Gerät nicht gepairt ist, anderenfalls ist der Wert die [[hmId]] der Zentrale.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kanalbezogene Register ===&lt;br /&gt;
Kanalbezogene Register existieren für jeden Kanal eines Gerätes einmal und werden in der sogenannten &#039;&#039;&#039;List1&#039;&#039;&#039; gespeichert (in der FHEM-Oberfläche als Hexbytefolge unter &#039;&#039;RegL_01.&#039;&#039; zu finden). &lt;br /&gt;
&lt;br /&gt;
(to be continued). Beispiele: sign, dblPress, longPress, expectAES, peerNeedsBurst, ...&lt;br /&gt;
&lt;br /&gt;
=== Platzhalter für Erklärung der List2 ===&lt;br /&gt;
&lt;br /&gt;
=== Verknüpfungsbezogene Register ===&lt;br /&gt;
Diese Register sind am umfangreichsten und werden für jeden Verknüpfungspartner (peer) einzeln separat angelegt in der &#039;&#039;&#039;List3&#039;&#039;&#039; (&#039;&#039;RegL_03.&amp;lt;peer&amp;gt;&#039;&#039;). Die grundsätzlichen Funktionen und ihre Zusammenhänge sind auch ausführlich in der Einsteigerdokumentation erklärt, inklusive Skizzen für die sogenannte &#039;&#039;state machine&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
Diese Register regeln das Verhalten eines Aktors beim Erhalt eines sog. Triggers. Tastensensoren senden &#039;&#039;short&#039;&#039;- und (automatisch wiederholte) &#039;&#039;long&#039;&#039;-Trigger bei kurzen bzw. längeren Tastendrücken. Für beide Arten gibt es relativ ähnliche Registergruppen, die genau festlegen, in welchem Zustand welcher Trigger welche Aktion auslöst. Einen Sonderfall stellen Zustandsmelder dar (Fensterkontakte, Schaltkontaktinterfaces, aber auch Bewegungsmelder), die einmalige Trigger mit einem Wert zwischen 0 und 200 senden. Für diese gelten ebenfalls die short-Registersätze.&lt;br /&gt;
&lt;br /&gt;
Jedes Register setzt sich prinzipiell also zusammen&lt;br /&gt;
* aus einer Unterscheidung, ob sie für short- oder long-Trigger gelten (sh bzw. lg)&lt;br /&gt;
* Aktionswunsch (action) / Bedingung (condition, ct) / Sprungquelle (DimJt bzw. SwJt bei Dimmer/Schaltern) oder Zustand (Off, OnDly, RampOn, On, OffDly, RampOff)&lt;br /&gt;
* der eigentlichen Einstellungsmöglichkeit (Variable)&lt;br /&gt;
Der zugewiesene Registerwert steuert dann die Aktion entsprechend.&lt;br /&gt;
&lt;br /&gt;
=== Platzhalter für weitere Listen ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;TEXTBAUSTEINSPEICHER (wird entfernt)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Mögliche Aktionstypen bei Tastendruck:&lt;br /&gt;
- off: Es erfolgt keine Aktion&lt;br /&gt;
- downDim: Herunterdimmen bei langem Tastendruck (peer dual)&lt;br /&gt;
- upDim: Hochdimmen bei langem Tastendruck (peer dual&lt;br /&gt;
- toggleDim:  Herunter.oder Hochdimmen bei langem Tastendruck, wechselt (Eintastenb, peer single)&lt;br /&gt;
- jmpToTarget: Springe zum definierten Sprungziel&lt;br /&gt;
- toggleDimToCntInv?&lt;br /&gt;
- toggleDimToCnt?&lt;br /&gt;
- toggleToCntInv?&lt;br /&gt;
- toggleToCnt?&lt;br /&gt;
Triggerschwellen für Werte (jeweils zwei für short und long-Trigger)&lt;br /&gt;
- [sh|lg]CtValHi: hoher Triggerwert (High) für Short/Long (0-255, normal 100)&lt;br /&gt;
- [sh|lg]CtValLo: niedriger Triggerwert (Low) für Short/Long (0-255, normal 50)&lt;br /&gt;
Mögliche Bedingungen für einen Trigger (Trigger ist erfüllt, wenn bereitgestellter Wert …)&lt;br /&gt;
- ltLo/ltHi (less than low/high): niedriger als Low/High&lt;br /&gt;
- geLo/geHi (greater than or equal low/high) gleich oder höher als High&lt;br /&gt;
- between: zwischen Low und High, also über/gleich Low und kleiner/gleich High&lt;br /&gt;
- outside: kleiner als Low und größer als High&lt;br /&gt;
Die Triggerbedingungen gibt es getrennt für jeden aktuellen Zustand des Dimm-Aktors:&lt;br /&gt;
- [sh|lg]Ct[Off|DlyOn|RampOn|On|DlyOff|RampOff|Off], insgesamt 12&lt;br /&gt;
Sprungquellen und Sprungziele: Bei Eintreffen eines gültigen Triggers wird von einem Zustand in einen anderen Zustand gesprungen. Hier gibt es&lt;br /&gt;
- DimJt...&lt;br /&gt;
&lt;br /&gt;
Relevante ähnliche Informationen / Details hier: [https://homematic-forum.de/forum/viewtopic.php?t=7508 Expertenmode: Aktionstypen bei einer Direktverknüpfung]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:HomeMatic Components]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30745</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30745"/>
		<updated>2019-06-12T19:30:08Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben.&amp;lt;br&amp;gt;   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss ein geeignetes I2C Interface Modul (z.B. RPII2C, FRM oder NetzerI2C) zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Nachfolgend wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
	$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
	$content=~ m/received : (\d+) |/is;&lt;br /&gt;
	$status = $1;&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30744</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30744"/>
		<updated>2019-06-12T19:29:38Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+&amp;lt;br&amp;gt;Foto: RITTER Elektronik GmbH]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell von Ritter Elektronik hergestellt wird, beschrieben. Die PIUSV+ wird über Reichelt Elektronik vertrieben.   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss ein geeignetes I2C Interface Modul (z.B. RPII2C, FRM oder NetzerI2C) zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Nachfolgend wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
	$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
	$content=~ m/received : (\d+) |/is;&lt;br /&gt;
	$status = $1;&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Kategorie:USV&amp;diff=30743</id>
		<title>Kategorie:USV</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Kategorie:USV&amp;diff=30743"/>
		<updated>2019-06-12T06:10:08Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Unterbrechungsfreie Stromversorgung (USV) ist für manche Zwecke der Hausautomatisierung eine extrem nützliche Angelegenheit.&lt;br /&gt;
*USV-Systeme mit genügend Leistung zur Versorgung von Desktop-Computern oder Servern liefern in der Regel 230 V Wechselspannung am Ausgang und sind über ein Interface abfragbar.&lt;br /&gt;
*Mini-USV-Systeme liefern Kleinspannung (5 - 48V) bei Leistungen von ca. 15 - 30 W, haben aber teilweise den Nachteil, kein Interface zu besitzen.&lt;br /&gt;
*USV-Zusätze für Einplatinencomputer wie den Raspberry Pi können meist direkt auf diese aufgesteckt werden, liefern aber nur wenige Watt Leistung.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Hardware Typen]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30742</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30742"/>
		<updated>2019-06-11T20:24:00Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Umsetzung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell über Reichelt vertrieben wird, beschrieben.   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss ein geeignetes I2C Interface Modul (z.B. RPII2C, FRM oder NetzerI2C) zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Nachfolgend wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
	$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
	$content=~ m/received : (\d+) |/is;&lt;br /&gt;
	$status = $1;&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30741</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30741"/>
		<updated>2019-06-11T20:22:24Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Umsetzung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell über Reichelt vertrieben wird, beschrieben.   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss ein geeignetes I2C Interface Modul (z.B. RPII2C, FRM oder NetzerI2C) zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Nachfolgend wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
	$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
	$content=~ m/received : (\d+) |/is;&lt;br /&gt;
	$status = $1;&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
        fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30740</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30740"/>
		<updated>2019-06-11T20:21:30Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Umsetzung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell über Reichelt vertrieben wird, beschrieben.   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss ein geeignetes I2C Interface Modul (z.B. RPII2C, FRM oder NetzerI2C) zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Nachfolgend wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
	$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
	$content=~ m/received : (\d+) |/is;&lt;br /&gt;
	$status = $1;&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
        fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Datagramm&lt;br /&gt;
define USV_Datagramm dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Statusregister&lt;br /&gt;
define USV_Statusregister dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30739</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30739"/>
		<updated>2019-06-11T20:18:51Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Umsetzung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell über Reichelt vertrieben wird, beschrieben.   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss ein geeignetes I2C Interface Modul (z.B. RPII2C, FRM oder NetzerI2C) zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Nachfolgend wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $datagramm;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $status;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$datagramm=$content&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        fhem(&amp;quot;set PIi2c_1 writeByte 18 00&amp;quot;);&lt;br /&gt;
	$content=fhem(&amp;quot;get PIi2c_1 read 18&amp;quot;,1);&lt;br /&gt;
	$content=~ m/received : (\d+) |/is;&lt;br /&gt;
	$status = $1;&lt;br /&gt;
&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $datagramm&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
        fhem(&amp;quot;set USV_Statusregister $status&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;br /&gt;
[[Kategorie:USV]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30720</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30720"/>
		<updated>2019-06-10T19:24:27Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Umsetzung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell über Reichelt vertrieben wird, beschrieben.   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Kommunikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss ein geeignetes I2C Interface Modul (z.B. RPII2C, FRM oder NetzerI2C) zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Nachfolgend wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $content&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30719</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30719"/>
		<updated>2019-06-10T19:23:33Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Umsetzung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell über Reichelt vertrieben wird, beschrieben.   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Je nach Anforderung können/müssen entsprechend Anpassungen durchgefüht werden.&lt;br /&gt;
&lt;br /&gt;
Da die Komunnikation über die I2C-Schnittstelle des Raspberry Pi&#039;s erfolgt, muss ein geeignetes I2C Interface Modul (z.B. RPII2C, FRM oder NetzerI2C) zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Nachfolgend wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $content&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30715</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30715"/>
		<updated>2019-06-10T19:15:26Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Ausblick */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell über Reichelt vertrieben wird, beschrieben.   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
I2C-Daten werden über ein I2C Interface Modul wie beispielsweise RPII2C, FRM oder NetzerI2C gesendet. Daher muss eines dieser Module zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Hier wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $content&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30713</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30713"/>
		<updated>2019-06-10T19:06:20Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Ausblick */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell über Reichelt vertrieben wird, beschrieben.   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
I2C-Daten werden über ein I2C Interface Modul wie beispielsweise RPII2C, FRM oder NetzerI2C gesendet. Daher muss eines dieser Module zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Hier wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $content&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Die hier vorgestellte Lösung ist als Beispiel zu verstehen. Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter und vollständiger zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30712</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30712"/>
		<updated>2019-06-10T19:03:56Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
[[Datei:Piusvplus.jpg|mini|400px|rechts|Unterbrechungsfreie Spannungsversorgung &amp;quot;PIUSV+]]&lt;br /&gt;
&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell über Reichelt vertrieben wird, beschrieben.   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
I2C-Daten werden über ein I2C Interface Modul wie beispielsweise RPII2C, FRM oder NetzerI2C gesendet. Daher muss eines dieser Module zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Hier wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $content&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Datei:Piusvplus.jpg&amp;diff=30711</id>
		<title>Datei:Piusvplus.jpg</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Datei:Piusvplus.jpg&amp;diff=30711"/>
		<updated>2019-06-10T18:58:31Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: Unterbrechungsfreie Spannungsversorgung PIUSV+&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Beschreibung ==&lt;br /&gt;
Unterbrechungsfreie Spannungsversorgung PIUSV+&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30710</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30710"/>
		<updated>2019-06-10T18:44:07Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell über Reichelt vertrieben wird, beschrieben.   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
I2C-Daten werden über ein I2C Interface Modul wie beispielsweise RPII2C, FRM oder NetzerI2C gesendet. Daher muss eines dieser Module zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Hier wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $content&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;);&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Meldung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Der Inhalt in USV_Meldung bleibt hier so lange stehen, bis dieser durch einen selbst zu realisierenden set-Befehl gelöscht wird.&lt;br /&gt;
Dadurch können auch kurze Spannungsunterbrechungen erfasst werden.&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30694</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30694"/>
		<updated>2019-06-05T19:46:39Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Umsetzung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell über Reichelt vertrieben wird, beschrieben.   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
I2C-Daten werden über ein I2C Interface Modul wie beispielsweise RPII2C, FRM oder NetzerI2C gesendet. Daher muss eines dieser Module zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Hier wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $content&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;)&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen (Abschaltung erfolgt hier nach 21 Sekunden)&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30693</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30693"/>
		<updated>2019-06-05T19:42:13Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Umsetzung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell über Reichelt vertrieben wird, beschrieben.   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
I2C-Daten werden über ein I2C Interface Modul wie beispielsweise RPII2C, FRM oder NetzerI2C gesendet. Daher muss eines dieser Module zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Hier wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In die Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $usv_meldung;&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv_meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv_meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $content&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;)&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30581</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30581"/>
		<updated>2019-05-31T07:31:43Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Idee */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell über Reichelt vertrieben wird, beschrieben.   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit &amp;lt;code&amp;gt;sudo apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
I2C-Daten werden über ein I2C Interface Modul wie beispielsweise RPII2C, FRM oder NetzerI2C gesendet. Daher muss eines dieser Module zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Hier wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $usv_meldung&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv-meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv-meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv-meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $content&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;)&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
attr USV_Netzteilspannung fp_Raspberry 25,460,2,USV Netzteilspannung:&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
attr USV_Akkuspannung fp_Raspberry 75,460,2,USV Akkuspannung:&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
attr USV_Spannung fp_Raspberry 125,460,2,USV PI-Spannung:&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
attr USV_Strom fp_Raspberry 175,460,2,USV PI-Strom:&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
attr USV_Leistung fp_Raspberry 225,460,2,USV PI-Leistung:&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
attr USV_Leistung fp_Raspberry 225,460,2,USV Meldung:&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
	<entry>
		<id>http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30564</id>
		<title>Unterbrechungsfreie Spannungsversorgung &quot;PIUSV+&quot; direkt ansteuern</title>
		<link rel="alternate" type="text/html" href="http://wiki.fhem.de/w/index.php?title=Unterbrechungsfreie_Spannungsversorgung_%22PIUSV%2B%22_direkt_ansteuern&amp;diff=30564"/>
		<updated>2019-05-30T07:01:17Z</updated>

		<summary type="html">&lt;p&gt;Xaneu: /* Registerbeschreibung (für eigene Erweiterungen) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Idee ==&lt;br /&gt;
&lt;br /&gt;
Hier wird der direkte FHEM-Zugriff auf die Unterbrechungsfreien Spannungsversorgung PIUSV+, die früher von CW2 und aktuell über Reichelt vertrieben wird, beschrieben.   &lt;br /&gt;
Der direkte Zugriff bedeutet, dass die Kommunikation vollständig über die I2C-Schnittstelle erfolgt, wie es die Originalsoftware &amp;quot;piupsmon&amp;quot; auch bewerkstelligt.&lt;br /&gt;
&lt;br /&gt;
Der direkte Zugriff hat folgenden Vorteile:&lt;br /&gt;
* Die Originalsoftware &amp;quot;piupsmon&amp;quot;, die für den Betrieb der USV vorgesehen ist, wird nicht bzw. nicht mehr benötig (ggf. sollte diese mit sudo &amp;lt;code&amp;gt;apt-get --purge piupsmon&amp;lt;/code&amp;gt; deinstalliert werden). Die Originalsoftware, die vom ursprünglichen Hersteller CW2 stammt und nicht mehr supportet wird, arbeitet nicht immer zuverlässig.&lt;br /&gt;
* Es muss kein zusätzliches Skript in die piupsmon-Software zum sauberen Runterfahren des FHEM-Servers eingebunden werden.&lt;br /&gt;
* Die direkte Ansteuerung bietet mehr Möglichkeiten (auch für eigene Erweiterungen). So wird beispielsweise nach einem Spannungsausfall wie hier beschrieben der Shutdown nicht nach einer festen Zeit ausgelöst, sondern beim Unterschreiten einer bestimmten Akkusspannung.&lt;br /&gt;
* Es können diverse Werte wie Versorgungspannung, Pi-Spannung, Pi-Strom, Pi-Leistung und Akku-Status ausgelesen bzw. angezeigt werden.&lt;br /&gt;
* Durch die eigene Kontrolle über die USV wird die Sicherheit erhöht, wodurch ein Crash des Betriebssystems auf dem Systemspeicher (SD-Karte oder externer USB-Speicher) noch effektiv verhindert werden kann.&lt;br /&gt;
&lt;br /&gt;
== Umsetzung ==&lt;br /&gt;
&lt;br /&gt;
I2C-Daten werden über ein I2C Interface Modul wie beispielsweise RPII2C, FRM oder NetzerI2C gesendet. Daher muss eines dieser Module zuvor definiert werden (siehe Commandref).&lt;br /&gt;
Hier wurde der Zugriff auf die I2C-Schnittstelle über das Modul RPII2C realisiert.&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;99_myUtils.pm&amp;quot; müssen die folgende Funktionen kopiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=pl&amp;gt;&lt;br /&gt;
sub USV_Werte_auslesen($$)&lt;br /&gt;
{&lt;br /&gt;
my ($USV_Netzteilspannung_Error_Counter, $USV_Akkuspannung_Error_Counter) = @_;&lt;br /&gt;
&lt;br /&gt;
my $content;&lt;br /&gt;
my $u_akku_high;&lt;br /&gt;
my $u_akku_low;&lt;br /&gt;
my $u_akku;&lt;br /&gt;
my $u_netz_high;&lt;br /&gt;
my $u_netz_low;&lt;br /&gt;
my $u_netz;&lt;br /&gt;
my $u_pi_high;&lt;br /&gt;
my $u_pi_low;&lt;br /&gt;
my $u_pi;&lt;br /&gt;
my $i_pi_high;&lt;br /&gt;
my $i_pi_low;&lt;br /&gt;
my $i_pi;&lt;br /&gt;
my $p_pi;&lt;br /&gt;
my $usv_meldung&lt;br /&gt;
&lt;br /&gt;
# Werte lesen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 02&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
$content=fhem(&amp;quot;get PIi2c_1 readblock 18 10&amp;quot;,1);&lt;br /&gt;
$content=~ m/received : (\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+).(\d+) |/is;&lt;br /&gt;
$u_akku_high=$1;&lt;br /&gt;
$u_akku_low=$2;&lt;br /&gt;
$u_netz_high=$7;&lt;br /&gt;
$u_netz_low=$8;&lt;br /&gt;
$u_pi_high=$5;&lt;br /&gt;
$u_pi_low=$6;&lt;br /&gt;
$i_pi_high=$3;&lt;br /&gt;
$i_pi_low=$4;&lt;br /&gt;
&lt;br /&gt;
$u_akku=((($u_akku_high &amp;amp; 0x7F)*256+$u_akku_low)/1000);&lt;br /&gt;
$u_netz=((($u_netz_high &amp;amp; 0x7F)*256+$u_netz_low)/1000);&lt;br /&gt;
$u_pi=((($u_pi_high &amp;amp; 0x3F)*256+$u_pi_low)/1000);&lt;br /&gt;
$i_pi=((($i_pi_high &amp;amp; 0x3F)*256+$i_pi_low)/1000);&lt;br /&gt;
$p_pi=floor($u_pi*$i_pi*1000+0.5)/1000;&lt;br /&gt;
&lt;br /&gt;
if ($u_akku&amp;lt;5 &amp;amp;&amp;amp; $u_akku&amp;gt;2.5 &amp;amp;&amp;amp; $u_netz&amp;lt;6 &amp;amp;&amp;amp; $u_pi&amp;lt;6 &amp;amp;&amp;amp; $i_pi&amp;lt;3 &amp;amp;&amp;amp; not($u_pi==0 &amp;amp;&amp;amp; $i_pi&amp;gt;0) &amp;amp;&amp;amp; not($i_pi==0 &amp;amp;&amp;amp; $u_pi&amp;gt;0))&lt;br /&gt;
	{&lt;br /&gt;
	if ($u_netz&amp;lt;0.1)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Netzteilspannung_Error_Counter==2) { $usv-meldung=&amp;quot;FHEM: USV-Netzspannung fehlt!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Netzteilspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Netzteilspannung_Error_Counter $USV_Netzteilspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if ($u_akku&amp;lt;3.0)&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter++;&lt;br /&gt;
		if ($USV_Akkuspannung_Error_Counter==2) { $usv-meldung=&amp;quot;FHEM: USV-Akkuspannung zu niedrig!&amp;quot;; }&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	else&lt;br /&gt;
		{&lt;br /&gt;
		$USV_Akkuspannung_Error_Counter=0;&lt;br /&gt;
		fhem(&amp;quot;set USV_Akkuspannung_Error_Counter $USV_Akkuspannung_Error_Counter&amp;quot;);&lt;br /&gt;
		}&lt;br /&gt;
	&lt;br /&gt;
	if (($u_netz&amp;lt;0.1) &amp;amp;&amp;amp; ($u_akku&amp;gt;3.0) &amp;amp;&amp;amp; ($u_akku&amp;lt;3.5)) # shutdown-Bedingung ermitteln&lt;br /&gt;
		{&lt;br /&gt;
		$usv-meldung=&amp;quot;Raspberry Pi und USV wurden wegen Stromausfall abgeschaltet!&amp;quot;;&lt;br /&gt;
		USV_abschalten();&lt;br /&gt;
		rasp_shutdown();&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	$u_akku=$u_akku.&amp;quot; V (3.0 ... 4.2 V)&amp;quot;;&lt;br /&gt;
	$u_netz=$u_netz.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$u_pi=$u_pi.&amp;quot; V (5V)&amp;quot;;&lt;br /&gt;
	$i_pi=$i_pi.&amp;quot; A&amp;quot;;&lt;br /&gt;
	$p_pi=$p_pi.&amp;quot; W&amp;quot;;&lt;br /&gt;
	fhem(&amp;quot;set USV_Datagramm $content&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Akkuspannung $u_akku&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Netzteilspannung $u_netz&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Spannung $u_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Strom $i_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Leistung $p_pi&amp;quot;);&lt;br /&gt;
	fhem(&amp;quot;set USV_Meldung $usv_meldung&amp;quot;)&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
sub USV_abschalten()&lt;br /&gt;
{&lt;br /&gt;
# USV-Abschaltung auslösen&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 10&amp;quot;);&lt;br /&gt;
fhem(&amp;quot;set PIi2c_1 writeByte 18 15&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
sub rasp_shutdown()&lt;br /&gt;
{&lt;br /&gt;
my @processes = `sudo shutdown -h now`;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Anmerkung:&lt;br /&gt;
Um den Raspberry wie hier direkt vom FHEM aus über den Befehl &amp;quot;sudo shutdown -h now&amp;quot; auszuschalten, muss in die Datei &amp;lt;code&amp;gt;/etc/sudoers.d/010_pi-nopasswd&amp;lt;/code&amp;gt; hinter dem Eintrag&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
folgendes ergänzt werden &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pi ALL=(ALL) NOPASSWD: ALL&lt;br /&gt;
fhem ALL=(ALL) NOPASSWD: /sbin/reboot, /sbin/shutdown, /sbin/halt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In der Datei &amp;quot;fhem.cfg&amp;quot; kann dann die Anzeige der USV-Parameter und die Abschaltung der USV beispielsweise folgendermaßen realisiert werden:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#i2C-Schnittstelle einrichten&lt;br /&gt;
define PIi2c_1 RPII2C 1&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Netzteilspannung&lt;br /&gt;
define USV_Netzteilspannung dummy&lt;br /&gt;
attr USV_Netzteilspannung fp_Raspberry 25,460,2,USV Netzteilspannung:&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter dummy&lt;br /&gt;
define USV_Netzteilspannung_Error_Counter_Init notify global:INITIALIZED set USV_Netzteilspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Akkuspannung&lt;br /&gt;
define USV_Akkuspannung dummy&lt;br /&gt;
attr USV_Akkuspannung fp_Raspberry 75,460,2,USV Akkuspannung:&lt;br /&gt;
define USV_Akkuspannung_Error_Counter dummy&lt;br /&gt;
define USV_Akkuspannung_Error_Counter_Init notify global:INITIALIZED set USV_Akkuspannung_Error_Counter 0&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Spannung&lt;br /&gt;
define USV_Spannung dummy&lt;br /&gt;
attr USV_Spannung fp_Raspberry 125,460,2,USV PI-Spannung:&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Strom&lt;br /&gt;
define USV_Strom dummy&lt;br /&gt;
attr USV_Strom fp_Raspberry 175,460,2,USV PI-Strom:&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Leistung dummy&lt;br /&gt;
attr USV_Leistung fp_Raspberry 225,460,2,USV PI-Leistung:&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Leistung&lt;br /&gt;
define USV_Meldung dummy&lt;br /&gt;
attr USV_Leistung fp_Raspberry 225,460,2,USV Meldung:&lt;br /&gt;
&lt;br /&gt;
# PI USV+ Werte aktualisieren und ggf. Abschaltung auslösen&lt;br /&gt;
define USV_Werte_auslesen at +*00:00:05 { USV_Werte_auslesen(Value(&amp;quot;USV_Netzteilspannung_Error_Counter&amp;quot;),Value(&amp;quot;USV_Akkuspannung_Error_Counter&amp;quot;)) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Registerbeschreibung (für eigene Erweiterungen) ==&lt;br /&gt;
&lt;br /&gt;
Die PIUSV+ kann per I2C-Schnittstelle über die Adresse &amp;quot;0x18&amp;quot; angesprochen werden.&amp;lt;br&amp;gt; &lt;br /&gt;
Achtung: lt. Foren wurde bei älteren PIUSV+ teilweise auch die Adresse &amp;quot;0x30&amp;quot; verwendet.&amp;lt;br&amp;gt; &lt;br /&gt;
Das nächste Byte, das hinter der Adresse an die PIUSV+ gesendet werden muss, ist als Befehl zu verstehen.&lt;br /&gt;
&lt;br /&gt;
Folgende Befehle sind möglich:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;Status lesen&amp;quot;              0x00   danach muss 1 Byte (Statusregister) gelesen werden&lt;br /&gt;
                                   Die einzelnen Bits des Statusregister haben folgende Bedeutung:&lt;br /&gt;
                                     Bit0:  Primäre Spannungsversorgung (5V) aktiv&lt;br /&gt;
                                     Bit1:  Sekundäre Spannungsversorgung (5V...25V) aktiv&lt;br /&gt;
                                     Bit2:  Akkuspannung zu niedrig&lt;br /&gt;
                                     Bit3:  Akku wird geladen&lt;br /&gt;
                                     Bit4:  Akku ist voll&lt;br /&gt;
                                     Bit5:  Taster S1 an der USV betätigt&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Firmare Version lesen&amp;quot;     0x01   danach müssen 12 Bytes (Zeichen) gelesen werden&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Werte lesen&amp;quot;               0x02   danach müssen 10 Byte gelesen werden&lt;br /&gt;
                                   Die zu lesenden Bytes haben folgende Reihenfolge und Bedeutung:&lt;br /&gt;
	                             HIGH_BYTE (UINT) Akku-Spannung in mV	&lt;br /&gt;
	                             LOW_BYTE  (UINT) Akku-Spannung in mV&lt;br /&gt;
                                     HIGH_BYTE (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     LOW_BYTE  (UINT) Strom in mA, der zum Raspberry Pi fließt&lt;br /&gt;
                                     HIGH_BYTE (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     LOW_BYTE  (UINT) 5V-Versorgungsspannung in mV (USV-Spannungversorung für Raspberry Pi)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV am Micro USB-Stecker der USV (primäre Spannungsversorgung)&lt;br /&gt;
                                     HIGH_BYTE (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
                                     LOW_BYTE  (UINT) Spannung in mV externe Spannungsversorgung (sekundäre Spannungsversorgung)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;USV-Abschaltung auslösen&amp;quot;  0x10   danach muss 1 Byte geschrieben werden&lt;br /&gt;
                                   Folgende Werte sind möglich:&lt;br /&gt;
                                     0x00 (default Wert): USV wird nach einer Zeit von 30sec. abgeschaltet&lt;br /&gt;
                                     0x01...0xFF:	  USV wird nach einer Zeit von 1...255 Sekunden abgeschaltet&lt;br /&gt;
                                   Anmerkung: Durch das zeitverzögerte Auschalten der USV kann sichergestellt werden,&lt;br /&gt;
                                              dass ein zuvor ausgelöster Shutdown des Raspberry Pi abgeschlossen ist.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ausblick ==&lt;br /&gt;
Es wäre sinnvoll, das hier Beschriebene in einem eigenen Modul z.B. &amp;quot;52_I2C_PIUPS_PLUS.pm&amp;quot; unterzubringen, um den Zugriff noch eleganter zu realisieren.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
[[Kategorie:Examples]]&lt;br /&gt;
[[Kategorie:Code Snippets]]&lt;/div&gt;</summary>
		<author><name>Xaneu</name></author>
	</entry>
</feed>