http://wiki.fhem.de/w/api.php?action=feedcontributions&user=Amenomade&feedformat=atomFHEMWiki - Benutzerbeiträge [de]2024-03-29T13:01:42ZBenutzerbeiträgeMediaWiki 1.39.3http://wiki.fhem.de/w/index.php?title=Notify&diff=34280Notify2020-11-25T21:37:03Z<p>Amenomade: Code "Eine PV-Anlage (Solarstrom)" korrigiert. Forum #116168</p>
<hr />
<div>{{SEITENTITEL:notify}}<br />
{{Infobox Modul<br />
|ModPurpose=Ausführung von Anweisung(en) als Reaktion auf Ereignisse<br />
|ModType=h<br />
|ModCmdRef=notify<br />
|ModForumArea=Automatisierung<br />
|ModTechName=91_notify.pm<br />
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]])<br />
}}<br />
== Einführung ==<br />
{{Hinweis|Weitere grundlegende Informationen/Beispiele zu notify enthält [http://fhem.de/Heimautomatisierung-mit-fhem.pdf Heimautomatisierung mit FHEM]}}<br />
Das Hilfsmodul notify dient dazu [[Ereignis|Ereignisse]] über ein Suchmuster zu erkennen und bei einem Treffer eine Aktion auszulösen. Mit ''notify'' und anderen [[Eventhandler|Eventhandlern]] <ref>hierzu gehören u.a. auch [[DOIF]], [[THRESHOLD]] und [[watchdog]]</ref> ist es möglich, Logikfunktionen im FHEM abzubilden.<br />
<br />
'''Beispiele:''' <br />
* Wird das Licht in der Küche eingeschaltet, soll FHEM dort auch das Radio einschalten. <br />
* Bei Druck auf einen Taster soll die Umwälzpumpe für das Warmwasser eingeschaltet werden. <br />
* Erweiterte Möglichkeiten: Aber nur, wenn das Radio aus ist bzw. die Temperatur im Rücklauf des Warmwassers unterhalb einer bestimmten Schwelle liegt<ref>vgl. hierzu z.B. {{Link2CmdRef|Anker=devspec|Label=FILTER}} und [[if-condition]]</ref>.<br />
<br />
== Syntax ==<br />
<br />
define <name> notify <Suchmuster> <command> <br />
<br />
Das ''[[Regulärer Ausdruck|Suchmuster]]'' (häufig als Regexp = regular expression = regulärer Ausdruck bezeichnet) ist sehr wichtig: Es ist entweder der Name des auslösenden ("triggernden") Gerätes oder die Kombination aus Gerät und auslösendem Ereignis (Event) <code>Gerätename:Event</code>. Die Events kann man dem [[Event_monitor|Event-Monitor]] entnehmen. Wenn dort z.B. <code>Rollo1</code> steht, dann reagiert ''notify'' auf <code>Rollo1 on</code> und <code>Rollo1 off</code> usw.<br />
<br />
Wenn man mehrere Suchmuster kombinieren möchte, kann man diese in Klammer schreiben, als Trenner wird dann Pipe (|) genutzt: <code>(Rollo1|Rollo2|Steckdose5)</code>.<br />
<br />
'''Auch die Verwendung von Platzhaltern ist möglich''':<br />
* <code>Rollo.</code> → das notify reagiert auf alles was mit Rollo und '''einem''' weiteren beliebigen Zeichen anfängt. Also auf Rollo1 wie auch auf RolloG, aber nicht auf Rollo_wischundweg<br />
* <code>Rollo.*</code> → notify reagiert auf alles das mit Rollo beginnt<br />
* <code>.*isch</code> → auf alles das mit isch aufhört (Tisch, Fisch)<br />
* <code>Schalter(1|2|3)</code> → hört auf Schalter1, Schalter2 und Schalter3<br />
* <code>dimmer:pct:.(100|7[6-9]|[89][0-9])</code> → reagiert, wenn pct einen Wert über 75 annimmt.<br />
<br />
Suchmuster/Regex kann man im Internet beispielsweise auf [http://regexpal.com/| http://regexpal.com/] testen.<br />
<br />
Es gibt seit Juli 2020 eine Perlfunktion notifyRegexpCheck zum Testen wie FHEM über das Suchmuster "denkt" - Beitrag im [https://forum.fhem.de/index.php/topic,111938.msg1074202.html#msg1074202 Forum]<br />
<br />
{{Hinweis|Das '''Suchmuster''' wird notify-intern um das Zeichen ^ (beginnt mit) und das Zeichen $ (endet mit) ergänzt<ref>Der Eventhandler [[DOIF]] verwendet die in Perl übliche Syntax für reguläre Ausdrücke als DOIF-Suchmuster.</ref>.<br />
<br />
Deshalb darf das Suchmuster nicht mit einem üblichen [[Regulärer Ausdruck|'''Regulären Ausdruck''']], wie er in Perl<ref>https://perldoc.perl.org/perlre.html</ref> verwendet wird, gleichgesetzt werden, da die Ergänzung zu einem grundsätzlich unterschiedlichen Verhalten führt, siehe nachstehendes Beispiel.}}<br />
<br />
'''Beispiel für das unterschiedliche Verhalten von ''Suchmuster'' und ''regulären Ausdruck'''''<br />
<br />
Für einen '''regulären Audruck''' gilt: Wenn der reguläre Ausdruck ''lampe'' ist und das [[Ereignis]] ''tischlampe'' dann passen ''tischlampe'' und ''lampe'' zueinander.<br />
<br />
Für das '''Suchmuster''' gilt: Wenn das Suchmuster ''lampe'' ist und das [[Ereignis]] ''tischlampe'' dann passen ''tischlampe'' und ''lampe'' '''nicht''' zueinander, weil das Suchmuster zu ^lampe$ ergänzt wird und damit exakt nur auf ''lampe'' matcht (passt).<br />
<br />
'''Beispiel Variablen Zuordnung zum Event'''<br />
2020-01-21 22:40:39 HUEDevice VibrationTest1 battery: 88<br />
{| class="wikitable"<br />
|-<br />
! !!$NAME !!$EVENT!!<br />
|-<br />
| ||||$EVTPART0 ||$EVTPART1<br />
|-<br />
|2020-01-21 22:40:39 HUEDevice|| VibrationTest1|| battery:|| 88<br />
|}<br />
<br />
== FHEMWEB-unterstütztes Anlegen eines notify ==<br />
{{Hinweis|Die Erstellung eines notify und insbesondere die korrekte Angabe des Suchmusters (Regex) führt gerade bei Einsteigern immer wieder zu Schwierigkeiten. Zur Fehlerminimierung empfiehlt es sich zum einen, die [[Konfiguration]] nicht direkt zu bearbeiten, sondern die "Befehl-Eingabezeile", die "Objektdetails" oder den [[Import von Code Snippets|Import von RAW-Definitionen]] zur Bearbeitung zu nutzen.}}<br />
<br />
=== Event Monitor ===<br />
Die komfortabelste Möglichkeit, die häufigsten Event-Handler zu erstellen, bietet der [[Event monitor|Event-Monitor]]. Die Vorgehensweis ist in dem zugehörigen Artikel dargestellt.<br />
<br />
=== Regexp wizard ===<br />
Zudem enthält FHEM einen Regexp wizard mit dem Regex anhand der in FHEM vorhandenen Devices und deren Events aus einer Auswahlbox selektiert werden können. Voraussetzungen sind:<br />
* Aktivierung des Hilfsmoduls [[eventTypes]] (bei allen Neuinstallationen Standard) <br />
* das gesuchte Ereignis (Event) ist nach Aktivierung des Hilfsmoduls bereits mindestens einmal eingetreten<br />
<br />
Schrittweise Darstellung der Nutzung des Regexp wizard zur Anlage eines "notify":<br />
<br />
In das [[Konfiguration#Befehl-Eingabefeld|Befehls-Eingabefeld]] eingeben und mit {{Taste|Enter}} bestätigen:<br />
define ntest notify a b<br />
Als Beispiel wird ein notify mit <name> "ntest" angelegt. "a" und "b" sind beliebige Platzhalter für <Suchmuster> und <Command>, die bei der weiteren Bearbeitung mit dem endgültigen Werten ersetzt werden.<br />
Der Regexp wizard öffnet sich:<br />
[[Datei:Regexp wizard1.JPG|400px|thumb|center]]<br />
Nun in der Auswahlbox das auslösende Event (Ereignis) auswählen; zunächst das Device und dann das gewünschte Regex. Hier soll das notify bei jeder Veränderung der Temperatur (temperature.*) des Device BTHR918N reagieren. Abschließend mit einem Mausklick auf {{Taste|set}} bestätigen. Wählt man mehrere Regex in dieser Weise aus, so wird das "notify" bei Eintritt jedes dieser Events ausgeführt:<br />
[[Datei:Regexp wizard2.JPG|400px|thumb|center]]<br />
Anschließend den Platzhalter "a" mit Klick auf den Link "removeRegexpPart" löschen:<br />
[[Datei:Regexp wizard3.JPG|400px|thumb|center]]<br />
Den Link "DEF" anklicken, damit sich der DEF-Editor öffnet:<br />
[[Datei:Regexp wizard4.JPG|400px|thumb|center]]<br />
Jetzt den auszuführenden Befehl im "DEF"-Bereich durch Überschreiben des Platzhalters "b" eintragen und mit Klick auf {{Taste|modify ntest}} abschließen:<br />
[[Datei:Regexp wizard5.JPG|400px|thumb|center]]<br />
Das fertige und sofort aktive "notify" sieht abschließend folgendermaßen aus:<br />
[[Datei:Regexp wizard6.JPG|400px|thumb|center]]<br />
Am Schluss das Speichern über {{Taste|Save config}} nicht vergessen.<br />
<br />
== Mein notify geht nicht - wie kann ich mir selbst helfen: Debugging ==<br />
Funktioniert ein notify nicht wie gewünscht, kann es nur zwei Hauptursachen haben: <br />
* Entweder das Suchmuster paßt nicht zum gewünschten Auslöser (FHEM Device), und/oder<br />
* die Anweisung enthält einen Fehler. <br />
Sollte kein Fehler im Logfile auftauchen aber das notify ausgelöst werden, stimmt meist der Übertragungsweg zum Zieldevice nicht.<br />
Der STATE des notify zeigt normalerweise mit Datum/Uhrzeit die letzte Auslösung an.<br />
<br />
Beim Debuggen sollte man daher beide Elemente getrennt untersuchen. Hier ein Beispiel welches nicht wie gewünscht funktioniert:<br />
<source lang="perl"> define n_test notify n_test:muster Ausführungsteil</source><br />
Zum debuggen benötigen wir <br />
* den [[Event monitor]]<br />
* das [https://fhem.de/commandref.html#trigger trigger-Kommando] - kann man jederzeit verwenden um das Suchmuster als Event unabhängig vom Auslöser zu erzeugen.<br />
* die FHEM Kommandozeile<br />
* den [[DEF-Editor]]<br />
* eventuell einen Texteditor um Codeblöcke zwischen zu lagern und Notizen zu machen.<br />
<br />
Das Suchmuster im Beispiel notify triggert auf sich selbst, es soll auf jeden Event mit dem Inhalt '''muster''' ausgelöst werden, Beispiel:<br />
2018-07-14 14:31:03 notify n_test muster bild<br />
<br />
=== Suchmuster ===<br />
Sollte das notify nicht funktionieren:<br />
* keine Reaktion wie gewünscht<br />
* keine Fehlermeldung in der Weboberfläche beim Anlegen, keine Fehlermeldung im Logfile<br />
* STATE ist unverändert auf active oder einem altem Datum/Uhrzeit<br />
liegt der Fehler mit Sicherheit im Suchmuster. Man hat die Chance das Suchmuster mit dem trigger Befehl zu erzeugen und zu schauen ob die Anweisung ausgeführt wird. Dabei ist zu beachten: Der erste ":" im Suchmuster ist zusätzlich zwischen Gerät und Event als Trennung. Jeder weiter : ist, wenn vorhanden, Bestandteil des Events! Siehe dazu den Abschnitt [https://fhem.de/commandref_DE.html#notify Hinweise in der commandref]<br />
*Im Beispiel: Event: n_test muster -> Suchmuster n_test:muster<br />
Um aus dem [[Event]] ein passendes Suchmuster zu erzeugen kann der [[Event monitor|Event-Monitor]] direkt verwendet werden. Man kann ein neues notify erzeugen oder ein Bestehendes modifizieren lassen.<br />
<br />
Unser Regex im Beispiel ist zu spezifisch, es triggert nur exakt auf '''muster'''. Dieser Trigger erzeugt den folgenden Eintrag im Eventmonitor, entspricht exakt dem Suchmuster und löst das notify aus:<br />
trigger n_test muster<br />
2018-07-13 11:52:08 notify n_test muster<br />
Das Suchmuster für unsere Anforderung muss in <code>n_test:muster.*</code> geändert werden, damit jeder Event der mit muster beginnt das notify auslöst.<br />
Der . im Regex steht für jedes beliebige Zeichen und der * für eine beliebige Anzahl des Zeichens davor: also beliebig viele beliebige Zeichen nach muster.<br />
<br />
Das Suchmuster wird häufig in ein komplizierteres Regex umgewandelt um im notify mehrere Aktionen zu starten. Das eigene Regex kann z.B. mit http://regexpal.com/ oder https://regex101.com/ getestet werden.<br />
<br />
Funktioniert der Auslöser, das notify tut aber noch nicht was es soll, müssen wir die Anweisung untersuchen. In unserem korrigierten Beispiel<br />
<source lang="perl"> defmod n_test notify n_test:muster.* Ausführungsteil</source><br />
folgt beim Kommando <code>trigger n_test muster bild</code> ein Eintrag im Log:<br />
2018.07.13 11:47:57 3: n_test return value: Unknown command Ausführungsteil, try help.<br />
Das notify wurde zwar getriggert aber die Anweisung war nicht ausführbar. <br />
<br />
Ein richtiges Suchmuster und eine fehlerhafte Anweisung wird also normalerweise einen Fehlereintrag im Logfile erzeugen!<br />
<br />
=== Spezialfall: notify löst zwar aus - aber zu oft ===<br />
In dem Fall ist das Suchmuster (regExp) zu unscharf oder das triggernde Gerät löst das Event zu oft aus. Das regExp sollte so genau wie möglich konstruiert werden, device:.* ist eine einfache aber oft keine gute Wahl!<br />
<br />
Im Device, welches den Event auslöst, kann mit den Attributen event-on-.* die Häufigkeit gesteuert werden. Insbesondere ist hier das regExp .* eine Art Standardwahl um aufeinanderfolgende gleichartige Events zu verhindern.<br />
<br />
'''Achtung''': durch falsche Angaben kann man Events ganz leicht völlig verhindern! <syntaxhighlight><br />
attr device event-on-change-reading .*<br />
</syntaxhighlight><br />
<br />
=== Anweisung ===<br />
Wird das notify getriggert oder will man ganz schnell mal ein notify testen, kann man die Anweisung durch folgenden Code ersetzen, man öffnet also einfach nur die DEF, kopiert den ursprünglichen Inhalt an einen sicheren Ort und ersetzt die Anweisung durch eine der beiden Zeilen. Die erste Zeile kann man auch einfach mal in der Kommandozeile testen:<br />
<source lang="perl">{Log 1, "Das Notify n_test hat ausgeloest."}<br />
{Log 1, "Das Device $NAME hat ausgeloest, der Event sah so aus: $EVENT"}</source><br />
Wird das notify ausgelöst, muss anschließend im Logfile ein Eintrag zu finden sein:<br />
2018.07.13 10:28:57 1: Das Notify n_test hat ausgeloest, der Event sah so aus: muster<br />
Unsere Anweisung <code>Ausführungsteil</code> liefert in der Kommandozeile selbst einen Fehler:<br />
<code>Unknown command Ausführungsteil, try help.</code><br />
Ein Versuch mit geschweiften Klammern <code>{Ausführungsteil}</code> liefert wieder einen Fehler:<br />
<code>Unrecognized character \xC3; marked by <-- HERE after {Ausf<-- HERE near column 6 at (eval 5977) line 1.</code><br />
Diese Variante <code>{"Ausführungsteil"}</code> liefert den String Ausführungsteil ohne Fehler: Das notify arbeitet fehler- aber sinnfrei.<br />
Der fertige Code:<br />
defmod n_test notify n_test:muster.* {"Ausführungsteil"}<br />
<br />
Man kann die Anweisung, normalerweise so wie sie ist, in der FHEM Kommandozeile testen. Sind im Perl Code (in geschweiften Klammern) im DEF Editor Semikolon enthalten muss man diese für den Test in der Kommandozeile (oder Raw Def) verdoppeln.<br />
Laufzeitabhängige Variablen sind in der Kommandozeile meist nicht verfügbar, diese sollte man für den Test einfach durch passende Inhalte austauschen. So kann man die komfortable Variante (loggt den Namen und das komplette Event) nicht in der Kommandozeile ausführen. <br />
<br />
Funktioniert ein FHEM Befehl in der Kommandozeile nicht (z.B. Lampe geht nicht an) kann es im notify auch nicht funktionieren, dann muss die Fehlersuche an anderer Stelle fortgeführt werden. <br />
<br />
Komplexeren Code im Ausführungsteil sollte man beim Testen in Teilabschnitte aufteilen, von der Laufzeit abhängige Variable ($NAME, $EVENT, $EVTPART) durch Strings ("TestWort") ersetzen, die Teilabschnitte separat testen und anschließend schrittweise wieder komplettieren.<br />
<br />
== Beispiele ==<br />
{{Hinweis|Für die nachfolgenden Beispiele wurden einige unterschiedliche Technologien verwendet. Sie können aber recht einfach auf alle anderen Systeme übertragen werden, dabei sollte ggf. darauf geachtet werden, dass sich Schaltbefehle und Events teilweise je nach konkret eingesetzter Technologie unterscheiden können. Dann ist ggf. eine Erweiterung, z.B. durch eine [[if-condition|if-Abfrage]] erforderlich.}}<br />
<br />
=== Schalter entprellen ===<br />
Will man ein notify innerhalb eines bestimmten Zeitraumes nur einmal auslösen lassen, auch wenn er in diesem Zeitraum mehrfach getriggered werden sollte, so bietet sich das Attribut disabledAfterTrigger an,<br />
attr <notify_device> disabledAfterTrigger <Anzahl Sekunden><br />
In dem Zeitraum wird dann nur einmal (beim ersten Mal) der Befehl ausgelöst, auch wenn mehrfach getriggered wurde. Der Zeitraum kann Bruchteile von Sekunden umfassen.<br />
<br />
=== Etwas schalten, wenn ein anderes Gerät geschaltet wird ===<br />
<br />
==== Vorbedingungen ====<br />
Dieses Beispiel verwendet eine einfache InterTechno-kompatible Funksteckdose für das Radio und einen HM-Aktor für das Licht:<br />
<br />
define RadioKueche IT 000000FFFF 0F F0<br />
define LichtKueche CUL_HM 3A37D6<br />
Beachte: beide kennen als Event bzw. Schaltbefehle ''on'' und ''off''.<br />
<br />
==== notify Befehl ====<br />
define LichtamRadioan notify LichtKueche set RadioKueche $EVENT <br />
oder alternativ: <br />
define LichtamRadioan notify LichtKueche { fhem "set RadioKueche $EVENT" }<br />
<br />
<br />
==== Erklärung ====<br />
* Der Name des ''notify'' "LichtamRadioan" kann frei gewählt werden, er dient nur dazu, das notify in FHEM eindeutig zu identifizieren.<br />
* "$EVENT" ist ein Platzhalter für den Zustand vom Pattern. $EVENT enthält ein "off" wenn das LichtKueche aus- und ein "on" wenn das Licht eingeschaltet wird.<br />
* "{ &lt;perlcode&gt; }" alles was zwischen {} steht ist Perl code. Perl kennt das Schlüsselwort fhem. Das Schlüsselwort FHEM dient dazu, FHEM Befehle auszuführen. Es wird also der FHEM Befehl "set RadioKueche on/off" ausgeführt. on oder off ist abhängig vom Pattern. Der eigentliche FHEM Befehl muss in " " stehen.<br />
* Wann ist ein Wechsel auf die Perl-Ebene erforderlich? <br />
** einfache FHEM-Befehle sollten in der Regel direkt verwendet werden, dies ist ressourcenschonender.<br />
** Immer dann, wenn dies nicht möglich ist, weil z.B. komplexerer Code ausgeführt werden soll, (blockierende) Prozesse ausgelagert werden sollten oder Systembefehle ausgeführt werden, ist es günstiger, auf die Perl-Ebene zu wechseln <ref>In diesem {{Link2Forum|Topic=88398|Message=808685|LinkText=Forenbeitrag}} wird z.B. erläutert, wie man nichtblockierend externe Scripte aufrufen kann, die dann ihre Ergebnisse wieder an FHEM übergeben.</ref>. <br />
<br />
=== Einschalten von mehreren Geräten/Lampen, wenn das Licht eingeschaltet wird ===<br />
Dieses Beispiel verwendet einen HM-Aktor für das Licht sowie zwei Milight-Birnen, die einzeln geschaltet werden sollen<ref>Dies ist ausdrücklich keine Empfehlung für diese Technologie und der Module</ref> in den Stehlampen:<br />
<br />
==== Vorbedingungen ====<br />
FHEM:<br />
define LichtWZ CUL_HM 3A37D8<br />
define Stehlampe1 MilightDevice RGBW Milight_Wohnzimmer 5<br />
define Stehlampe2 MilightDevice RGBW Milight_Wohnzimmer 6<br />
<br />
==== notify Befehl ====<br />
define SteckdoseWZein notify LichtWZ set Stehlampe1,Stehlampe2 $EVENT<br />
oder ''in Perl''<br />
define SteckdoseWZein notify LichtWZ { fhem "set Stehlampe1 $EVENT;;set Stehlampe2 $EVENT " } <br />
==== Erklärung ====<br />
Wenn das LichtWZ eingeschaltet wird, dann werden auch die Stehlampen (1 und 2) eingeschaltet.<br />
<br />
=== Einfache ODER Funktion ===<br />
Eine einfache ODER Funktion kann sehr einfach realisiert werden<br />
<br />
==== Vorbereitung ====<br />
KNX:<br />
* 3x GAs der abzufragende Werte (0/0/40 0/0/41 0/0/42)<br />
<br />
FHEM:<br />
define Licht1 CUL_HM 3A37D8<br />
define Licht2 CUL_HM 1B7EC3<br />
define Stehlampe MilightDevice RGBW Milight_Wohnzimmer 7<br />
<br />
==== notify Befehl ====<br />
define SteckdoseWZein notify (Licht1|Licht2) set Stehlampe $EVENT <br />
oder<br />
define SteckdoseWZein notify (Licht.) set Stehlampe $EVENT<br />
<br />
==== Erklärung ====<br />
Die Werte in der Klammer (wichtig ist das »|«) sind die Rückgabewerte. Alternativ kann in diesem Beispiel auch »Licht.« (zu beachten ist der Punkt) geschrieben werden. Der Punkt ist ein Platzhalter für (genau) ein beliebiges Zeichen.<br />
<br />
Danach folgt der set Befehl.<br />
Wenn also das Licht1 oder Licht2 den Wert "on" hat, dann hat auch die Steckdose den Wert "on"<br />
<br />
Alternative: [[structure]]<br />
<br />
=== Einfache UND Funktion ===<br />
Ob man dieses Konstrukt noch als einfach bezeichnen kann, wage ich mal zu bezweifeln. In FHEM fehlen Loggingfunktionen, die man alle selber mit Perl Code erstellen kann (Danke an MAZ).<br />
Dadurch ist FHEM zwar mächtig, wird aber für viele sehr kompliziert.<br />
<br />
In diesem Beispiel soll - wenn drei Rollos geschlossen sind - am Taster eine LED eingeschaltet werden.<br />
<br />
==== Vorbereitung ====<br />
KNX:<br />
* 3x GDs für die Rückgabewert Rollo geschlossen == 1 (0/0/50 0/0/51 0/0/52)<br />
* GD LED am Lichtschalter (0/0/106)<br />
<br />
FHEM:<br />
define R1ZU KNX 0/0/50:dpt1.009<br />
attr R1ZU dummy 1<br />
define R2ZU KNX 0/0/51:dpt1.009<br />
attr R2ZU dummy 1<br />
define R3ZU KNX 0/0/52:dpt1.009<br />
attr R3ZU dummy 1<br />
define LEDalleRolloZu KNX 0/0/106:dpt1<br />
Durch das Attribut dummy werden keine Schaltfunktion angeboten. Es kann nur Werte anzeigen.<br />
<br />
==== notify Befehl ====<br />
define nt.allerolloszu notify (R1ZU|R2ZU|R3ZU) {<br />
my $r1 = Value("R1ZU");;<br />
my $r2 = Value("R2ZU");;<br />
my $r3 = Value("R3ZU");;<br />
if ($r1 eq "on" &amp;&amp; $r2 eq "on" &amp;&amp; $r3 eq "on") {<br />
fhem("set LEDalleRolloZu on");;<br />
} else {<br />
fhem("set LEDalleRolloZu off");;<br />
}<br />
}<br />
<br />
==== Erklärung ====<br />
Es werden die drei Rückgabewerte R1ZU, R2ZU und R3ZU ausgewertet. Danach folgt Perl Code, deswegen beginnt das ganze mit einer { und endet mit }<br />
<br />
my $r1 =&gt; Variable $r1 definieren<br />
= Value("R1ZU");; ==&gt; weist den Rückgabewert (on oder off) von R1ZU der Variable $r1 zu <br />
<br />
Der doppelte ;; ist ein FHEM Thema. Eigentlich würde für Perl ein ; reichen. Aber FHEM nutzt selbst das ; und daher wird ein ;; benötigt. Mit den ersten drei my Zeilen werden die Rückgabewerte den Variablen zugewiesen.<br />
<br />
Danach erfolgt ein normales "if then else" Konstrukt. Die Zeile »($r1 eq "on" &amp;&amp; $r2 eq "on" &amp;&amp; $r3 eq "on")«&#160;kann man so lesen: Wenn $r1 den Wert "on" und (&amp;&amp;) $r2 den Wert "on" und $r3 den Wert "on" dann schalte die LEDalleRolloZu ein {fhem("set LEDalleRolloZu on")}<br />
ansonsten else schalte die LED aus. {fhem("set LEDalleRolloZu off")<br />
<br />
Alternative: [[structure]]<br />
<br />
=== Zeitverzögert schalten ===<br />
{| class="wikitable"<br />
| '''Aufgabe:''' || Zeitverzögert schalten<br />
|- <br />
| '''Beschreibung:''' || Mit einem Notify zeitverzögert eine Aktion auslösen.<br />
|- <br />
| '''Vorbereitung:''' || Gerät "Lampe" ist definiert und es gibt eine Situation, die ein Ereignis "Fernbedienung:.*" generiert.<br />
|-<br />
| '''Befehl:''' || <code>define ntfy1 notify Fernbedienung:.* sleep 7.5;; set Lampe $EVENT</code><br />
|-<br />
| '''Erläuterungen:''' || Bei Eintreten eines Ereignisses "Fernbedienung*" wird nach einer Pause von siebeneinhalb Sekunden der Befehl <set Lampe ??> ausgeführt, wobei der eigentliche Befehl aus dem auslösenden Ereignis übernommen wird.<br />
:''Quelle: {{Link2Forum|Topic=17161|LinkText=FHEM Forum}}''<br />
|}<br />
<br />
=== Eine PV-Anlage (Solarstrom) zur Steuerung der Rollos nutzen (optional Zeit und Datums abhängig) ===<br />
Hier ein kleines Beispiel, wie man mit Hilfe einer PV-Anlage die Sonneneinstrahlung auf der Südseite ermittelt und dies zur Rolladensteuerung nutzt.<br />
Optional: Die Funktion soll allerdings nur zwischen 9:30 und 17:00 stattfinden. (zweites Beispiel)<br />
Optional: Die Funktion soll nur zwischen dem 6. und 9. Monat funktioneren. (drittes Beispiel)<br />
<br />
==== Vorbereitung ====<br />
PV Anlage mit SolarView abfragen.<br />
Per Hand ermitteln, ab wieviel erzeugtem Strom es sinnvoll ist die Rollos zu schließen.<br />
<br />
==== notify Syntax ====<br />
FHEM:<br />
<br />
define sv SolarView solarview 15000 wr1 wr2 wr3 wr4 <----vier Wechselrichter<br />
attr sv event-on-change-reading currentPower <br />
<br />
define nt.sonnenlichtpersolar notify (sv:currentPower.*) { <br />
if ($EVTPART1 &lt; 3000 ) {<br />
fhem('set Flur1 Auf');<br />
}else {<br />
if ($EVTPART1 &gt; 5000 ) {<br />
fhem('set Flur1 Ab');<br />
} <br />
}<br />
}<br />
<br />
Optional 1: Zeitabhängig<br />
<syntaxhighlight lang="Perl"><br />
(sv:currentPower.*) { <br />
my $hm = sprintf("%02d:%02d", $hour, $min);<br />
if ( $hm gt "09:30" && $hm lt "17:00") { <br />
if ($EVTPART1 < 5000 ) {<br />
fhem('set Flur1 Auf');<br />
}else {<br />
if ($EVTPART1 > 8000 ) {<br />
fhem('set Flur1 Ab');<br />
} <br />
}<br />
}<br />
}<br />
</syntaxhighlight><br />
Optional 2: Zeit und Datum<br />
<syntaxhighlight lang="Perl"><br />
(sv:currentPower.*) { <br />
my $hm = sprintf("%02d:%02d", $hour, $min);<br />
if ($month >= 6 && $month <= 9) {<br />
if ( $hm gt "09:30" && $hm lt "17:00") { <br />
if ($EVTPART1 < 5000 ) {<br />
fhem('set Flur1,RBUERO1,RBUERO2 Auf');<br />
}else {<br />
if ($EVTPART1 > 8000 ) {<br />
fhem('set Flur1,Flur2,RBUERO1,RBUERO2 Ab');<br />
} <br />
}<br />
}<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
==== Erklärung ====<br />
* Das define wird in der Kommandozeile im Webbrowser eingegeben.<br />
* Anschließend wird im Webbrowser die DEF bearbeitet, das erspart uns Probleme mit Perl<br />
* define sv SolarView ... <==== ist die Schnittstelle vom SolarView<br />
* define nt.sonnenlichtpersolar notify (sv:currentPower.*) { <==== hier wird ein notify angelegt, der auf das "define sv" Wert "currentPower.*" (.* ist irgendwas) reagiert<br />
if ($EVTPART1 &lt; 3000 ) {<br />
fhem('set Flur1 Auf');<br />
}else {<br />
if ($EVTPART1 &gt; 5000 ) {<br />
fhem('set Flur1 Ab');<br />
} <br />
}<br />
}<br />
Diese if-Funktion wertet den Rückgabewert von currentPower aus. Hierbei muss man wissen, dass $EVTPART1 das Split-Ergebnis vom Rückgabewert ist<br />
<br />
Beispiel: Der Rückgabewert (wie im Beispiel) ist "currentPower: 6000".<br />
Jetzt steht im "$EVTPART0 == currentPower:" und im "$EVTPART1 == 6000"<br />
Das bedeutet, dass man sich nicht selbst den richtigen split (Perl Befehl) Aufruf ausdenken muss, dies übernimmt vielmehr FHEM.<br />
<br />
Ergebnis: <br />
Das Rollo wird abhängig von der erzeugten IST_Strommenge auf und zu gefahren.<br />
Damit dies nicht dauernd hin und her pendelt, wurde der Auf Wert sehr klein und den Ab Wert sehr groß gewählt.<br />
<br />
'''Optional 1:''' Der Block "my $hm = sprintf("%02d:%02d", $hour, $min);" erzeugt die String-Variable $hm mit dem Inhalt $hour:$min. %02d begrenzt die Ausgabe auf zwei Stellen.<br />
Danach wird mit "if ( $hm gt "09:30" && $hm lt "17:00")" mit stringvergleichenden Operatoren geprüft, ob die Uhrzeit zwischen 9:30 und 17:00 liegt (lt = kleiner als; gt = größer als). Es wäre auch ein le und ge möglich: le = kleiner/gleich als, ge = größer/gleich als.<br />
<br />
'''Optional 2:'''if( $month >= 6 && $month <= 9) {<br />
<br />
Hier wird die numerische FHEM-Standard-Variable $month (Monat) auf größer/gleich bzw kleiner/gleich mit den binären Operatoren überprüft.<br />
Die Funktion arbeitet also nur zwischen dem 6. und dem 9. Monat und dann auch nur zwischen 9:31 und 16:59.<br />
<br />
=== Status eines Kippfensters mit 2 Fensterkontakten abbilden ===<br />
<br />
==== Vorbereitung ====<br />
Es ist je ein Fensterkontakt der ''open'' oder ''closed'' meldet, oben und unten am Fenster angebracht.<br />
Die Namen der beiden FHEM-Devices sind ''fensterKontaktOben'' und ''fensterKontaktUnten''.<br />
<br />
==== notify Syntax ====<br />
FHEM:<br />
define statusFenster notify fensterKontakt(Oben|Unten):(open|closed) {<br />
if ( ReadingsVal('fensterKontaktOben', 'state', 'undef') eq 'open' && ReadingsVal('fensterKontaktUnten', 'state', 'undef') eq 'open')<br />
{ fhem 'set Terrassentuer open' }<br />
if ( ReadingsVal('fensterKontaktOben', 'state', 'undef') eq 'closed' && ReadingsVal('fensterKontaktUnten', 'state', 'undef') eq 'closed')<br />
{ fhem 'set Terrassentuer closed' }<br />
if ( ReadingsVal('fensterKontaktOben', 'state', 'undef') eq 'open' && ReadingsVal('fensterKontaktUnten', 'state', 'undef') eq 'closed')<br />
{ fhem 'set Terrassentuer tilted' }<br />
if ( ReadingsVal('fensterKontaktOben', 'state', 'undef') eq 'closed' && ReadingsVal('fensterKontaktUnten', 'state', 'undef') eq 'open')<br />
{ fhem 'set Terrassentuer undef' }<br />
}<br />
<br />
== Weitere Hinweise ==<br />
* Entsprechend zu $EVENT gibt es auch noch $NAME und $TYPE. $NAME und $TYPE enthalten den Namen bzw. Typ des Ereignis auslösenden Gerätes.<br />
* Wird der Perl-Code in einem <code>notify</code> immer länger, lagere den Code wegen der Übersichtlichkeit in eine eigene Programmdatei aus, wie in [[99_myUtils anlegen]] beschrieben.<br />
* Achtung! Wenn man das Skript für den notify-Befehl über mehrere Zeilen schreibt, muss man anscheinend darauf achten, dass keine abschließende Leerzeile mitgespeichert wird. Sonst wird der notify-Befehl ignoriert.<br />
* Dieser {{Link2Forum|Topic=38520|Message=307325}} enthält Vorschläge zur Vorgehensweise bei der Erstellung von komplexen ''notify'' Definitionen bzw. bei deren Fehlerbehebung.<br />
<br />
== Weiterführende Links ==<br />
* [[Escapen in Perlbefehlen]]<br />
* [[Klammerebenen]]<br />
<br />
== Hinweise ==<br />
<references /><br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Hilfsmodul]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=Datei:HM-LC-Sw4-Ba-PCB.jpg&diff=34188Datei:HM-LC-Sw4-Ba-PCB.jpg2020-11-09T08:12:32Z<p>Amenomade: Amenomade lud eine neue Version von Datei:HM-LC-Sw4-Ba-PCB.jpg hoch</p>
<hr />
<div>== Beschreibung ==<br />
HM-LC-Sw4-Ba-PCB</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=HM-LC-Sw4-Ba-PCB_4-Kanal-Funk-Schaltaktor_f%C3%BCr_Batteriebetrieb&diff=34183HM-LC-Sw4-Ba-PCB 4-Kanal-Funk-Schaltaktor für Batteriebetrieb2020-11-07T22:12:13Z<p>Amenomade: Bild von https://forum.fhem.de/index.php/topic,115656.0/topicseen.html#msg1099231</p>
<hr />
<div>{{Infobox Hardware<br />
|Bild=HM-LC-Sw4-Ba-PCB.jpg<br />
|Bildbeschreibung=HomeMatic 4 Kanal Schaltaktor (für Batteriebetrieb)<br />
|HWProtocol=HomeMatic<br />
|HWType=Aktor<br />
|HWCategory=HomeMatic<br />
|HWComm=868MHz<br />
|HWChannels=4<br />
|HWVoltage=4-15V bzw. 2-3V &nbsp;DC<br />
|HWPowerConsumption=30mA max, 100μA (WOR)<br />
|HWPoweredBy=Kleinspannung / Batterie<br />
|HWSize=61x72mm<br />
|HWDeviceFHEM=[[CUL_HM]]<br />
|HWManufacturer=ELV / eQ-3 <br />
}}<br />
Mit dem [[HM-LC-Sw4-Ba-PCB 4-Kanal-Funk-Schaltaktor für Batteriebetrieb]] können bis zu vier angeschlossene Geräte per Funk oder über Taster auf der Platine geschaltet werden.<br />
<br />
== Features ==<br />
Batteriebetriebener Schaltaktor zum Schalten von batterie- oder akkubetriebenen Geräten (max. 20 V bei max. 3 A). Durch Verwendung eines MOSFET nur geringfügig höherer Energiebedarf (im Gegensatz zu Relais) im eingeschalteten Zustand. Ein Schalten ist über passende Fernbedienungen, HM-Schalter oder per Software (hier FHEM) möglich. Dies ist die 4-Kanal-Variantes des [[HM-LC-Sw1-Ba-PCB]].<br />
<br />
'''Technische Daten:'''<br />
* Spannungsversorgung: 2-3 V oder 4-15 V = (über Steckbrücke auswählbar)<br />
* Stromverbrauch im Burst-Modus: 100 μA<br />
* Schaltausgänge: 4 Open-Drain-Ausgang 3 A max. 20 VDC<br />
* Maße(BxHxT): 45 x 24 x 45 mm<br />
<br />
== Hinweise zu Inbetriebnahme und Installation ==<br />
Nach der Erstinbetriebnahme sollte die Warnschwelle für zu niedrige Versorgungsspannung eingestellt werden, ansonsten gibt es im Logfile laufend Warnungen. Einstellung auf beispielsweise 6 V mit dem folgenden Befehl:<br />
:<code>set CUL_HM_HM_LC_SW4_BA_PCB_xxxxxx regSet lowBatLimitBA 6</code><br />
Möglich sind Werte zwischen 5 und 15 V (4.5 werden z.B. von FHEM als ungültig abgewiesen).<br />
<br />
<Bitte ergänzen><br />
<br />
== Hinweise zum Betrieb mit FHEM ==<br />
Der HM-LC-SW4-BA-PCB kann mit einem [[CUL]] erst mit einer Firmware (culfw) ab Stand Mai 2013 betrieben werden. Grund hierfür ist der Burst-Modus, der in früheren Versionen der culfw nicht unterstützt wird (siehe {{Link2Forum|Topic=12902|LinkText=hier}}).<br />
<br />
Alternativ kann zur Ansteuerung des Aktors ein [[HMLAN Konfigurator|HM-LAN]] verwendet werden.<br />
<br />
Im Auslieferungszustand ist die LED-Signalisierung ausgeschaltet. Mittels<br />
:<code>set CUL_HM_HM_LC_SW4_BA_PCB_xxxxxx regSet ledMode on</code><br />
kann man die onboard-LED-Signalisierung ein- und per<br />
:<code>set CUL_HM_HM_LC_SW4_BA_PCB_xxxxxx regSet ledMode off</code><br />
wieder ausschalten. Sowohl bei manueller Betätigung als auch bei Steuerung via FHEM zeigen die LED dann den Schaltstatus an.<br />
<br />
=== FHEM Config-Auszug ===<br />
Bei eingeschaltetem [[autocreate]] werden von FHEM folgende Einträge in der [[Konfiguration]] erzeugt:<br />
<pre><br />
define HM_123456 CUL_HM 123456<br />
attr HM_123456 IODev CUL_0<br />
attr HM_123456 autoReadReg 4_reqStatus<br />
attr HM_123456 expert 2_full<br />
attr HM_123456 firmware 1.1<br />
attr HM_123456 model HM-LC-SW4-BA-PCB<br />
attr HM_123456 msgRepeat 1<br />
attr HM_123456 serialNr MEQ0166010<br />
attr HM_123456 subType switch<br />
attr HM_123456 webCmd getConfig:clear msgEvents<br />
define FileLog_HM_123456 FileLog ./log/HM_123456-%Y.log HM_123456<br />
attr FileLog_HM_123456 logtype text<br />
define HM_123456_Sw_01 CUL_HM 12345601<br />
attr HM_123456_Sw_01 model HM-LC-SW4-BA-PCB<br />
attr HM_123456_Sw_01 peerIDs 00000000,<br />
attr HM_123456_Sw_01 webCmd statusRequest:toggle:on:off<br />
define HM_123456_Sw_02 CUL_HM 12345602<br />
attr HM_123456_Sw_02 model HM-LC-SW4-BA-PCB<br />
attr HM_123456_Sw_02 peerIDs 00000000,<br />
attr HM_123456_Sw_02 webCmd statusRequest:toggle:on:off<br />
define HM_123456_Sw_03 CUL_HM 12345603<br />
attr HM_123456_Sw_03 model HM-LC-SW4-BA-PCB<br />
attr HM_123456_Sw_03 peerIDs 00000000,<br />
attr HM_123456_Sw_03 webCmd statusRequest:toggle:on:off<br />
define HM_123456_Sw_04 CUL_HM 12345604<br />
attr HM_123456_Sw_04 model HM-LC-SW4-BA-PCB<br />
attr HM_123456_Sw_04 peerIDs 00000000,<br />
attr HM_123456_Sw_04 webCmd statusRequest:toggle:on:off<br />
</pre><br />
<br />
=== Mögliche Schaltoperationen ===<br />
* on<br />
* on-for-timer<br />
* off<br />
* toggle<br />
Über FHEM wird zudem on-till unterstützt.<br />
<br />
=== Log-Auszüge ===<br />
====FHEM-Log====<br />
<Bitte ergänzen><br />
<br />
====Device-Log====<br />
<Bitte ergänzen><br />
<br />
== Links ==<br />
* Anleitung: [http://files.elv.de/Assets/Produkte/13/1305/130557/Downloads/130557_hm_schaltaktor_um.pdf PDF]<br />
* 1-Kanal-Variante des Aktors: [[HM-LC-Sw1-Ba-PCB]]<br />
* 4-Kanal-Variante mit Relais: [[HM-LC-Sw4-PCB 4-Kanal-Schaltaktor]]<br />
<br />
[[Kategorie:HomeMatic Components]]<br />
[[Kategorie:Schalter (Empfänger)]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=Datei:HM-LC-Sw4-Ba-PCB.jpg&diff=34182Datei:HM-LC-Sw4-Ba-PCB.jpg2020-11-07T22:11:04Z<p>Amenomade: HM-LC-Sw4-Ba-PCB</p>
<hr />
<div>== Beschreibung ==<br />
HM-LC-Sw4-Ba-PCB</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=DbLog&diff=32485DbLog2020-01-19T11:01:04Z<p>Amenomade: /* Beispiel: Anlegen und Nutzung einer SQLite-Datenbank */ Update Befehle nach contrib</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Protokolliert Ereignisse in einer Datenbank<br />
|ModType=h<br />
|ModForumArea=Automatisierung<br />
|ModTechName=93_DbLog.pm<br />
|ModOwner=tobiasfaust ({{Link2FU|118|Forum}}/[[Benutzer Diskussion:Tobias.faust|Wiki]])<br />DS_Starter ({{Link2FU|16933|Forum}}/[[Benutzer Diskussion:DS_Starter|Wiki]])<br />
}}<br />
<br />
== Einleitung ==<br />
Mit der Zeit entstehen in FHEM recht umfangreiche Log-Daten für die verschiedensten konfigurierten Devices. Die übliche Einstiegs-[[Konfiguration]] sieht vor, dass die Logs als {{Link2CmdRef|Lang=de|Anker=FileLog|Label=FileLog}} gespeichert werden - je nach Einstellung in wenigen sehr großen oder vielen kleineren Dateien. Der Datei-basierte Zugriff ist allerdings nicht wirklick performant und kann schnell zum Flaschenhals werden (z.B. bei der Darstellung von Graphen über einen längeren Zeitraum).<br />
<br />
Alternativ kann FHEM die Log-Daten mittels {{Link2CmdRef|Lang=de|Anker=DbLog|Label=DbLog}} in einer Datenbank speichern. Diese kann lokal als einfache SQLite- oder als zentrale Server-Datenbank (s.u.) gestaltet sein. Schon eine lokale einfache SQLite-Datenbank ist in der Regel deutlich performanter als File-basierte Logs.<br />
<br />
Damit eine Datenbank-Nutzung möglich ist, müssen folgende Anpassungen gemacht werden:<br />
# [[#Datenbank|Erstellen einer entsprechenden Datenbank]]<br />
# [[#Datenbank-Anbindung mittels db.conf|Konfiguration der Datenbank-Anbindung in FHEM]]<br />
# [[#Konfiguration als Device in fhem.cfg|Anpassen aller (oder einzelner) Konfigurationen von FileLog nach DbLog]]<br />
# [[#Anpassen der gplot-Konfigurationen|Ggf. Anpassen der gplot-Konfigurationen]]<br />
<br />
;Hinweis:<br />
Reporting und Management von DbLog-Datenbankinhalten kann mit dem Modul [[DbRep - Reporting und Management von DbLog-Datenbankinhalten|DbRep]] stattfinden.<br />
<br />
== Konfiguration ==<br />
=== Datenbank-Anbindung mittels db.conf ===<br />
DbLog wird durch 2 verschiedene Einträge aktiviert/definiert. In einer Datei namens '''db.conf''' werden die Parameter für eine Verbindung zur Datenbank (host, username, password, etc.) hinterlegt. Diese Datei kann in einem beliebigen Verzeichnis angelegt werden. Für eine MySQL-Datenbank sieht die db.conf folgendermaßen aus:<br />
<br />
%dbconfig= (<br />
connection => "mysql:database=fhem;host=db;port=3306",<br />
user => "fhemuser",<br />
password => "fhempassword",<br />
);<br />
<br />
Im Verzeichnis '''contrib/dblog''' der FHEM-Installation befindet sich eine Beispielkonfiguration mit der Syntax für jeden unterstützen Datenbanktyp.<br />
Es wird empfohlen diese Datei zu kopieren und erst dann entsprechend zu bearbeiten. Am Besten kopiert man diese Datei in das FHEM Home Directory /opt/fhem/ und achtet auf die entsprechenden Rechte!<br />
chown fhem:dialout /opt/fhem/db.conf<br />
<br />
=== Konfiguration als Device ===<br />
Das DbLog Device wird dann definiert mit<br />
:<code>define <name> DbLog <configfilename> <regexp> </code><br />
wobei ''<configfilename>'' dem Pfad zur zuvor angelegten db.conf entspricht.<br />
Ein Beispiel hierfür wäre:<br />
:<code>define logdb DbLog ./db.conf .*:.* </code><br />
Die Angabe von <code>.*:.*</code> bedeutet, dass sämtliche DeviceMessages (Messwerte, Batteriestatus, KeepAlives, etc.) in die Datenbank geschrieben werden. Dies führt u.U. dazu, dass die Datenbank auch mit vielen teils irrelevanten Werten gefüllt wird. Man kann daher die zu loggenden Werte einschränken, indem man genau angibt welche Werte übertragen werden sollen. Dies ist in [[#Finetuning des Loggings]] beschrieben.<br />
<br />
Unbedingt beachten: bei Verwendung des Moduls configdb wird die Konfigurationsdatei aus der '''''Datenbank''''' gelesen. Deshalb ist es erforderlich, das File mittels <code>configdb fileimport db.conf </code> vorher zu importieren !<br />
<br />
=== Finetuning des Loggings ===<br />
Bei der Konfiguration des Log-Devices werden die zu loggenden Daten definiert - in der einfachsten Form sieht das so aus: <code>define logdb DbLog ./db.conf .*:.* </code>. Die Angabe von <code>.*:.*</code> bedeutet, dass sämtliche DeviceMessages (Messwerte, Batteriestatus, KeepAlives, etc.) in die Datenbank geschrieben werden. Dies führt u.U. dazu, dass die Datenbank auch mit sehr vielen und teils nicht benötigten Werten gefüllt wird und schnell wächst. Die Datenbank ist zwar deutlich leistungsfähiger, was große Datenmengen angeht, Datensparsamkeit kann aber schnell sinnvoll werden...<br />
<br />
Um das Log-Aufkommen einzugrenzen gibt es mehrere Ansätze:<br />
* Einschränkung über den <code>define</code>-Eintrag<br />
* Einschränkung über DbLogExclude-Einträge der jeweiligen Devices<br />
* Einschränkung über DbLogInclude-Einträge des jeweiligen Devices<br />
* Ausschluß von Device/Reading-Kombinationen über das Attribut "excludeDevs". Es können [https://fhem.de/commandref_DE.html#devspec devspec] verwendet werden. <br />
<br />
==== Einschränkung über den zentralen <code>define</code>-Eintrag ====<br />
Man kann die zu loggenden Werte einschränken, indem man genau angibt welche Werte übertragen werden sollen. Die erste Wildcard, also das erste <code>.*</code>, entspricht dem in FHEM verwendeten Device-Namen. Die zweite Wildcard entspricht dem vom Device ausgegebenen zu loggenden Wert. Separiert werden beiden Angaben durch einen Doppelpunkt. <br />
<br />
Ein Beispiel, um zwar alle definierten Devices zu erfassen, aber nur die Werte Temperatur, Ventilposition und Luftfeuchte in die Datenbank zu schreiben wäre:<br />
:<code>define myDbLog DbLog ./db.conf .*:(temperature|valveposition|humidity).* </code><br />
<br />
==== Einschränkung über die jeweiligen Devices ====<br />
Man kann die zu loggenden Werte für einzelne Devices separat einschränken, ohne dies im zentralen define-Eintrag machen zu müssen. Dies kann interessant sein, wenn beispielsweise ein Device Fehlerwerte meldet, die uninteressant sind, oder es meldet unnötig häufig Werte - beides ist z.B. bei 1-wire-Temperatursensoren gerne der Fall.<br />
<br />
Um das einzuschränken gibt es 2 Stellparameter, die als Attribute direkt zum jeweiligen Device konfiguriert werden:<br />
* DbLogExclude - definiert Werte, die nicht geloggt werden sollen<br />
* DbLogInclude - definiert Werte, die geloggt werden sollen ( siehe attr DbLogSelectionMode )<br />
* event-min-interval, event-on-change-reading und event-on-update-reading beeinflussen, wie häufig Werte geloggt werden (vgl. {{Link2CmdRef|Lang=de|Anker=event-on-update-reading}})<br />
<br />
Eine konkrete Konfiguration für einen sehr gesprächigen 1-wire-Temperatursensor könnte wie folgt aussehen:<br />
<pre><br />
define EG_Balkon GPIO4 BUSMASTER<br />
attr EG_Balkon DbLogExclude failures,T,85 # logge keine "failures", "T"-Werte und "85"-Werte (default-Werte, wenn keine Temperatur gelesen werden kann)<br />
attr EG_Balkon event-on-change-reading state # logge nur, wenn sich ein Wert ändert (wenn sich die Temperatur nicht ändert, logge das nicht)<br />
attr EG_Balkon event-min-interval state:900 # logge spätestens alle 900sec = 15min<br />
attr EG_Balkon event-on-update-reading .* # logge alle Werte, die aktualisiert werden<br />
<br />
attr <1-Wire-Device vom Typ OWTHERM oder OWSWITCH> DbLogExclude data.* # verhindert das Logging der state-Eintragungen<br />
</pre><br />
<br />
Eine in diesem {{Link2Forum|Topic=33697|Message=264127}} vorgestellte Strategie zur Vermeidung unnötigen Loggings ist, dass bei der Definition von Devices durch das nachfolgende <code>notify</code> automatisch ein DbLogExclude für alle Werte (.*) des Devices zugewiesen wird und dies nur bei Interesse an geloggten Werten gelöscht bzw. angepasst wird:<br />
<code>define nDbLogExclude notify global:DEFINED.* attr $EVTPART1 DbLogExclude .*</code><br />
<br />
Ebenso ist es mittlerweile möglich, lediglich erwünschte Werte (Positiv-Liste) zu loggen und alle anderen zu verwerfen. Hierfür wird im LogDevice das attribut DbLogSelectionMode Include verwendet. Nun kann für jedes Device mit DbLogInclude <Reading1>,<Reading2>,... angegeben werden, welche Readings geloggt werden sollen. <br />
Integriert ist ebenfalls ein "min-interval", siehe {{Link2CmdRef}}.<br />
<br />
== Datenbank ==<br />
Unterstützte Datenbanksysteme (Auswahl):<br />
* Sqlite<br />
* MySQL<br />
* PostGreSql<br />
<br />
=== Tabellen ===<br />
Die Datenbank ist relativ simpel gestaltet und besteht lediglich aus den folgenden beiden Tabellen:<br />
* current<br />
* history<br />
<br />
DbLog ist auf eine feste Tabellenstruktur angewiesen. Man muss daher in seiner Datenbank eine Tabelle mit folgenden Spalten anlegen:<br />
{| class="wikitable"<br />
|-<br />
! Spalte<br />
! Beschreibung (en)<br />
! Beschreibung (de)<br />
! Beispiel<br />
|-<br />
| '''TIMESTAMP'''<br />
| timestamp of event<br />
| Zeitstempel<br />
| 2007-12-30 21:45:22 <br />
|-<br />
| '''DEVICE'''<br />
| device name<br />
| Device-Name<br />
| Wetterstation<br />
|-<br />
| '''TYPE'''<br />
| device type<br />
| Device-Typ<br />
| KS300<br />
|-<br />
| '''EVENT'''<br />
| event specification as full string<br />
| Eventspezifikation als Text<br />
| humidity: 71 (%)<br />
|-<br />
| '''READING'''<br />
| name of reading extracted from event<br />
| Bezeichnung des Readings<br />
| humidity<br />
|-<br />
| '''VALUE'''<br />
| actual reading extracted from event<br />
| Wert des Readings<br />
| 71<br />
|-<br />
| '''UNIT'''<br />
| unit extracted from event<br />
| Einheit des Readings<br />
| %<br />
|-<br />
|}<br />
<br />
Die Vorlagen zur Anlage von Tabellen und Indizes sind für jeden unterstützten Datenbanktyp im Verzeichnis '''contrib/dblog''' der FHEM-Installation, oder hier zu finden: [https://svn.fhem.de/trac/browser/trunk/fhem/contrib/dblog/ Link]. Das MySQL-Skript (db_create_mysql.sql) legt eine neue Datenbank, das PostGres-Skript (db_create_postgresql.sql) ein neues Schema mit Namen "fhem" an.<br />
<br />
==== current ====<br />
Die Tabelle current enthält für jedes zu loggende Device lediglich den letzten Wert. Falls noch kein Wert geloggt wurde, ist diese Tabelle leer. <br />
Falls der Inhalt gelöscht wird, bauen sich die Daten automatisch wieder auf. Es gehen durch das löschen der Tabelle current keine Log-Informationen verloren.<br />
Der Inhalt wird aber u.a. für die Dropdown-Felder beim Plot-Editor verwendet.<br />
<br />
Um doppelte Einträge in der Tabelle zu vermeiden, wurden die Möglichkeit geschaffen Primary Keys zu definieren. Da in der Spalte <code>READING</code> u.U. bei verschiedenen Geräten gleiche Namen vorkommen können, sollte der Primary Key um den Gerätenamen erweitert werden. Der Primary Key sollte also aus <code>DEVICE</code> und <code>READING</code> bestehen. Um in der Datenbank ''fhem'' diesen PK zu setzen, kann folgender SQL Code verwendet werden:<br />
<br />
<syntaxhighlight lang="sql"><br />
ALTER TABLE `fhem`.`current` <br />
CHANGE COLUMN `DEVICE` `DEVICE` VARCHAR(64) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL ,<br />
CHANGE COLUMN `READING` `READING` VARCHAR(64) CHARACTER SET 'utf8' COLLATE 'utf8_bin' NOT NULL ,<br />
ADD PRIMARY KEY (`DEVICE`, `READING`);<br />
</syntaxhighlight><br />
<br />
==== history ====<br />
Die Tabelle history enthält alle bisher geloggten Daten. Löschen in dieser Tabelle bedeutet automatisch Datenverlust (gewollt oder nicht ... )<br />
Der Inhalt dieser Tabelle wird verwendet, um die Plots zu zeichnen oder Auswertungen mit [https://wiki.fhem.de/wiki/DbRep_-_Reporting_und_Management_von_DbLog-Datenbankinhalten DbRep] anzufertigen<br />
<br />
{{Todo|Ausbauen}}<br />
<br />
Um Problem beim Import von cacheFiles zu vermeiden, kann in der Datenbank ein PK angelegt werden, welcher Timestamp, Device und Reading umfasst. Dadurch werden doppelte Einträge wirksam verhindert.<br />
<br />
== Anpassen der gplot-Konfigurationen ==<br />
Die meisten gplot-Konfigurationen sind bisher lediglich auf FileLog-Konfigurationen ausgelegt. Deshalb müssen sie für die Verwendung mit DbLog angepasst werden. Glücklicherweise beschränkt sich dies auf die reinen FileLog-Zeilen - es müssen die DbLog-Äquivalente hinzugefügt werden. Die FileLog-Einträge müssen zwar nicht gelöscht werden, wenn man aber FileLog und DbLog parallel betreibt, sollte man getrennte gplot-Dateien für beide Logging-Typen haben um Auswertungsprobleme erkennen zu können.<br />
<br />
Für die fht.gplot Konfiguration sähe die Anpassung wie folgt aus (lediglich die vier DbLog-Zeilen wurden hinzugefügt):<br />
<pre><br />
# Created by FHEM/98_SVG.pm, 2014-12-25 21:53:30<br />
set terminal png transparent size <SIZE> crop<br />
set output '<OUT>.png'<br />
set xdata time<br />
set timefmt "%Y-%m-%d_%H:%M:%S"<br />
set xlabel " "<br />
set title '<L1>'<br />
set ytics nomirror<br />
set y2tics <br />
set grid y2tics<br />
set ylabel "Actuator/Window (%)"<br />
set y2label "Temperature in C"<br />
set yrange 0:100<br />
set y2range 5:25<br />
<br />
#FileLog 4:.measured-temp\x3a:0:<br />
#FileLog 4:.actuator\x3a:0:int<br />
#FileLog 4:.desired-temp::<br />
#FileLog 4:.window\x3a::<br />
<br />
#DbLog <SPEC1>:.measured-temp:0:<br />
#DbLog <SPEC1>:.actuator:0:int<br />
#DbLog <SPEC1>:.desired-temp::<br />
#DbLog <SPEC1>:.window::<br />
<br />
plot "<IN>" using 1:2 axes x1y2 title 'Measured temperature' ls l0 lw 1 with lines,\<br />
"<IN>" using 1:2 axes x1y1 title 'Actuator (%)' ls l1 lw 1 with lines,\<br />
"<IN>" using 1:2 axes x1y2 title 'Desired Temperature' ls l2 lw 1 with steps,\<br />
"<IN>" using 1:2 axes x1y1 title 'Window' ls l3 lw 1 with steps<br />
</pre><br />
<br />
Des Weiteren ist zu beachten: <br />
<br />
On-Off-Plots<br />
<br />
EG_Bad:window:::$val=~s/(on|off)(\d*).*/$1eq"on"?1:0/eg<br />
<br />
unter Berücksichtigung von dim-Werten:<br />
<br />
EG_WoZi_Licht:value:::$val=~s/(on|off)(\d*).*/$1eq"on"?1:($1eq"dim"?$2*0.01:0)/eg<br />
<br />
== Beispiel: Anlegen und Nutzung einer SQLite-Datenbank ==<br />
Im folgenden wird eine lokale SQLite-Datenbank auf einen Ubuntu-System angelegt (nach Quelle: [http://www.tatsch-it.de/fhem-dblog/ http://www.tatsch-it.de/fhem-dblog/])<br />
<ol><br />
<li><br />
''Installation von SQLite:''<br />
<pre>sudo aptitude install sqlite3 libdbi-perl libdbd-sqlite3-perl</pre><br />
</li><br />
<li><br />
''Anlegen der SQLite-Datenbank fhem.db'' (öffnet auch direkt eine SQL-Kommandozeile):<br />
<pre>sudo sqlite3 /opt/fhem/fhem.db</pre><br />
In der geöffneten SQL-Kommandozeile eingeben:<br />
<pre><br />
CREATE TABLE history (TIMESTAMP TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));<br />
CREATE TABLE current (TIMESTAMP TIMESTAMP, DEVICE varchar(64), TYPE varchar(64), EVENT varchar(512), READING varchar(64), VALUE varchar(128), UNIT varchar(32));<br />
CREATE INDEX Search_Idx ON `history` (DEVICE, READING, TIMESTAMP);<br />
</pre><br />
Die Kommandozeile verlässt man mit <code>.exit</code>.<br />
</li><br />
<li><br />
''Anpassen des Besitzers und der Rechte der Datenbank-Datei:''<br />
<pre><br />
sudo chown fhem /opt/fhem/fhem.db<br />
sudo chmod 666 /opt/fhem/fhem.db<br />
</pre><br />
</li><br />
<li><br />
''Datenbank-Anbindung des FHEM konfigurieren:''<br />
<pre>sudo nano /opt/fhem/db.conf</pre><br />
Inhalt:<br />
<pre><br />
%dbconfig= (<br />
connection => "SQLite:dbname=/opt/fhem/fhem.db",<br />
user => "",<br />
password => ""<br />
);<br />
</pre><br />
</li><br />
<li><br />
''Logging des FHEM auf die Datenbank konfigurieren:'' (hier sind nur die Anpassungen aufgeführt)<br />
<pre>sudo nano /opt/fhem/fhem.cfg</pre><br />
<pre><br />
...<br />
attr global userattr DbLogExclude ... # erlaubt es einzelne Einträge nicht zu loggen<br />
...<br />
define logdb DbLog ./db.conf .*:.* # logt alle(!) auflaufenden Events aller Konfigurationen<br />
...<br />
</pre><br />
Da durch diese <code>define</code>-Definition alle auflaufenden Events gelogt werden, müssen keine weiteren Anpassungen in der Konfiguration gemacht werden. Die FileLog-Einträge können bedenkenlos bestehen bleiben - dann wird in Datenbank und FileLog gelogt und man verliert keine Daten, falls etwas nicht klappt. Wenn alles wie geplant läuft, können die FileLog-Definitionen gelöscht werden (ebenso die Log-Dateien). Ebenso können die zu loggenden Daten später eingegrenzt werden (s. [[#Finetuning des Loggings]]).<br />
</li><br />
<li><br />
''FHEM neu starten:''<br />
<pre><br />
sudo service fhem stop<br />
sudo service fhem start<br />
</pre><br />
</li><br />
<li><br />
''Kontrollieren, ob Logs in die Datenbank geschrieben werden:''<br />
<pre>sudo sqlite3 /opt/fhem/fhem.db</pre><br />
In der geöffneten SQL-Kommandozeile eingeben:<br />
<pre><br />
select * from history order by TIMESTAMP; # dies gibt alle(!) Logs chronologisch aus (kann nach längerem Betrieb recht lange dauern)<br />
</pre><br />
Die Kommandozeile verlässt man mit <code>.exit</code>.<br />
</li><br />
<li><br />
''Anpassung der glot-Dateien:'' siehe [[#Anpassen der gplot-Konfigurationen]]<br />
</li><br />
</ol><br />
<br />
== Beispiel: Anlegen und Nutzung einer Mysql-Datenbank ==<br />
Hierfür gibt es eine [[DbLog-MySQL|extra Seite]], die die Unterschiede und Feinheiten zwischen den verschiedenen Versionen berücksichtigt<br />
<br />
Anstatt nano kann jeder andere kompatible Editor verwendet werden. Weiterhin bitte beachten, dass die hier genannten Befehle teilweise root-Rechte voraussetzen. Entweder komplett als root arbeiten, oder mittels sudo.<br />
<br />
Unter Ubuntu/debian: <br />
apt-get update && apt-get install mysql-server mysql-client libdbd-mysql libdbd-mysql-perl<br />
<br />
<br />
Bei der Installation sollte man aus Sicherheitsgründen ein Passwort für den mysql-root vergeben, wenn man nicht sogar ganz den Login verbietet.<br />
<br />
Hinweis: im Folgenden ist "#" der normale Prompt und "mysql>" der prompt innerhalb mysql, dieser kann mit exit verlassen werden. <br />
<br />
Zum Test mal mit mysql verbinden:<br />
# mysql -p -u root<br />
Enter password:<br />
mysql> exit<br />
<br />
Jetzt die Tabellenstruktur anlegen. <br />
Hierfür kann die Datei /opt/fhem/contrib/dblog/db_create_mysql.sql als Vorlage verwendet und das Passwort und der Benutzername geändert werden. <br />
cd /opt/fhem/contrib/dblog/<br />
nano db_create_mysql.sql<br />
Dann wird die Datei eingelesen (root Passwort wird abgefragt): <br />
<br />
# mysql -u root -p < db_create_mysql.sql<br />
<br />
Jetzt kann man den Zugang testen: <br />
<br />
# mysql -p -u <fhemuser><br />
Enter password: <fhempassword><br />
mysql> show databases;<br />
<br />
Nun müsste eine Datenbank "fhem" angezeigt werden, die die Tabellen current und history enthält.<br />
<br />
Nun in der Datei db.conf den mysql-Block auskommentieren und ebenfalls Benutzername, Passwort UND HOST anpassen. Leider ist hier nicht standardmäßig localhost eingestellt.<br />
nano /opt/fhem/db.conf<br />
<br />
Jetzt kann unter FHEM ein DbLog-Device angelegt werden (mit dem beispiel wird alles geloggt: <br />
define logdb DbLog ./db.conf .*:.*<br />
Als State muss ein "connected" angezeigt werden. <br />
<br />
Ein rereadcfg in FHEM stellt sicher, dass die neue Konfiguration übernommen wird - ein Neustart ist nicht erforderlich.<br />
<br />
Nun kann die Funktion noch einmal überprüft werden: <br />
<syntaxhighlight lang="sql"><br />
# mysql -u <fhemuser> -p<br />
Enter password: <fhempassword><br />
mysql> use fhem;<br />
Database changed<br />
mysql> show tables;<br />
+----------------+<br />
| Tables_in_fhem |<br />
+----------------+<br />
| current |<br />
| history |<br />
+----------------+<br />
2 rows in set (0,00 sec)<br />
mysql> select * from history; # Achtung, kann sehr groß werden .... #<br />
</syntaxhighlight><br />
<br />
Anscheinend gibt es bei der neuen Version MariaDB (im Gegensatz zu mysql) ein neues Anmeldeverfahren, so dass in der Datenbank selbst Veränderungen vorgenommen werden müssen, damit der Zugriff durch FHEM funktioniert: https://kofler.info/root-login-problem-mit-mariadb/<br />
<br />
== Beispiel: Abfragescript PHP/MySQL ==<br />
Um eine schnelle Übersicht zu bekommen habe ich mir dieses Script geschrieben:<br />
<syntaxhighlight lang="php"><?php $pdo = new PDO('mysql:host=localhost;dbname=fhem', 'fhemuser', 'fhempasswort');<br />
echo '<h2>Tabelle Current</h1><br><table border="1">';<br />
echo "<tr><th>Anzahl</th><th>Name</th><th>Readings</th></tr>";<br />
$sql = "SELECT COUNT(*), DEVICE, GROUP_CONCAT(DISTINCT READING ORDER BY READING DESC SEPARATOR '</li><li>') FROM current GROUP BY DEVICE;"; foreach ($pdo->query($sql) as<br />
$row) {<br />
echo "<tr><td>" . $row[0] . "</td><td>" . $row[1] . "</td><td><ol><li>" . $row[2] . "</li></ol></td></tr>";<br />
}<br />
echo "</table>";<br />
<br />
<br />
echo '<h2>Tabelle History</h1><br><table border="1">';<br />
echo "<tr><th>Anzahl</th><th>Name</th></tr>";<br />
$sql = "SELECT COUNT(*), DEVICE FROM history GROUP BY DEVICE;"; foreach ($pdo->query($sql) as<br />
$row) {<br />
echo "<tr><td>" . $row[0] . "</td><td>" . $row[1] . "</td></tr>";<br />
}<br />
echo "</table>";<br />
?><br />
</syntaxhighlight><br />
<br />
Bitte passt fhemuser und fhempasswort an. Das Ganze kommt dann nach ''/var/www/html/fhemdb.php'' und ist mit ''<IP>/fhemdb.php'' aufrufbar. Wenn ihr den 2. Block für die history Tabelle ausklammert oder entfernt läuft das Script viel schneller ab - klar die history Tabelle ist meist randvoll.<br />
<br />
== Integration von DBLog in eigene Module ==<br />
=== Bereitstellung der UNITS ===<br />
Mit der DbLog_splitFn kann der Modulautor selbst festlegen, wie die Events des Moduls in die Bestandteile Reading/Value/Unit zerlegt werden um ein korrektes Logging per DbLog zu gewährleisten.<br />
<br />
Dazu muss der Modulautor in der [[DevelopmentModuleIntro#X_Initialize|Initialize-Funktion]] eine <code>DbLog_splitFn</code> bereitstellen:<br />
<br />
<syntaxhighlight lang="perl"><br />
sub X_Initialize($)<br />
{<br />
my ($hash) = @_;<br />
...<br />
$hash->{DbLog_splitFn} = "X_DbLog_splitFn";<br />
}<br />
</syntaxhighlight><br />
<br />
Die genaue Aufrufsyntax und Funktionweise einer DbLog_split-Funktion findet man [[DevelopmentModuleIntro#X_DbLog_split|hier]].<br />
<br />
== Werte auslesen ==<br />
Manchmal möchte man Daten aus den Logs abrufen ohne händisch in der Datenbank herumzuwühlen (s.u.). Dies ist insb. auch dann hilfreich, wenn man eigenen Funktionen, Notifys oder spezielle Plots entwirft, bei denen man auf Logdaten zugreifen möchte.<br />
<br />
Grundsätzlich beschrieben ist dies in der {{Link2CmdRef|Lang=de|Anker=DbLog}} und unterscheidet sich minimal (aber entscheidend) von der Struktur bei [[FileLog#Werte_auslesen|FileLogs]].<br />
<br />
Hier ein paar Beispiele, was man damit anstellen kann:<br />
<br />
* <code>get meineDB - - 2016-10-01 2016-10-03 meinSensor</code> alle Einträge des meinSensor vom 01.10.-03.10.2016<br />
* <code>get meineDB - - 2016-10-01_08:00:00 2016-10-01_16:00:00 meinSensor</code> alle Einträge des meinSensor von 8-16 Uhr am 01.10.2016<br />
* <code>get meineDB - - 2016-10-01_08:00:00 2016-10-01_16:00:00 meinSensor:temperature</code> nur die temperature Werte<br />
* <code>{ ReadingsTimestamp("meinSensor","state","0") }</code> Timestamp des aktuellen state des meinSensor<br />
* <code>{ OldTimestamp("meinSensor") }</code> Timestamp des letzten state des FHT_3a32<br />
* <code>{ time_str2num(OldTimestamp("meinSensor")) }</code> Timestamp in Sekunden des letzten state des meinSensor<br />
* ...<br />
<br />
== Bearbeitung von Datenbank-Einträgen ==<br />
{{Hinweis|Dieser Abschnitt soll lediglich eine kleine Einführung in die Datenbank-Bearbeitung liefern. Für vertiefende Informationen sollte man sich grundsätzlich mit SQL beschäftigen. Eine umfassende und gut verständliche Anleitung zu SQL bietet bspw. [http://www.w3schools.com/sql/default.asp w3schools].}}<br />
Irgendwann wird der Fall eintreten, dass in der Datenbank Einträge drinstehen, die geändert oder gelöscht werden sollen (zB. fehlerhafte Sensor-Rückmeldungen, umbenannte Readings). In klassischen Log-Dateien würde man diese einfach bearbeiten und löschen/anpassen (wobei man aber tunlichst zuvor FHEM stoppt, um Datenfehler zu vermeiden). Eine Datenbank kann bearbeitet werden, ohne FHEM stoppen zu müssen. <br />
<br />
Datenbanken kann man ohne weitere Hilfsmittel direkt von der Kommandozeile/Shell aus bearbeiten. Alternativ gibt es auch verschiedenste Tools (webbasiert oder als Applikation), die einen dabei unterstützen (Bsp. findet man u.a. [https://wiki.ubuntuusers.de/SQLite/#Grafische-Benutzeroberflaechen hier]). Für einfache Arbeiten reicht allerdings idR. Shell.<br />
<br />
=== SQLite-Datenbanken ===<br />
'''Öffnen der DB unter Linux:''' <br />
<br />
(Es werden Schreibrechte benötigt,ohne kann man die DB zwar öffnen, aber nichts machen)<br />
sudo sqlite3 fhem.db<br />
Dadurch öffnet sich ein SQL-Konsole, auf der alle weiteren Befehle ausgeführt werden.<br />
<br />
'''Schliessen der DB:'''<br />
<br />
sqlite> .exit<br />
<br />
<br />
'''Hilfe anzeigen:'''<br />
<br />
sqlite> .help<br />
<br />
<br />
'''Alle Tabellen anzeigen:'''<br />
<br />
sqlite> .tables<br />
<br />
<br />
'''Das Schema der DB anzeigen:''' <br />
<br />
(vgl. oben [[DbLog#Datenbanken]] und [[DbLog#Beispiel: Anlegen und Nutzung einer SQLite-Datenbank]])<br />
<br />
sqlite> .schema<br />
<br />
<br />
'''Alle Eintäge anzeigen:''' <br />
<br />
Die Einträge liegen alle in der Tabelle "History".<br />
<br />
'''Ganz wichtig''' ist immer das ";" am Ende Zeile (bei allen Kommandos, die nicht mit einem "." anfangen). Wenn es vergessen wurde zeigt die Konsole solange neue Zeilen bis ein ";" eingegeben wird. So kann ein Befehl auch bequem über mehrere Zeilen geschrieben werden.<br />
<br />
sqlite> select * from HISTORY;<br />
<br />
Dies kann sehr lange dauern und kann ggf. mit <code>STRG-C</code> abgebrochen werden.<br />
<br />
<br />
'''Alle Einträge eines Geräts anzeigen:'''<br />
<br />
In <code>where</code>-Statements werden Strings in einfache Anführungsstriche gesetzt, Zahlen nicht.<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug';<br />
<br />
<br />
'''Alle Einträge eines Readings eines Geräts anzeigen:'''<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug' and READING='Graeser';<br />
<br />
<br />
'''Alle Einträge eines bestimmten Wertes eines Readings eines Geräts anzeigen:'''<br />
<br />
sqlite> select * from HISTORY where DEVICE='Pollenflug' and READING='Graeser' and VALUE>1;<br />
<br />
<br />
'''LÖSCHEN aller Einträge eines bestimmten Wertes eines Readings eines Geräts anzeigen:'''<br />
<br />
'''Achtung:''' Löschen kann nicht rückgängig gemacht werden!! Also IMMER erst die entsprechenden SELECT-Statements solange verfeinern bis wirklich nur die gewünschten Einträge angezeigt werden. Dann das <code>select *</code> durch <code>delete</code> ersetzen.<br />
<br />
sqlite> delete from HISTORY where DEVICE='Pollenflug' and READING='Graeser' and VALUE>1;<br />
<br />
<br />
== Datenbank reparieren ==<br />
Es kann immer wieder mal vorkommen, dass Datenbanken Fehler enthalten. Das muss im Alltag garnicht auffallen und auch nicht immer schlimm enden. Wenn man auf der SQL-Konsole aber bspw. eine Meldung <code>Error: database disk image is malformed</code> erhält, sollte man ein Reparatur vornehmen.<br />
<br />
=== SQLite-Datenbanken ===<br />
Die folgenden Schritte beschreiben, wie man eine SQLite-DB reparieren kann (Quelle: [http://techblog.dorogin.com/2011/05/sqliteexception-database-disk-image-is.html]):<br />
<br />
<ol><br />
<li><br />
DB öffnen:<br />
<pre>sudo sqlite3 fhem.db</pre><br />
</li><br />
<li><br />
Integritäts-Check durchführen:<br />
<pre>sqlite> pragma integrity_check;</pre><br />
Kommt hier ein "ok" ist die DB gesund. Ansonsten erscheint etwas wie<br />
<pre><br />
*** in database main ***<br />
On tree page 118786 cell 1: Rowid 75 out of order (previous was 816660)<br />
On tree page 118786 cell 4: Rowid 815704 out of order (previous was 816727)<br />
Corruption detected in cell 0 on page 118786<br />
Multiple uses for byte 132 of page 118786<br />
...<br />
</pre><br />
</li><br />
<li><br />
Datenbank-Dump erstellen (Export gesamten DB in die Datei "dump_all_20160516_1043.sql") und DB verlassen:<br />
<pre><br />
sqlite> .mode insert<br />
sqlite> .output dump_all_20160516_1043.sql<br />
sqlite> .dump<br />
sqlite> .exit<br />
</pre><br />
</li><br />
<li><br />
Neue Datenbank erstellen und den Dump einlesen, Integritäts-Check machen und verlassen:<br />
<pre>sudo sqlite3 fhem-neu.db</pre><br />
<pre><br />
sqlite> .read dump_all_20160516_1043.sql<br />
sqlite> pragma integrity_check;<br />
ok<br />
sqlite> .exit<br />
</pre><br />
</li><br />
<li><br />
Spätestens jetzt FHEM stoppen:<br />
<pre>sudo service fhem stop</pre><br />
</li><br />
<li><br />
Alte DB sichern und neue aktivieren:<br />
<pre><br />
sudo mv fhem.db fhem.db.sv_20160516<br />
sudo mv fhem-neu.db fhem.db<br />
</pre><br />
</li><br />
<li><br />
Kontrollieren, dass die neue DB die gleichen Rechte wie die alte DB hat (und ggf. korrigieren):<br />
<pre><br />
~/fhem$ ls -lha<br />
insgesamt 6,3G<br />
drwxr-xr-x 12 fhem root 4,0K Mai 16 11:07 .<br />
drwxr-xr-x 4 root root 4,0K Dez 25 17:50 ..<br />
...<br />
-rw-r--r-- 1 root root 1,4G Mai 16 11:04 fhem.db<br />
-rw-r--r-- 1 fhem root 2,6G Mai 16 10:59 fhem.db.sv_20160516<br />
...<br />
<br />
~/fhem$ sudo chown fhem:root fhem.db<br />
<br />
~/fhem$ ls -lha<br />
insgesamt 6,3G<br />
drwxr-xr-x 12 fhem root 4,0K Mai 16 11:07 .<br />
drwxr-xr-x 4 root root 4,0K Dez 25 17:50 ..<br />
...<br />
-rw-r--r-- 1 fhem root 1,4G Mai 16 11:04 fhem.db<br />
-rw-r--r-- 1 fhem root 2,6G Mai 16 10:59 fhem.db.sv_20160516<br />
...<br />
</pre><br />
</li><br />
<li><br />
FHEM wieder starten (und natürlich kontrollieren):<br />
<pre>sudo service fhem start</pre><br />
</li><br />
</ol><br />
<br />
<br />
== Datenbank migrieren ==<br />
Eine schöne Anleitung zur Migration von SQLite zu MySQL/MariaDB mit Hilfe von [[DbRep - Reporting und Management von DbLog-Datenbankinhalten|DbRep]] findet sich hier: [https://demaya.de/fhem-umzug-sqlite-mysql-mariadb/].<br />
<br />
Hinweis: Wenn die SQLite-DB sehr groß wird, kann es sein, dass der oben beschriebene Weg nicht funktioniert (konkret war dies bei meiner 15 GB großen DB nicht möglich, der Prozess hat sich immer nach mehreren Stunden aufgehängt).<br />
<br />
== Nützliche Codeschnipsel ==<br />
Anbei ein paar nützliche Codeschnipsel rund um DbLog<br />
<br />
<br />
=== Dateigrösse mitloggen ===<br />
Da die Datenbank ins Unermessliche wachsen kann, empfiehlt es sich - je nach Speicherplatz - ab einer bestimmten Grösse tätig zu werden. Dazu muss diese Grösse allerdings ermittelt werden. Diese geschieht mittels des Userreadings, welches man vorteilshafterweise mit im DbLog-device anlegt:<br />
<br />
<pre>attr myDbLog userReadings DbFileSize:reduceLogState.* { (split(' ',`du -m fhem.db`))[0] }</pre><br />
<br />
Mittels dieses Attributs wird die Grösse der .db-Datei immer nach dem Ausführen des ReduceLog in das Reading "DbFileSize" in ganzzahligen MByte abgelegt.<br />
<br />
Basierend auf diesem Reading können dann weitere Aktionen, beispielsweise ein Plot, erstellt werden.<br />
<br />
Die oben beschriebene Möglichkeit ist für SQLite verwendbar. Zur Ermittlung der DB-Größe andere DB-Typen (aber auch für SQLite nutzbar) kann wie [[DbRep_-_Reporting_und_Management_von_DbLog-Datenbankinhalten#Gr.C3.B6.C3.9Fe_der_FHEM-Datenbank_ermitteln | hier]] beschrieben vorgegangen werden.<br />
<br />
<br />
== Performance-Optimierung ==<br />
Auch eine Datenbank kann mit der Zeit langsamer werden. Dies hängt von mehreren Faktoren ab:<br />
* Menge der gelogten Daten (zB. > 4-5 GB)<br />
* Eingesetzte Hardware (zB. langsame SD-Karte vs. schnelle SSD)<br />
* Eingesetztes Datenbanksystem (zB. SQLite, MySQL)<br />
* Komplexität der Abfragen (zB. für aufwändige Graphen oder Berechnungen)<br />
<br />
Diese Punkte sollen im folgenden diskutiert werden:<br />
<br />
<br />
=== Komplexität der Abfragen ===<br />
Dies ist kein Problem der Datenbank, sondern rein der Abfrage. Dem entsprechend muss die Optimierung auch in der Abfrage oder im Skript gesucht werden. Dies ist nicht Ziel dieses Abschnittes und wird hier nicht weiter behandelt.<br />
<br />
<br />
=== Eingesetztes Datenbanksystem ===<br />
Welches Datenbanksystem eingesetzt wird (zB. SQLite oder MySQL) hat auf die Performance der Datenbank gar keinen so großen Einfluss, wie vielleicht zuerst gedacht. Selbst SQLite kann problemlos Datenbanken mit etlichen GB Größe performant verarbeiten. Der Flaschenhals ist hier viel mehr die darunter liegende Hardware (s.u.).<br />
<br />
Die Performance der Datenbank an sich, kann aber durch verschiedene Maßnahmen verbessert werden:<br />
* Pflegemaßnahmen bzgl. der Daten<br />
* '''Erstellung von Indizes'''<br />
<br />
<br />
==== Menge der Daten und Pflegemaßnahmen bzgl. der Daten ====<br />
Die Menge der geloggten Daten hat natürlich Einfluss auf die Geschwindigkeit von Abfragen - je mehr Daten vorhanden sind, desto mehr Daten müssen auch durchforstet werden um eine Abfrage zu bedienen. Die Reduzierung der geloggten Datenmenge hat also direkten Einfluss auf die Größe und damit auch die Geschwindigkeit der Datenbank. Die Menge der zu loggenden Daten lässt sich an zwei Stellen einschränken:<br />
* bei der Definition jedes Devices (s. Kapitel oben)<br />
* bei der Festlegung des fhem-weiten Log-Levels (s. [[Loglevel]])<br />
<br />
Die Menge der bereits geloggten Daten kann zB. mit Hilfe von [[DbRep - Reporting und Management von DbLog-Datenbankinhalten|DbRep]] verringert und optimiert werden, bspw.<br />
* löschen unnötiger Daten<br />
* vacuum der Datenbank<br />
<br />
Insgesamt haben diese Maßnahmen aber nur einen eingeschränkten Effekt auf die Performance der DB. Deutlich effektiver ist die Erstellung eines Index (s.u.).<br />
<br />
<br />
==== Erstellung von Indizes ====<br />
Die Erstellung von Indizes hat mit Abstand den größten Einfluss auf die Performance einer Datenbank (auf unveränderter Hardware). Extrem zusammengefasst ist ein Index eine extrem optimiertes Nachschlageverzeichnis für einen bestimmten Typ Daten (ein Index wie im Buch halt). Eine wunderbare Einführung in Indizes bietet [[https://use-the-index-luke.com/de|https://use-the-index-luke.com]].<br />
<br />
In fhem sind Indizes sogar sehr einfach einzurichten da die Datenbank-Nutzung sehr stark vorgegeben ist. Nahezu jede Abfrage folgt dem Schema ''Device -> Reading -> Datum -> Wert''. Ein Index kann genau diese Abfrage bedienen und beschleunigen. Ein Index nur über die Devices wäre ein erster Schritt, brächte aber noch keinen großen Gewinn (wie um Link oben gut beschrieben). Über die gesamten ersten drei Schritte erstellt (Device -> Reading -> Datum) bringt der Index aber sofort eine deutliche Geschwindigkeitssteigerung.<br />
<br />
Die Erstellung eines Index erfolgt direkt in der Datenbank (und nicht aus fhem heraus), hier am Beispiel einer SQLite-DB:<br />
<br />
Öffnen der DB:<br />
<pre> sudo sqlite3 fhem.db </pre><br />
<br />
Erzeugen des Index auf der DB-Konsole (das Semikolon am Ende ist wichtig):<br />
<pre> create index idx_device_reading_timestamp on history (device, reading, timestamp); </pre><br />
<br />
Verlassen der DB:<br />
<pre> .exit </pre><br />
<br />
Einzig zu berücksichtigen ist, dass dieser Index die Datenbank um bis zu 1/3 vergrößert. Er kann aber bei Bedarf auch wieder entfernt werden. Bei meiner 15 GB SQLite-Datei (auf einem Mac Mini mit SSD) hat dies ca. 15 min gedauert (den fhem hatte ich vorsichtshalber währenddessen deaktiviert).<br />
<br />
Sollte jemand spezielle Berechnungen oder Skripte ausführen, die nach einem anderen Abfrage-Schema arbeiten, könnte man dafür spezialisierte zusätzliche Indizes erstellen. Das sollte aber dann mit dem Wissen des obigen Links erarbeitet werden, da dann etwas mehr Hintergrundwissen sehr hilfreich ist.<br />
<br />
<br />
==== DB-Backup ====<br />
Ein anderer Aspekt, der eigentlich nichts mit der Performance der DB zu tun hat, ist der Einfluss aufs Backup. Wird bspw. ein Systembackup per RSYNC gemacht, muss bei SQLite immer die komplette ggf. riesige Datei gesynct werden - bei MySQL würden nur die veränderten DB-Elemente gesynct. Dies soll hier nicht weiter vertieft werden, sollte aber bei einer Gesamtstrategie bedacht werden.<br />
<br />
<br />
=== Eingesetzte Hardware ===<br />
fhem hat grundsätzlich sehr viele kleine Datenzugriffe, unabhängig davon ob FileLog oder DbLog eingesetzt wird. Deshalb ist der absolut größte Performance-Gewinn durch den Einsatz schneller Festplatten zu erreichen - ganz einfache Aussage: ''je schneller desto besser ;-)''. Konkret bietet eine SSD mit mind. 250MB/s Datenzugriff eine ordentliche Basis für jedes datengestützte System, wie den fhem.<br />
<br />
Wenn die Datenmenge größer und die Abfragen komplexer werden, müssen natürlich irgendwann auch die Prozessorleistung und der Arbeitsspeicher mit wachsen. Aber auch an einem Raspi wird eine SSD deutlich performanter sein, als eine einfache SD-Karte oder eine klassische rotierende Festplatte.<br />
<br />
<br />
== Links ==<br />
* [[Heizleistung_und_Gasverbrauch|Beispiel das DbLog-Daten für SVG-Plots verwendet]]<br />
* [[SVG-Plots von FileLog auf DbLog umstellen]]<br />
<br />
[[Kategorie:Logging]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=FHEM_Connector_f%C3%BCr_Amazon_Alexa&diff=32329FHEM Connector für Amazon Alexa2020-01-06T15:52:10Z<p>Amenomade: /* Geräte im FHEM-Webfrontend zuweisen */ Links</p>
<hr />
<div>{{Baustelle}}<br />
'''Alexa FHEMlazy''' war historisch ein Fork des Original [[Alexa-Fhem|alexa-fhem]], der im Januar 2019 mit dem Original zusammengeführt wurde und nun als '''FHEM Connector''' verfügbar ist.<br />
<br />
Er ermöglicht innerhalb von Minuten die Verknüpfung von FHEM mit einem Amazon Echo Gerät. Auch Geräte anderer Hersteller mit verbauten Mikrofonen und Alexa-Sprachassistenten-Unterstützung sollten problemlos funktionieren. Für folgende Geräte ist dies bspw. der Fall (Falls Ihr andere/weitere Gerätemodelle bzw. Hersteller in Verwendung habt, bitte hier pflegen):<br />
<br />
* SONOS Beam und SONOS One <br />
<br />
Gegenüber dem klassischen Ansatz ergeben sich Einschränkungen, so läuft die Software normalerweise unter dem gleichen Benutzer wie FHEM auf dem gleichen Server, und es wird z.Zt. nur der Smarthome-Skill unterstützt (die Variante, bei der die Möglichkeiten der Interaktion von Amazon festgelegt wurden).<br />
Dafür ist weder ein Developer-Account bei Amazon, eigene Lambda- und Skillfunktionen, noch das Öffnen eines eingehenden Ports aus dem Internet nötig. <br />
* Die Software integriert einen Installer, der die Erstkonfiguration und Anmeldung übernimmt<br />
* Die Kommunikation zur Software auf dem heimischen Rechner und dann zu FHEM verläuft über SSH und einen vom FHEM-Verein gehosteten Server<br />
* Funktioniert mit IPv4, IPv6, echtem Dual Stack und DS-Lite<br />
* Als Skill bei Amazon wird der Skill "FHEM Connector" verwendet.<br />
<br />
Der Thread im Forum zur Software ist hier: {{Link2Forum|Topic=94817}}.<br />
<br />
{{Infobox Modul<br />
|ModPurpose=Einfache Anbindung von FHEM an Amazon Assistent Alexa<br />
|ModType=h<br />
|ModCmdRef=alexa<br />
|ModTechName=39_alexa.pm / alexa-fhem<br />
|ModForumArea=Frontends/Sprachsteuerung<br />
|ModOwner=gvzdus, André/ justme1968 ({{Link2FU|430|Forum}} / [[Benutzer Diskussion:Justme|Wiki]])<br />
}} <br />
<br />
<br />
==Einführung==<br />
<br />
===Arbeitsweise und Datenfluss===<br />
Vorläufig ist alexa-fhem im "FHEM Connector-Modus" ein reiner [https://developer.amazon.com/de/docs/smarthome/understand-the-smart-home-skill-api.html SmartHome-Skill].<br />
SmartHome-Skills erhalten weder die Sprachdaten selber noch das, was Amazon in Textform verstanden hat, sondern vielmehr extrahiert Amazon aus dem verstandenen Text Anweisungen und Abfragen für Geräte, die dann an den Skill übermittelt werden. Charmant ist dabei, dass unmittelbar gefragt werden kann "Alexa, wie ist die Temperatur im Wohnzimmer?", während andere Skills zunächst explizit angesprochen werden müssen ("Alexa, frage FHEM nach der Temperatur im Wohnzimmer"). Außerdem kann der Nutzer mehrere Smarthome-Skills installieren, und die Geräte werden zu einer Gesamtmenge zusammengefasst.<br />
<br />
Gehen wir den Datenfluss bei der konkreten Frage "Wie ist die Temperatur im Wohnzimmer?" durch:<br />
* Alexa hat bei der Skillinstallation gelernt, dass "FHEM Connector" bei Dir einen Thermostaten im Raum Wohnzimmer kennt. Dadurch wird bei der Sprachanalyse von "Alexa Voice Service" in der Cloud erkannt, dass eine Abfrage an "FHEM Connector" erfolgversprechend ist.<br />
* Zunächst wird die zentrale "Lambda-Funktion" von "FHEM Connector" aufgerufen. Die Funktion leitet aber im Kern nur den Request unverändert an den vom Verein bereitgestellten Server weiter. Im Request enthalten ist ein Token, das sogenannte "Bearer-Token".<br />
* Der "Vereinsserver" prüft anhand dieses Tokens, ob es überhaupt bekannt ist, und zu welchem Nutzer es gehört. Ist dieser Nutzer verbunden, wird der Request wiederum quasi unverändert an den Nutzer weitergeleitet.<br />
* Diese Weiterleitung passiert über einen sogenannten SSH-Reverse-Tunnel, der von Deiner Seite und der Software auf dem FHEM-Tunnel automatisch aufgebaut wird.<br />
* Auf Deiner Seite läuft die eigentliche Software, und zwar unter nodeJS. nodeJS ist ein Javascript ausführender Miniserver, der lokal auf Port 3000 auf Requests "lauscht". In der Original-Version [[Alexa-Fhem|Alexa FHEM]] kommen die Requests aus dem Internet (hoffentlich von der eigenen Lambda-Funktion), hier bei "FHEM Connector" kommen sie ausschließlich aus dem SSH-Tunnel von lokal.<br />
* Die Software validiert nun diesen Request anhand des Bearer-Tokens. Konkret wird dabei das bei der Installation generierte Token, dass bei der Skill-Aktivierung an Amazon übertragen wurde, mit dem lokal gespeicherten Wert verglichen. Stimmt das Token, wird der Befehl verarbeitet, üblicherweise wird hierbei ein Aufruf an die Webschnittstelle von FHEM abgesetzt.<br />
* FHEM führt den Befehl aus<br />
<br />
Hört sich langsam und kompliziert an? Kompliziert: Okay. Langsam eher nicht, in etlichen Fällen liegt die Gesamtantwortszeit unter 200 ms.<br />
<br />
Soweit ein erster Überblick über die Datenflüsse. Im Abschnitt Sicherheit ist das Konzept der Absicherung deutlich genauer und ausführlicher beschrieben.<br />
<br />
==Installation==<br />
<br />
Du wirst bei der Installation zuerst auf der Kommandozeile auf Deinem Raspberry (o.ä.) unterwegs sein, anschließend im Webfrontend von FHEM, und zum Schluss auf der Alexa-Konsole im Web.<br />
<br />
===node.js installieren===<br />
<br />
Bei Jessy liegt NodeJS bereits in einer ausreichend aktuellen Version vor. Mit<br />
<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
sudo apt-get install nodejs npm<br />
</syntaxhighlight><br />
<br />
kannst Du es installieren. Mit <br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
node --version<br />
</syntaxhighlight><br />
<br />
erfährst Du die aktuelle Version - wenn hier etwas mit "8" vorneweg erscheint, ist alles gut.<br />
Ansonsten suche Dir bitte eine Anleitung im Web, wie Du NodeJS auf Deinem System auf einen aktuellen Stand bringen kannst.<br />
<br />
=== Alexa-FHEM installieren ===<br />
<br />
Nun installieren wir Alexa-fhem aus dem offiziellen Repository:<br />
<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
sudo npm install -g alexa-fhem<br />
</syntaxhighlight><br />
<br />
Der Vorgang benötigt etwas Zeit.<br />
<br />
=== Alexa-FHEM aktivieren ===<br />
<br />
Wechsele jetzt in FHEM-Web!<br />
<br />
Wichtig ist, dass das Alexa-Modul in der Version ab 14. Januar 2019 vorliegt. Dafür bitte einmal FHEM aktualisieren:<br />
Speichern der Config nicht vergessen, und<br />
<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
update<br />
shutdown restart<br />
</syntaxhighlight><br />
<br />
Alles, was jetzt noch nötig ist, ist das Anlegen eines Alexa-Devices. Gib dafür in der FHEM-Web-Kommandozeile<br />
<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
define alexa alexa<br />
</syntaxhighlight><br />
<br />
an. Nun läuft, während Du bereits das neu angelegte Alexa-Devices siehst, ein komplexer Prozess im Hintergrund:<br />
<br />
* Falls noch kein SSH-Key für den Benutzer, unter dem FHEM läuft, existiert, wird einer generiert<br />
* Es wird ein Secret-Key im Prozess generiert, dass den Server nicht verlässt, und der Skillanmeldung dient.<br />
* Du wirst auf dem Server "va-fhem.fhem.de" des FHEM-Vereins mit dem SSH-Key angemeldet, und der Hash-Wert Deines Secret-Key dort abgelegt.<br />
<br />
Und wenn Du diese Sätze gelesen hast, sollte inzwischen sich das Alexa-Device in FHEM-Web aktualisiert haben, und <br />
ungefähr so aussehen:<br />
<br />
[[Datei:Alexa-Device-2.png|800px]]<br />
<br />
Neben dem Status für alexa-fhem und der Proxyverbindung ist wichtig, dass diese beiden Zeilen beim Reload aufgetaucht sind:<br />
<br />
<syntaxhighlight lang="bash" style="width:90%;"><br />
alexaFHEM.bearerToken crypt:...<br />
alexaFHEM.skillRegKey crypt:...<br />
</syntaxhighlight><br />
<br />
Ja, und diesen Schlüssel benötigst Du wirklich! Also am besten schon einmal mit <br />
<br />
<syntaxhighlight lang="bash" style="width:90%;"><br />
get <alexa> proxyKey<br />
</syntaxhighlight><br />
<br />
in Klartext anzeigen lassen und in ein Editor-Fenster dauerhaft wegsichern.<br />
<br />
Jetzt solltest Du Dein Alexa-Device nicht mehr löschen, denn das im Reading angezeigte "bearerToken" zu löschen bedeutet, dass die Software die Zugriffe von nicht mehr überprüfen kann und keine Kommandos mehr funktionieren. In diesem Fall hilft nur die Neuinstallation des Skills.<br />
<br />
==== Fehler bei der Aktivierung ====<br />
<br />
Während kompliziertere Fehlerfälle im Abschnitt "Mögliche Probleme und Lösungen" behandelt werden, hier häufige Fälle, warum die kryptischen Zeilen nicht auftauchen:<br />
<br />
* Zuerst bitte einfach einmal die Seite neu laden.<br />
<br />
===== 401: Authorization Required =====<br />
<br />
Wenn Du FHEM-Web mit einem User/Passwort-Schutz versehen hast, wirst du folgende Fehlermeldung sehen: <br />
<br />
<syntaxhighlight lang="bash" style="width:90%;"><br />
alexaFHEM stopped; failed to connect to fhem: 401: Authorization Required<br />
</syntaxhighlight><br />
<br />
In der Regel musst du die Angaben User/Passwort noch einmal explizit setzen. Im Attribute-Abschnitt "alexaFHEM-auth" auswählen, User/Passwort mit ":" getrennt angeben und "attr" anklicken. alexa-fhem wird automatisch neu gestartet. Hier das Ganze in der Text-Variante:<br />
<br />
<syntaxhighlight lang="bash" style="width:90%;"><br />
attr alexa alexaFHEM-auth user:pass<br />
</syntaxhighlight><br />
<br />
===== Permission denied =====<br />
<br />
Wenn du folgende Fehlermeldungen im Alexa Logfile siehst, wurde das Verzeichnis "/opt/fhem/.ssh/" von dir bei der Arbeit mit "root" oder "sudo" mit den falschen Berechtigungen versehen:<br />
<br />
<syntaxhighlight lang="bash" style="width:90%;"><br />
[2019-7-25 11:59:12] sshautoconf: aborted with ssh-keygen returned error - key_save_private: Permission denied<br />
[2019-7-25 11:59:12] *** SSH: proxy configuration failed: ssh-keygen returned error - key_save_private: Permission denied<br />
</syntaxhighlight><br />
<br />
Prüfen kannst du die Berechtigungen mit folgendem Befehl auf der Shell-Konsole: <br />
<br />
<syntaxhighlight lang="bash" style="width:90%;"><br />
ls -l /opt/fhem/.ssh<br />
</syntaxhighlight><br />
<br />
Du solltest dann folgende Ausgabe erhalten:<br />
<br />
<syntaxhighlight lang="bash" style="width:90%;"><br />
insgesamt 12<br />
-rw------- 1 fhem dialout 1675 Jul 12 13:10 id_rsa<br />
-rw-r--r-- 1 fhem dialout 391 Jul 12 13:10 id_rsa.pub<br />
-rw-r--r-- 1 fhem dialout 884 Jul 12 13:10 known_hosts<br />
</syntaxhighlight><br />
<br />
Steht in der Ausgabe nicht "fhem dialout" (dein fhem User), sondern bspw. "root root", dann bspw. mit folgendem Befehl an deinen fhem User anpassen:<br />
<br />
<syntaxhighlight lang="bash" style="width:90%;"><br />
chown fhem:dialout /opt/fhem/.ssh<br />
</syntaxhighlight><br />
<br />
Mit dem ersten Befehl "ls -l ..." kannst du dann nochmal prüfen, ob die Berechtigungen korrekt übernommen wurden. <br />
<br />
===== weitere Prüfungen =====<br />
<br />
Hast Du noch die Shell-Konsole offen? Dann prüfe bitte noch einmal auf der Konsole, ob nun zwei Prozesse laufen:<br />
<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
ps -ef | egrep '(alexa|ssh)'<br />
</syntaxhighlight><br />
<br />
sollte Dir idealerweise so etwas anzeigen:<br />
<syntaxhighlight lang="bash" style="width:90%;"><br />
fhem 31322 1 99 13:56 ? 00:00:03 alexa <br />
fhem 31332 31322 8 13:56 ? 00:00:00 /usr/bin/ssh -R 1234:127.0.0.1:<zufälliger port> -oServerAliveInterval=90 -p 58824 fhem-va.fhem.de<br />
</syntaxhighlight><br />
<br />
"alexa" ist dabei der Node-JS-Prozess, der ssh-Prozess ist die aufgebaute Verbindung zum Vereinsserver.<br />
<br />
Wenn Du diese Prozesse '''nicht''' siehst oder das Alexa-Device keinen Registrierungskey anzeigt, dann ist leider der Start nicht glatt verlaufen.<br />
<br />
Im Logfile (über den link <code>Logfile</code> in der Detail-Ansicht über <code>set</Code>, oder über den Namen bei ''currentlogfile'' in den Internals) findest Du idealerweise selber Hinweise, wo es hakt, oder kannst im Forum nachfragen.<br />
<br />
=== Geräte im FHEM-Webfrontend zuweisen ===<br />
Um das Aha-Erlebnis zu vergrößern, ist jetzt ein guter Zeitpunkt, 1 oder besser mind. 2 Geräte für den Alexa-Dienst zuzuweisen. Von Haus aus wird keines Deiner FHEM-Geräte automatisch Alexa zugewiesen!<br />
<br />
Wähle die Geräte aus, rufe sie auf und setze das Attribut "alexaName". Hierbei in Kürze nur der Hinweis:<br />
* Keine Angst vor Leerzeichen und Umlauten, funktioniert.<br />
* Große Angst vor Rechtschreibfehlern (Terrasse, Rollladen) oder komplizierten Wörtern "handgebastelte Martinslaterne im Kinderzimmer Iphigenie-Chantal".<br />
* Das Attribut "alexaRoom" ist NUR FÜR DEN CUSTOM SKILL relevant. Ausnahme: structure und LightScene Devices, siehe: [[FHEM_Connector_f%C3%BCr_Amazon_Alexa#Was_geht_alles_.3F]].<br />
<br />
Lade die Geräte neu in die Software, indem Du <code>set <alexa> restart</code> ausführst!<br><br />
<br><br />
<br />
'''Anmerkungen (weil oft gestellte Fragen im Forum) bzgl. erkennung von Geräten:'''<br />
<br />
* Wichtig ist, dass die Filtereinstellung in der alexa-fhem.cfg (zu finden unter "Edit Files") passt.<br />
Also was dort eingetragen ist (Standard: alexaName=..* / also es ist ein alexaName vergeben) auch an den entsrpechenden Devices in fhem vorhanden ist.<br />
Stimmt das schon nicht überein, kann alexa-fhem schon mal keine Devices von fhem abfragen/finden.<br />
Ob der Filter entsprechend funktioniert kann man wie folgt testen: ''list Filtereinstellung'' beispiel mit Standardfilter: ''list alexaName=..*''<br />
<br />
* Hat alexa-fhem per Filter Devices aus fhem "gefunden", geht es weiter mit der "Erkennung". Also um welches Device (Typ und "Fähigkeiten") handelt es sich. Dazu gilt folgendes:<br />
** sind entsprechende Readings beim Device vorhanden (z.B. temperature, state mit on/off, ...) erkennt das alexa-fhem automatisch. Die Liste der automatisch erkannten Readings wächst ständig. Daher erst mal schauen ob das Device bereits entsprechend erkannt (typisiert) wurde. Das kann durch prüfen des alexa-fhem-Logs geschehen (NICHT fhem-log!).<br />
** sind entsprechende "set-Befehle" erkennbar (oft auch durch Readings). Also ist beispielsweise (wie beim Dummy nötig) ein ''setList'' mit entsprechenden Einträgen vorhanden oder entsprechende Readings, z.B. desired-temp zum Stellen der Temperatur etc.<br />
** wird das Device nicht richtig oder "unvollständig" erkannt helfen folgende Attribute:<br />
*** genericDeviceType: hiermit kann alexa-fhem in die gewünschte Richtung "geschubbst" werden. Anmerkung: man kann nicht alles erzwingen, Readings bzw. set-Befehle müssen passen (oder per homebridgeMapping passend gemacht werden). Wenn ein genericDeviceType nicht per "Drop-Down" erscheint, dann kann er auch (wenn bekannt) einfach per WEB-cmd eingegeben werden: ''attr Devicename genericDeviceType media''<br />
*** homebridgeMapping: hierdurch kann alexa-fhem bei der Erkennung von Zuständen und möglichen Einstellungen (also WAS kann das Device) unterstützt werden. Mittels homebridgeMapping können vorhandene Readings (Zustände) auf für alexa-fhem bekannte Zustände gemappt werden. Ebenso können damit Standard-fhem-Kommandos von alexa-fhem auf Device-spezifische gemappt werden. Beispiel: on/off auf Ein/Aus (falls das Device statt on/off eben ein Ein/Aus erwartet). Zum Beispiel: <syntaxhighlight lang="bash" style="width:50%;"><br />
attr <thermostat> homebridgeMapping TargetTemperature=target::target,minValue=18,maxValue=25,minStep=0.5 CurrentTemperature=myTemp:temperature<br />
</syntaxhighlight> [https://github.com/justme-1968/homebridge-fhem/blob/master/README.md weitere Beispiele]<br />
<br />
'''Anmerkung bzgl. genericDeviceType und homebridgeMapping:'''<br><br />
* diese Attribute werden von verschiedenen "Sprachsteuerungsmodulen" in fhem verwendet (homebridge [dort wurde es "erfunden"], alexa-fhem, gassistant, ...). Daher ist nicht jedes Mapping für alle "Dienste" verwendbar. Ausprobieren schadet aber nicht.<br />
* ebenso kann man mit diesen Attributen (homebridgeMapping wird gerne so "missbraucht") nichts erzwingen, was seitens Amazon/Alexa nicht unterstützt bzw. verstanden wird! D.h. zunächst ist zu prüfen, ob ein bestimmter (gewünschter) Sprachbefehl seitens Amazon/Alexa unterstützt wird! Aktuelles Beispiel (Stand Jan 2020): "Alexa, fahre den Rollo hoch/runter". Da ist Amazon/Alexa gerade dabei etwas zu tun. Bislang wird das nicht unterstützt, also ist das auch mit einem entsprechenden homebridgeMapping nicht zu erzwingen! Was unterstützt wird kann man bei Amazon nachlesen: [https://developer.amazon.com/es-ES/docs/alexa/device-apis/list-of-interfaces.html]<br />
<br />
== Finale: Skill verknüpfen ==<br />
Suche im WebFrontend oder der Alexa-App den Skill "FHEM Connector". Für nicht-Mac/iOS Anwerder empfiehlt das WebFrontend (https://alexa.amazon.de) statt die App, damit Du den Anmeldeschlüssel auch bequem kopieren kannst.<br />
<br />
Wenn du noch nicht bei Amazon angemeldet bist, erwartet Amazon zunächst, dass Du Dich normal bei Amazon anmeldest.<br />
<br />
Sobald Du "FHEM Connector" aktivierst, öffnet sich ein Browser-Tab mit folgender Maske:<br/><br />
[[Datei:FHEMlazy_login.png|240px]]<br />
<br />
Hier kopierst Du Deinen Anmeldeschlüssel (im Klartext!) hinein und klickst auf Check. Als glücklicher Mensch ist auf der folgenden Statusseite alles grün:<br/><br />
[[Datei:FHEMlazy_check.png|240px]]<br />
<br />
Im Einzelnen wird hier geprüft, ob Du per SSH verbunden bist (und auch Deine IP zur Sicherheit angezeigt), ob der Reverse-Tunnel steht, ob nodeJS erreichbar ist und wie viele Geräte Alexa gleich finden sollte (in meinem Fall 22).<br />
<br />
Sollte etwas nicht grün sein und Du eine Idee zum Fixen haben, kannst Du mit "Retry" neue Versuche auslösen.<br />
<br />
Ist alles okay, klicke rechts den Button "Activate Skill". Du springst damit wieder zurück zu Amazon, die Dir hoffentlich zur erfolgreichen Verknüpfung gratulieren.<br />
<br />
Amazon möchte nun unmittelbar die Gerätesuche starten, und unter SmartHome-Geräte sollten diese nun auftauchen.<br />
<br />
== Was geht alles ? ==<br />
<br />
* Geräte, die sich ein- und ausschalten lassen:<br />
** Automatisch: Müssen <code>set on</code> und <code>set off</code> Kommandos haben<br />
** dummys müssen <code>setList</code> mit on und off haben<br />
** Über <code>genericDeviceType</code> switch bzw. light kann bestimmt werden ob es in alexa als Schalter oder Licht behandelt wird.<br />
** Wenn die Set-Kommandos im FHEM Device anders benannt sind: hombridgeMapping On:cmdOn=<ein>,cmdOff=<aus> setzen<br />
** Kommandos:<br />
***Alexa, schalte <name> ein/aus<br />
***Alexa, Licht an/aus<br />
***Alexa, schalte <gruppe> ein/aus<br />
<br />
* Geräte, die eine Temperatur messen<br />
** Automatisch: Es muss ein Reading temperature geben<br />
** Über <code>genericDeviceType</code> thermometer<br />
** Sonst: hombridgeMapping CurrentTemperature:reading=<reading><br />
<br />
* Geräte, deren Helligkeit sich ändern lässt<br />
** Automatisch: wenn <code>dim</code> oder <code>pct</code> Kommandos erkannt werden<br />
** Über <code>genericDeviceType</code> light<br />
** Über homebridgeMapping: Wenn <code>helligkeit</code> das Reading für die aktuelle Helligkeit enthält und die Helligkeit mit <code>set <device> prozent xxx</code> gesetzt wird, sieht das homebridgeMapping wie folgt aus:<br />
*** homebridgeMapping Brightness=helligkeit::prozent,minValue=0,maxValue=<maximalwert><br />
<br />
**Kommandos:<br />
***Alexa, mache <name> heller/dunkler<br />
***Alexa, Licht heller/dunkler<br />
<br />
* Geräte, deren Farbe sich ändern lässt<br />
** ...<br />
<br />
* Geräte, deren Farbtemperatur sich ändern lässt<br />
** ...<br />
<br />
* Geräte, bei denen sich eine Lautstärke einstellen lässt<br />
** ...<br />
<br />
* Geräte, bei denen sich ein prozentualer Wert einstellen lässt<br />
** Automatisch: wenn <code>dim</code> oder <code>pct</code> Kommandos erkannt werden<br />
** ...<br />
<br />
* elektrische Türschlösser<br />
** <code>genericDeviceType</code>: lock<br />
** hombridgeMapping mit LockCurrentState und LockTargetState<br />
<br />
* Thermostate<br />
** Über <code>genericDeviceType</code> thermostate<br />
** ...<br />
<br />
<br />
* structure Devices aus FHEM (ab alexa-fhem version 0.5.7)<br />
** können mit <code>genericDeviceType</code> scene als Szene eingebunden werden<br />
** über <code>alexaRoom</code> kann der name um einen Ort ergänzt werden<br />
** Szenen aus einer structure lassen sich ein- und ausschalten<br />
** Wichtig:<br />
*** Ein Skill darf nur 12 Szenen automatisch erkennen und einbinden.<br />
<br />
<br />
* LightScene Devices aus FHEM (ab alexa-fhem version 0.5.8)<br />
** können mit <code>genericDeviceType</code> scene als Szenen eingebunden werden<br />
** über <code>alexaRoom</code> kann der name um einen Ort ergänzt werden<br />
** Szenen aus einer LightScene lassen sich nur einschalten<br />
** Wichtig:<br />
*** Ein Skill darf nur 12 Szenen automatisch erkennen und einbinden.<br />
<br />
<br />
* Geräte, deren Kanal sich umschalten lässt (ab alexa-fhem version 0.5.13)<br />
** Über <code>genericDeviceType</code> media<br />
** hombridgeMapping ChannelController:reading=<reading>,cmd=<cmd><br />
** Erlaubte Werte siehe hier: https://developer.amazon.com/de/docs/device-apis/alexa-channelcontroller.html#changechannel<br />
** ...<br />
<br />
* Geräte, deren Playback status sich schalten lässt (ab alexa-fhem version 0.5.13)<br />
** Über <code>genericDeviceType</code> media<br />
** hombridgeMapping PlaybackController:playback,values=Play;Pause;Stop;Previous;Next<br />
** Erlaubte Werte siehe hier: https://developer.amazon.com/de/docs/device-apis/alexa-playbackcontroller.html#discovery<br />
** ...<br />
<br />
* Geräte, deren Eingang sich umschalten lässt (ab alexa-fhem version 0.5.13)<br />
** Über <code>genericDeviceType</code> media<br />
** hombridgeMapping InputController:reading=<reading>,cmd=<cmd>,values=HDMI+1;HDMI+2;XBOX<br />
** Erlaubte Werte siehe hier: https://developer.amazon.com/de/docs/device-apis/alexa-property-schemas.html#input<br />
** ...<br />
<br />
<br />
* Kontaktsensoren (ab alexa-fhem version 0.5.15)<br />
** Über <code>genericDeviceType</code> contact<br />
** hombridgeMapping ContactSensorState:reading=<reading> oder CurrentDoorState:reading=<reading><br />
** Die Anzeige in der Alexa-App funktioniert sofort, die Abfrage per Sprache erst ab Version 0.5.27.<br />
<br />
<br />
* Geräte, deren Lautstärke sich ändern lässt (ab alexa-fhem version 0.5.24)<br />
** Über <code>genericDeviceType</code> speaker<br />
** Automatisch: es muss ein Reading <code>volume</code> und/oder <code>mute</code> geben<br />
** hombridgeMapping Volume:reading=<reading>,cmd=<cmd> Mute:reading=<reading>,cmd=<cmd><br />
** ...<br />
<br />
<br />
* Geräte, die sich ein- (und optional) ausschalten lassen als Szene (ab alexa-fhem version 0.5.26)<br />
** Über <code>genericDeviceType</code> scene<br />
** Automatisch: Müssen <code>set on</code> und <code>set off</code> Kommandos haben<br />
** hombridgeMapping On:reading=<reading>,cmdOn=<cmd>[,cmdOff=<cmd>]<br />
** Hinweis: Fehlende Kommandos lassen sich mit cmdalias erzeugen<br />
** Wichtig:<br />
*** Ein Skill darf nur 12 Szenen automatisch erkennen und einbinden.<br />
<br />
<br />
Es werden noch einige andere häufig verwendete Geräte (Homematic, hue,...) automatisch erkannt.<br />
<br />
to be continued ...<br />
<br />
In der [https://developer.amazon.com/docs/device-apis/list-of-interfaces.html List of Capability Interfaces] bei Amazon kann man sehen, welche Möglichkeiten das Smart Home Skill API aktuell in einzelnen Ländern bietet. Leider ohne die jeweiligen landessprachlichen Kommandos.<br />
<br />
== Mögliche Probleme und Lösungen ==<br />
<br />
Es kann vorkommen, dass Geräte zwar korrekt erkannt werden, aber das durch Alexa erkannte Kommando nicht richtig umgesetzt wird (Beispiel - mittlerweile behoben: {{Link2Forum|Topic=96766}}). Neben dem FHEM-Log gibt es noch das Logfile, welches von alexa-fhem angelegt wird. <br />
<br />
=== Fehlersuche über die FHEM-Oberfläche ===<br />
<br />
* alexa-fhem Logfile anschauen (Detail-Ansicht des <alexa>-Device aufrufen, klick auf '''Logfile''' oben)<br />
* alexa-fhem im Debug-Modus aufrufen:<br />
** -D zum alexaFHEM-params attribut hinzufügen<br />
** Alexa-Befehl auslösen<br />
** -D aus dem alexaFHEM-params attribut entfernen<br />
* Die notwendigen Informationen finden sich in dem alexa-Logfile (siehe oben)<br />
<br />
=== Fehlersuche über Kommandozeile (lies: Shell) + FHEM-Oberfläche ===<br />
<br />
:* set <alexa> stop (FHEM-Oberfläche)<br />
:* Auf der Kommandozeile <code>alexa-fhem -D -c /opt/fhem/alexa-fhem.cfg > debug.log</code> starten (dadurch wird die Datei debug.log erzeugt im aktuellen Verzeichnis)<br />
:* Alexa-Befehl auslösen<br />
:* alexa-fhem auf der Kommandozeile wieder stoppen (CTRL-C)<br />
:* set <alexa> start (FHEM-Oberfläche)<br />
<br />
Die Datei debug.log sollte Hinweise enthalten, wie das Problem zu lösen ist oder Dich zumindest in die richtige Richtung schieben.<br />
<br />
Im Beispiel aus dem Forum fand sich in dem Logfile der Hinweis darauf, dass das Device mit falschen min/max-Werten unterwegs war.<br />
<br />
=== Registrierungskey vergessen, Registrierung zurücksetzen ===<br />
<br />
Auf der Kommandoshell:<br />
<br />
<syntaxhighlight lang="bash" style="width:90%;"><br />
pi@raspberrypi:~# sudo -u fhem ssh -p 58824 fhem-va.fhem.de status<br />
Registered.<br />
Registered on 2019-01-13T15:38:13Z.<br />
</syntaxhighlight><br />
<br />
heisst, das der Vereinsserver eigentlich alles hat, was er will. Es wird kein neuer Schlüssel generiert.<br />
Wenn Du die Situation zurücksetzen möchtest, wäre die hässliche Methode, Deinen SSH-Key zu löschen. Eleganter ist, die Registrierung auf Vereinsseite zu löschen:<br />
<br />
<syntaxhighlight lang="bash" style="width:90%;"><br />
pi@raspberrypi:~# sudo -u fhem ssh -p 58824 fhem-va.fhem.de unregister<br />
Your registration has been removed<br />
</syntaxhighlight><br />
<br />
löscht Deinen Schlüssel mitsamt allen dort gespeicherten Daten auf Vereinsseite. Bei Restart von alexa-fhem in FHEM-WEB wird jetzt ein neuer Registrierungskey angefordert.<br />
<br />
== Sicherheitskonzept und Secrets ==<br />
<br />
Um diesen Abschnitt zu verstehen, solltest Du den Abschnitt "Arbeitsweise" im Kopf haben. Einerseits ist Dir vermutlich einleuchtend, dass ein Server, der per SSH rückwärts nur ausgewählte Kommandos in den Tunnel, den Du aufgebaut hast, leitet, "irgendwie sicherer" ist. Andererseits möchte man nicht blind vertrauen.<br />
<br />
=== SSH ===<br />
==== SSH - macht das nichts Gefährliches? ====<br />
SSH ist ein Veteran des Internet und entstand, um sich sicher (verschlüsselt) und schnell auf Servern einzuloggen. Schon früh wurde dabei der sogenannte "Reverse-Tunnel" implementiert: Also der vom Client (Deinem Rechner) geäußerte Wunsch: "Bitte leite mir Requests, die bei Dir, Server, auf Port xy eingehen, an meinen lokalen Port yz weiter.". Dieses Verfahren implementiert der Reverseproxy, wobei tatsächlich auf dem Server für Dich kein echter Port geöffnet wird.<br />
<br />
Wie Dir ggf. sicher der Unix-Guru Deines Vertrauens bestätigen wird: Die Kombination<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
ssh -R 1234:localhost:<zufälliger port> zielserver <br />
</syntaxhighlight><br />
erlaubt keine Ausführung von Shell-Kommandos auf Deinem Server, sondern einzig, dass vom SSH-Programm Verbindungen zu einem lokalen Port auf Deinem Server auf dem alexa-fhem lauscht aufgebaut werden. Du kannst also z.B. mit einem<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
sudo /usr/sbin/tcpdump -X -s 0 -i lo port <zufälliger port><br />
</syntaxhighlight><br />
vollständig überwachen (oder ggf. permanent aufzeichen), was auf Deinem Server von außen gesteuert passiert.<br />
<br />
==== Wie wird bei SSH verschlüsselt? ====<br />
Im Prinzip wie im Web auf SSL-Seiten, teils mit den gleichen Verschlüsselungsverfahren. Allerdings arbeitet SSH eher wie das im Web recht seltene Verfahren: Bei jeder Verbindung übermitteln sowohl Server wie auch Client den öffentlichen Teil ihres Schlüssels. Anders als im Web wird der Schlüssel aber nicht von einer öffentlichen Zertifizierungsstelle wie "LetsEncrypt" unterschrieben. Stattdessen entscheiden Server wie Client beim ersten Verbindungsaufbau typischerweise per manueller Frage: "Willst Du jetzt und künftig diesem Schlüssel vertrauen?" Bei der Installation wird diese Frage für Deine Seite bejaht, und fortan wird der öffentliche Schlüssel des FHEM-Servers auf Deinem Rechner gespeichert. Ab da bist Du z.B. davor sicher, dass jemand den DNS-Eintrag verbiegt oder sich in den Datenfluss Deines Providers einhängt: Ein geänderter Serverschlüssel würde bemerkt werden.<br />
<br /><br />
Soweit klar? Aus Deinem öffentlichen Schlüssel wiederum leitet der Server her: "Das ist definitiv wieder derjenige, der sich damals "registriert" hat". Und an dieser Stelle kann ich auch den <b>ersten Teil des 3-teiligen Registrierungskeys</b> erläutern: Die typischerweise 6-stellige Hex-Zahl am Anfang ist der Java-Hashcode Deines öffentlichen Schlüssel. Sie ist damit sozusagen Deine aus Deinem öffentlichen Schlüssel abgeleitete Benutzer-ID.<br />
<br />
=== Die Rolle der Secrets ===<br />
Wenn jetzt klar ist, dass die Verbindung zum Vereinsserver sicher und vertauschungsfrei funktioniert, bleiben noch 2 Probleme zu lösen:<br />
1) Im Web bei der Skill-Aktivierung musst Du beweisen, dass Du der Mensch am Browser bist, dem der SSH-Tunnel von IP xy mit dem öffentlichen Schlüssel X gehört. Bei der automatischen Registrierung werden lokal auf Deinem Rechner zwei 64-Bit-Secrets generiert:<br />
* Das <b>Anmelde</b>-Secret<br />
* Das <b>Bearer</b>-Token<br />
Beim Anmelden des SSH-Keys auf dem öffentlichen Server wird nun der <b>Hashwert</b> des ersten Secrets übertragen und dort in Verbindung mit Deinem öffentlichen Schlüssel gespeichert. Ein Hashwert bedeutet, dass (sofern das Verfahren, hier SHA256, funktioniert), niemand aus dem Hash das Secret zurückrechnen kann. Ein Datenbankklau auf dem Server gefährdet also nicht die Sicherheit Deines Passwortes.<br />
<br />
Wenn Du nun beim Skill-Aktivieren den Registrierungskey eingibst, dann "sieht" der Server zum ersten Mal Dein ausgewürfeltes Secret, vergleicht es mit dem Hashwert und wird es anschließend wieder umgehend vergessen. Anhand des Hashwertes kann der Server aber entscheiden, dass Du der legitime Nutzer zum öffentlichen Schlüssel XY bist.<br />
<br />
2) Das zweite Problem ist: Wie soll Amazon "beweisen", dass sie der legitime Aufrufer sind? Amazon erhält binnen wenigen Sekunden nach dem Klick auf "Activate Skill" den <b>dritten Teil</b> des Registrierungskeys als sogenanntes Bearer-Token. Zwar läuft er durch den Registrierungsserver, er wird dort, auf dem Registrierungs/Vereinsserver aber nicht gespeichert. Das Bearer-Token wird von Amazon bei allen Requests zu Deinem Server mitgesendet. Da es am Anfang zusätzlich Deine "User-ID" enthält, weiß der Vereinsserver, zu welchem SSH-Tunnel der Request zu senden ist. Aber lokal auf Deinem Rechner wird ausgewertet, ob das Token "stimmt".<br />
<br />
== alexa-fhem Updaten ==<br />
* alexa-fhem über FHEM anhalten:<br />
:<syntaxhighlight lang="perl" style="width:50%;">set alexa stop</syntaxhighlight><br />
<br />
*Auf der Konsole wie anfangs bei der Installation:<br />
:<syntaxhighlight lang="bash" style="width:50%;">sudo npm update -g alexa-fhem</syntaxhighlight><br />
<br />
:Manchmal hat npm Probleme mit einem Update. Dann einfach die aktuelle Version noch mal drüber Installieren: <br />
<br />
:<syntaxhighlight lang="bash" style="width:50%;">sudo npm install -g alexa-fhem</syntaxhighlight><br />
<br />
*alexa-fhem über FHEM wieder starten:<br />
:<syntaxhighlight lang="perl" style="width:50%;">set alexa start</syntaxhighlight><br />
<br />
== Bug- und Wunschliste ==<br />
* Ist beim Start keine Internetverbindung vorhanden, erfolgt kein Retry -- alexa-fhem muss restartet werden (ssh_autoconfig wertet keine temporären Fehler aus)<br />
<br />
==Weitergehende Informationen==<br />
*[[Alexa und Mappings]]<br />
*[[Alexa Tipps und Kniffe]]<br />
*[[FHEM Connector for Amazon Alexa]]<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Sprachsteuerung]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=Plot-Abriss_vermeiden&diff=32030Plot-Abriss vermeiden2019-12-19T21:27:14Z<p>Amenomade: AddLog Attribut</p>
<hr />
<div>{{Randnotiz|RNTyp=r|RNText='''HINWEIS''': Es gibt mittlerweile das Attribut addLog für FileLog Devices. <br />
This attribute takes a comma-separated list of devspec:reading:maxInterval triples. You may use regular expressions for reading. The last value of the reading will be written to the logfile, if after maxInterval seconds no event for this device/reading has arrived. Siehe {{Link2Forum|Topic=106489}}}}<br />
<br />
== Motivation ==<br />
Bei Nutzung des Attributs <code>event-on-change</code> werden Log-Einträge nur bei Werteänderung geschrieben. Dies führt<br />
# zum Abriss der Logs zum Ende des alten und zum Beginn des neuen Tages<br />
# zu inadäquat langen Pausen zwischen Logeinträgen, z.B. für <code>actuator</code>, der z.B. in den Wintermonaten bei Anwesenheit durchgängig 100%, bei Abwesenheit durchgängig 0% betragen kann. Der Wechsel zwischen diesen Werten wird mit langen Flanken dargestellt.<br />
<br />
== Funktionsweise ==<br />
Aus diesem Grund wurde die Routine <code>addLog</code> erstellt (siehe [[#Implementierung|Implementierung]]).<br />
Sie fügt zu definierten Zeitpunkten Einträge im Log hinzu.<br />
Dadurch sollen die o.g. Effekte vermieden werden.<br />
Zusätzliche Einträge sind mit dem Anhang <code><< addLog</code> gekennzeichnet.<br />
Der Aufruf erfolgt sinnvollerweise aus einem <code>at</code> oder einem <code>DOIF</code>.<br />
Üblich ist der Aufruf für alle Geräte bzw. readings, für die <code>event-on-change</code> gesetzt ist.<br />
<br />
Die Routine hat zwei Aufrufparameter:<br />
<syntaxhighlight lang=text><br />
addLog(<devicename>, <reading>)<br />
</syntaxhighlight><br />
<br />
== Beispiele aus fhem.cfg ==<br />
<syntaxhighlight lang=text><br />
### jede Stunde einen Eintrag für FHT actuator<br />
define a_actuator at +*01:00 {addLog("ez_FHT","actuator")}<br />
attr a_actuator room 99_System<br />
</syntaxhighlight><br />
<br />
<code>addLog</code> für mehrere <code>devices</code> in einem "Makro" zusammenfassen:<br />
<syntaxhighlight lang=text><br />
define addLog notify addLog {addLog("ez_Aussensensor","state");;\<br />
addLog("ez_FHT","actuator");;\<br />
addLog("ez_FHT","measured-temp");;\<br />
addLog("MunichWeather","humidity");;\<br />
addLog("MunichWeather","pressure");;\<br />
addLog("MunichWeather","temperature");;\<br />
addLog("MunichWeather","wind_chill");;}<br />
attr addLog room 99_System<br />
</syntaxhighlight><br />
<br />
<syntaxhighlight lang=text><br />
### Hier ist ein trigger des o.g. notify verwendet, um nicht in beiden at-defines alle Aufrufe listen zu müssen.<br />
define a_midnight1 at *23:59 trigger addLog<br />
attr a_midnight1 room 99_System<br />
define a_midnight2 at *00:01 trigger addLog<br />
attr a_midnight2 room 99_System<br />
# Alternativ können auch die Einzelaufrufe direkt im at erfolgen, z.B.<br />
define a_midnight_before at *23:59 {addLog("device","reading")}<br />
</syntaxhighlight><br />
<br />
==Beispiele mit DOIF ==<br />
Seitdem es [[DOIF]] gibt, lässt sich das Ganze auch etwas anders umsetzen:<br />
<br />
<syntaxhighlight lang=text><br />
define DF_addLogDaily DOIF ([23:59] or [00:01]) ({addLog("ez_FHT", "actuator")})<br />
attr DF_addLogDaily room 99_System<br />
attr DF_addLogDaily do always<br />
</syntaxhighlight><br />
Da mit diesem Aufruf aber die Problematik nur nach unten verschoben wird (Zoom auf Stunde oder Vierteltag),<br />
ist folgendes möglich:<br />
<syntaxhighlight lang=text><br />
define DF_addLogHourly DOIF ([:59] or [:01]) ({addLog("ez_FHT", "actuator")})<br />
attr DF_addLogHourly room 99_System<br />
attr DF_addLogHourly do always<br />
</syntaxhighlight><br />
Das Ganze lässt sich auch noch auf minütlich runterbrechen, erzeugt dadurch ggf. eine große Menge Logeinträge. Dies sollte man stets bedenken.<br />
<br />
== Log-Beispiele ==<br />
<syntaxhighlight lang=text><br />
2012-11-04_23:46:28 ez_Aussensensor T: 9.4 H: 78.5<br />
2012-11-04_23:59:00 ez_Aussensensor T: 9.4 H: 78.5 << addLog<br />
2012-11-04_23:59:00 ez_FHT actuator: 0% << addLog<br />
2012-11-04_23:59:00 ez_FHT measured-temp: 17.4 << addLog<br />
2012-11-05_00:01:00 ez_Aussensensor T: 9.4 H: 78.5 << addLog<br />
2012-11-05_00:01:00 ez_FHT actuator: 0% << addLog<br />
2012-11-05_00:01:00 ez_FHT measured-temp: 17.4 << addLog<br />
2012-11-05_00:24:31 ez_FHT actuator: 0% << addLog<br />
2012-11-05_00:42:32 ez_Aussensensor T: 9.1 H: 78.1<br />
2012-11-05_16:02:59 ez_Aussensensor T: 10.3 H: 65.9<br />
2012-11-05_16:05:56 ez_Aussensensor T: 10.2 H: 66.3<br />
2012-11-05_16:21:47 ez_Aussensensor T: 10.2 H: 66.3 << addLog<br />
2012-11-05_16:21:48 ez_FHT actuator: 100% << addLog<br />
2012-11-05_16:21:48 ez_FHT measured-temp: 18.5 << addLog<br />
2012-11-05_16:30:26 ez_FHT measured-temp: 18.7<br />
2012-11-05_16:44:18 ez_Aussensensor T: 9.9 H: 65.8<br />
</syntaxhighlight><br />
<br />
== Nebeneffekte ==<br />
<code>addLog</code> verwendet die Funktion <code>trigger</code>.<br />
Für fhem ist das gleichwertig mit dem Eintreffen eines Ereignisses.<br />
Es werden also ggf. alle <code>notifies</code> ausgeführt, die für das relevante Gerät abzuarbeiten sind.<br />
Dies ist wohl zu bedenken, bevor man <code>addLog</code> verwendet.<br />
<br />
== Bekannte Probleme ==<br />
Das Modul [[dewpoint]] fügt dem <code>state</code> eines <code>device</code> den zusatz <code>D: xx</code> hinzu.<br />
Abhängig vom Timing kann dies zu "verwurschtelten" Darstellungen führen.<br />
Die Verwendung von <code>addLog</code> in Verbindung mit <code>dewpoint</code> ist daher nicht empfohlen.<br />
<br />
== Implementierung ==<br />
Die Routine wird in eine lokale Programmdatei integriert, z.B. <code>99_myUtils.pm</code> (siehe [[99 myUtils anlegen]]).<br />
Wird die Funktion dort mit einem externen Editor eingefügt, muss anschließend <code>reload 99_myUtils.pm</code> ausgeführt werden.<br />
Auf Fehlermeldungen im fhem.log achten. <br />
<syntaxhighlight lang=perl><br />
#### Log-abriss vermeiden<br />
# called by<br />
# define addLog notify addLog {addLog("ez_Aussensensor","state");;\<br />
# addLog("ez_FHT","actuator");;\<br />
# addLog("MunichWeather","humidity");;\<br />
# addLog("MunichWeather","pressure");;\<br />
# addLog("MunichWeather","temperature");;\<br />
# addLog("MunichWeather","wind_chill");;}<br />
# define a_midnight1 at *23:59 trigger addLog<br />
# define a_midnight2 at *00:01 trigger addLog<br />
sub<br />
addLog($$) {<br />
my ($logdevice, $reading) = @_; # device and reading to be used<br />
my $logentry = ReadingsVal($logdevice,$reading,"addLog: invalid reading");<br />
if ($reading =~ m,state,i) {<br />
fhem "trigger $logdevice $logentry << addLog";<br />
} else {<br />
fhem "trigger $logdevice $reading: $logentry << addLog";<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
Zu Problemen mit diesem Code, der auch die Sonderbehandlung des speziellen FHEM-Readings <code>state</code> sicherstellen soll, in Verbindung mit anderen Readingnamen, die den Bestandteil "state" in beliebiger Groß-/Kleinschreibung und an beliebiger Position beinhalten siehe {{Link2Forum|Topic=92111}} mit Lösungsansätzen.<br />
== Alternativen ==<br />
Um Plot-Abrisse zu vermeiden, kann man auch [[LogProxy]] verwenden (sofern erforderlich iVm. dem ''createGluedFile''-Attribut des FileLog-Devices).<br />
[[Kategorie:Code Snippets]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=FRITZBOX&diff=31672FRITZBOX2019-11-10T12:21:00Z<p>Amenomade: /* userReadings per get tr064Command oder get luaQuery */</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Steuerung einer Fritz!Box über FHEM <br />
|ModType=d<br />
|ModForumArea=FRITZ!Box<br />
|ModTechName=72_FRITZBOX.pm<br />
|ModOwner=tupol/Topos ({{Link2FU|5432|Forum}} / [[Benutzer Diskussion:Topos|Wiki]])}}<br />
<br />
Das Modul [[FRITZBOX]] ermöglicht die Steuerung einer [[AVM Fritz!Box]] und von AVM FRITZ!WLAN Repeatern durch FHEM . An Fritzboxen können sowohl Geräte abgefragt werden, auf denen FHEM selbst läuft (lokaler Modus), als auch entfernte (externe) Geräte.<br />
<br />
== Voraussetzungen ==<br />
=== Remote-Zugang ===<br />
Für den Remote-Zugang müssen die Module JSON:XS, LWP und SOAP::Lite installiert sein; auf einem [[Raspberry Pi]] oder unter Ubuntu z.&nbsp;B. mit dem Befehl<br />
:<code>sudo apt-get install libjson-perl libwww-perl libsoap-lite-perl libjson-xs-perl</code><br />
<br />
Teilweise ist derzeit zusätzlich die Installation der telnet Libraries erforderlich, auch wenn der Telnet-Zugang nicht genutzt werden soll. Siehe dazu den nachfolgenden Abschnitt.<br />
<br />
=== Telnet ===<br />
Das Modul basierte ursprünglich auf dem Zugriff auf die Fritzbox per Telnet. Ab FRITZ!OS 6.2x baut AVM den abgekündigten Telnet-Zugang sowie die webcm-Schnittstelle sukzessive zurück bzw. hat dies, je nach Firmware, schon ganz abgestellt (siehe {{Link2Forum|Topic=38586|LinkText=dieses Forenthema}}). Der zukunftssichere Zugriff auf die Fritzbox sollte also per TR-064 erfolgen. Der Vollständigkeit halber und für ältere Firmwareversionen: <br />
<br />
# Wer den Zugang per Telnet (noch) nutzen (kann und) möchte, muss dies zuerst freischalten. Üblicherweise durch Eingabe von #96*7* an einem direkt an der entsprechenden FritzBox angeschlosssenen Telefon<br />
# Auf dem System, auf dem FHEM läuft ([[Systemübersicht#Server|Server]]) muss Telnet installiert sein; auf einem [[Raspberry Pi]] und unter Ubuntu z.&nbsp;B. mit dem Befehl<br />
::<code>sudo apt-get install libnet-telnet-perl</code><br />
<br />
== Installation ==<br />
=== Erste Schritte ===<br />
Zur Erstinstallation reicht ein einfaches <code>define FritzBox FRITZBOX</code>, dieses Modul funktioniert lokal (FHEM auf Fritzbox) sowie per Fernzugriff (FHEM auf einem anderen Server im Netz, siehe nächsten Schritt).<br />
<br />
==== TR-064: Modul FRITZBOX für Zugriff auf einem externen Server einrichten ====<br />
Für den Fernzugriff über TR-064 auf eine oder mehrere Fritzboxen und/oder einen FRITZ!WLAN Repeater sind die folgenden Schritte nötig (für jedes Gerät):<br />
<br />
Fritzbox definieren:<br />
:<code>define FritzBox FRITZBOX</code><br />
<br />
Wenn die Fritzbox nicht unter <nowiki>http://fritz.box</nowiki> erreichbar ist, IP im define setzen:<br />
:<code>define FritzBox FRITZBOX 192.168.168.168</code><br />
192.168.168.168 dabei natürlich durch die passende IP ersetzen... Alternativ kann statt der IP auch der Hostname eingegeben werden.<br />
<br />
Wenn ('''und nur wenn''') das Login auf der Benutzeroberfläche der FritzBox mit User und Passwort (und nicht nur per Passwort) geschieht, den User konfigurieren:<br />
:<code>attr FritzBox boxUser ''Benutzername'' </code><br />
In der Fritzbox muss dann auch "Anmeldung mit FRITZ!Box-Benutzernamen und Kennwort" ausgewählt sein.<br />
<br />
Passwort konfigurieren:<br />
:<code>set FritzBox password ''Passwort''</code> - legt das zugehörige Passwort fest (nur einmal --> gehört nicht in die cfg-Datei) <br />
<br />
Manuelle TR-064 Kommandos erlauben (Das Auslesen der Readings per TR-064 funktioniert auch ohne dieses Attribut.):<br />
:<code>attr FritzBox allowTR064Command 1</code><br />
<br />
==== Telnet: Modul FRITZBOX für Zugriff auf einem externen Server einrichten ====<br />
[[Datei:Screenshot_FritzBox_TelnetUser.png|mini|300px|rechts|Anlegen des Attributs telnetUser]]<br />
Bei Fernzugriff über Telnet sind weitere Schritte nötig:<br />
# Telnet auf der Fritzbox freischalten (Tastenkombination #96*7* am angeschlossenen Telefon (auch FritzFon)<br />
# TelnetUser definieren (wie im Screenshot gezeigt)<br />
# Passwort zum Benutzer auf der Fritzbox definieren<br />
<br />
[[Datei:Screenshot_FritzBox_Passwort.png|mini|300px|rechts|Passwort definieren]]<br />
<br />
(bitte die Buttons {{Taste|set}} und {{Taste|attr}} bei der Definition der jeweiligen Einträge nicht vergessen)<br />
<br />
Wer stattdessen lieber das [[Konfiguration|Befehl-Eingabefeld]] verwendet:<br />
<br />
:<code>define FritzBox FRITZBOX</code><br />
:<code>attr FritzBox telnetUser ''Benutzername'' </code> - legt den Benutzer fest<br />
:<code>set FritzBox password ''Passwort'' </code> - legt das zugehörige Passwort fest<br />
<br />
Wer keinen User konfiguriert hat, kann das Feld "telnetUser" leer lassen.<br />
<br />
Wer sicher gehen möchte, dass auch tatsächlich Telnet und nicht andere Zugriffe benutzt werden, sollte außerdem noch setzen:<br />
<br />
:<code>attr FritzBox forceTelnetConnection 1</code><br />
<br />
=== mögliche Fehlermeldungen ===<br />
Sollte schon bei <code>define FritzBox FRITZBOX</code> die Fehlermeldung kommen, dass dieses Modul nicht existiert, dann bitte prüfen, ob FHEM auf dem aktuellen Stand ist und ggf. [[Update|aktualisieren]].<br />
<br />
Kommt jetzt bei der erneuten Definition die Fehlermeldung <code>Error: Perl modul Net::Telnet is missing on this system</code> bitte wie oben schon erwähnt den Befehl <br />
:<code>sudo apt-get install libnet-telnet-perl</code> <br />
direkt per Telnet/SSH auf dem FHEM-Server ausführen und neu starten.<br />
Sollte alles geklappt haben, seht ihr nun eure Fritzbox und könnt diverse Einstellungen manuell vornehmen und/oder automatisch vornehmen lassen.<br />
<br />
== Anwendung ==<br />
=== Define ===<br />
Siehe {{Link2CmdRef|Lang=de|Anker=FRITZBOXdefine}}<br />
<br />
=== Attribute ===<br />
Siehe {{Link2CmdRef|Lang=de|Anker=FRITZBOXattr}}<br />
<br />
=== TR-064 ===<br />
Die offizielle Programmier-Schnittstelle der Fritz!Box läuft über das Protokoll TR-064.<br />
<br />
mit dem Attribute<br/><br />
<code>attr <device> allowTR064Command 1</code><br/><br />
kann man den Befehl<br/><br />
<code>get <device> tr064Command <service> <control> <action> [[parameterName1 parameterValue1] ...]</code><br/><br />
freischalten und damit auf diese Schnittstelle zugreifen.<br />
<br />
AVM hat die Schnittstellenbeschreibung unter [http://avm.de/service/schnittstellen/] veröffentlicht. Diese wird jedoch nur sehr sporadisch gepflegt.<br><br />
Ein besserer Einstiegspunkt befindet sich auf der Box unter http://fritz.box:49000/tr64desc.xml.<br><br />
Die möglichen TR-064-Aktionen kann man auch über den Befehl <code>get <device> tr064ServiceList</code> auslesen.<br />
<br />
Folgende Service und Controls existieren (für den get-Befehl ''tr064Command'' werden nur die fett formatierten Wörter benötigt)<br />
<br />
{| class="wikitable"<br />
|-<br />
!serviceType!!controlURL!!XML!!Dokument bei AVM<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''DeviceInfo:1'''||/upnp/control/'''deviceinfo'''||[http://fritz.box:49000/deviceinfoSCPD.xml deviceinfoSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/deviceinfoSCPD.pdf deviceinfoSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''DeviceConfig:1'''||/upnp/control/'''deviceconfig'''||[http://fritz.box:49000/deviceconfigSCPD.xml deviceconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/deviceconfigSCPD.pdf deviceconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''Layer3Forwarding:1'''||/upnp/control/'''layer3forwarding'''||[http://fritz.box:49000//layer3forwardingSCPD.xml layer3forwardingSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/layer3forwardingSCPD.pdf layer3forwardingSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''LANConfigSecurity:1'''||/upnp/control/'''lanconfigsecurity'''||[http://fritz.box:49000//lanconfigsecuritySCPD.xml lanconfigsecuritySCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/lanconfigsecuritySCPD.pdf lanconfigsecuritySCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''ManagementServer:1'''||/upnp/control/'''mgmsrv'''||[http://fritz.box:49000//mgmsrvSCPD.xml mgmsrvSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/mgmsrvSCPD.pdf mgmsrvSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''Time:1'''||/upnp/control/'''time'''||[http://fritz.box:49000//timeSCPD.xml timeSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/timeSCPD.pdf timeSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''UserInterface:1'''||/upnp/control/'''userif'''||[http://fritz.box:49000//userifSCPD.xml userifSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/userifSCPD.pdf userifSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_VoIP:1'''||/upnp/control/'''x_voip'''||[http://fritz.box:49000//x_voipSCPD.xml x_voipSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_voipSCPD.pdf x_voipSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_Storage:1'''||/upnp/control/'''x_storage'''||[http://fritz.box:49000//x_storageSCPD.xml x_storageSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_storageSCPD.pdf x_storageSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_OnTel:1'''||/upnp/control/'''x_contact'''||[http://fritz.box:49000//x_contactSCPD.xml x_contactSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_contactSCPD.pdf x_contactSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_WebDAVClient:1'''||/upnp/control/'''x_webdav'''||[http://fritz.box:49000//x_webdavSCPD.xml x_webdavSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_webdavSCPD.pdf x_webdavSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_UPnP:1'''||/upnp/control/'''x_upnp'''||[http://fritz.box:49000//x_upnpSCPD.xml x_upnpSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_upnp.pdf x_upnp.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_RemoteAccess:1'''||/upnp/control/'''x_remote'''||[http://fritz.box:49000/x_remoteSCPD.xml x_remoteSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_remoteSCPD.pdf x_remoteSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_MyFritz:1'''||/upnp/control/'''x_myfritz'''||[http://fritz.box:49000/x_myfritzSCPD.xml x_myfritzSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_myfritzSCPD.pdf x_myfritzSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_TAM:1'''||/upnp/control/'''x_tam'''||[http://fritz.box:49000/x_tamSCPD.xml x_tamSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_tam.pdf x_tam.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_AppSetup:1'''||/upnp/control/'''x_appsetup'''||[http://fritz.box:49000/x_homeautoSCPD.xml x_homeautoSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_appsetupSCPD.pdf x_appsetupSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_Homeauto:1'''||/upnp/control/'''x_homeauto'''||[http://fritz.box:49000/x_homeautoSCPD.xml x_homeautoSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_homeautoSCPD.pdf x_homeautoSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WLANConfiguration:1'''||/upnp/control/'''wlanconfig1'''||[http://fritz.box:49000/wlanconfigSCPD.xml wlanconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wlanconfigSCPD.pdf wlanconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WLANConfiguration:2'''||/upnp/control/'''wlanconfig2'''||[http://fritz.box:49000/wlanconfigSCPD.xml wlanconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wlanconfigSCPD.pdf wlanconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WLANConfiguration:3'''||/upnp/control/'''wlanconfig3'''||[http://fritz.box:49000/wlanconfigSCPD.xml wlanconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wlanconfigSCPD.pdf wlanconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''Hosts:1'''||/upnp/control/'''hosts'''||[http://fritz.box:49000/hostsSCPD.xml hostsSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/hostsSCPD.pdf hostsSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''LANEthernetInterfaceConfig:1'''||/upnp/control/'''lanethernetifcfg'''||[http://fritz.box:49000/lanifconfigSCPD.xml lanifconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/lanifconfigSCPD.pdf lanifconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''LANHostConfigManagement:1'''||/upnp/control/'''lanhostconfigmgm'''||[http://fritz.box:49000/lanhostconfigmgmSCPD.xml lanhostconfigmgmSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/lanhostconfigmgmSCPD.pdf lanhostconfigmgmSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANCommonInterfaceConfig:1'''||/upnp/control/'''wancommonifconfig1'''||[http://fritz.box:49000/wancommonifconfigSCPD.xml wancommonifconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wancommonifconfigSCPD.pdf wancommonifconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANDSLInterfaceConfig:1'''||/upnp/control/'''wandslifconfig1'''||[http://fritz.box:49000/wandslifconfigSCPD.xml wandslifconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wandslifconfigSCPD.pdf wandslifconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANDSLLinkConfig:1'''||/upnp/control/'''wandsllinkconfig1'''||[http://fritz.box:49000/wandsllinkconfigSCPD.xml wandsllinkconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wandsllinkconfigSCPD.pdf wandsllinkconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANEthernetLinkConfig:1'''||/upnp/control/'''wanethlinkconfig1'''||[http://fritz.box:49000/wanethlinkconfigSCPD.xml wanethlinkconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wanethlinkconfigSCPD.pdf wanethlinkconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANPPPConnection:1'''||/upnp/control/'''wanpppconn1'''||[http://fritz.box:49000/wanpppconnSCPD.xml wanpppconnSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wanpppconnSCPD.pdf wanpppconnSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANIPConnection:1'''||/upnp/control/'''wanipconnection1'''||[http://fritz.box:49000/wanipconnSCPD.xml wanipconnSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wanipconnSCPD.pdf wanipconnSCPD.pdf]<br />
|-<br />
|}<br />
<br />
=== Status-Symbol ===<br />
<code>attr <device> devStateIcon .*on.*off:WLAN_on_gWLAN_off .*on.*on.*:WLAN_on_gWLAN_on WLAN..off.*:WLAN_off</code><br />
<br />
Im Verzeichnis www/images/default müssen die passenden Dateien "WLAN_on_gWLAN_off.png", "WLAN_on_gWLAN_on.png" und "WLAN_off.png" liegen. Wenn die PNGs fehlen, können sie {{Link2Forum|Topic=29725|Message=318113|LinkText=hier}} heruntergeladen werden.<br />
<br />
== Anwendungsbeispiele ==<br />
[[Datei:Screenshot_FritzBox1.png|mini|300px|rechts|FRITZBOX Gerät auf der FHEM Oberfläche]]<br />
Sollte alles geklappt haben, seht ihr nun unter "Unsortiert" den im nebenstehenden Screenshot gezeigten Eintrag für das "Gerät" (hier mit dem Icon "it_router").<br />
<br />
=== TR-064 Beispiele ===<br />
*Box Reboot: <code>get <device> tr064Command DeviceConfig:1 deviceconfig Reboot</code><br />
*Internet Reconnect: <code>get <device> tr064Command WANIPConnection:1 wanipconnection1 ForceTermination</code><br />
*Daten eines Smart-Home-Gerätes auslesen: <code>get <device> tr064Command X_AVM-DE_Homeauto:1 x_homeauto GetGenericDeviceInfos NewIndex 0</code><br />
<br />
=== Klingel- und Sprachausgabe per TR-064 ===<br />
Das geht derzeit nicht, da entsprechende Kommandos per TR-064 nicht verfügbar sind. Da Telnet sukzessive abgestellt wird, sollten sich Interessenten per Feature-Request an AVM wenden, wie {{Link2Forum|Topic=38586|LinkText=hier}} beschrieben.<br />
<br />
Eine Alternative um Telefone klingeln zu lassen, ist die Nutzung des [[SIP-Client]]s.<br />
<br />
=== Anwesenheitserkennung per regelmäßiger Abfrage über das PRESENCE Modul ===<br />
Fritzboxen und die FRITZ!WLAN Repeater speichern den Status angemeldeter Geräte. Dieser Status lässt sich mittels des FRITZBOX Moduls über Readings abfragen, die das Format mac_AA_AA_AA_AA_AA_AA haben und die MAC-Adressen der jeweils angemeldeten Geräte (AA:AA:AA:AA:AA:AA) enthalten. Das Reading existiert, wenn das Gerät angemeldet ist. Wenn das Gerät abgemeldet ist, existiert es nicht mehr. Es gibt auch noch den Zwischenstatus "inactive", der anscheinend gesetzt wird, bevor das Reading gelöscht wird.<br />
<br />
Mit Hilfe des [[PRESENCE]] Moduls (vgl. [[Anwesenheitserkennung]]) kann man auf diese Weise den Anwesenheitsstatus abfragen. Anregungen dazu gibt es im zugehörigen {{Link2Forum|Topic=39433|LinkText=Forenthread}} zur Anwesenheitserkennung und in [http://heinz-otto.blogspot.de/2015/07/die-zeiten-andern-sich.html diesem Blogpost]. Auf dieser Basis könnte eine einfache Implementierung zum Beispiel so aussehen:<br />
<br />
Funktion in [[99_myUtils anlegen|99_myUtils]]:<br />
'''(Bitte beim Speichern darauf achten, dass nicht der Name 99_Utils gewählt wird.)''' <br />
<br />
<syntaxhighlight lang='perl'>sub checkFritzMACpresent($$) {<br />
# Benötigt: Name der zu testenden Fritzbox ($Device),<br />
# zu suchende MAC ($MAC), <br />
# Rückgabe: 1 = Gerät gefunden<br />
# 0 = Gerät nicht gefunden<br />
my ($Device, $MAC) = @_;<br />
my $Status = 0;<br />
$MAC =~ tr/:/_/;<br />
$MAC = "mac_".uc($MAC);<br />
my $StatusFritz = ReadingsVal($Device, $MAC, "weg");<br />
if ($StatusFritz eq "weg") {<br />
Log 1, ("checkFritzMACpresent ($Device): $MAC nicht gefunden, abwesend.");<br />
$Status = 0;<br />
} elsif ($StatusFritz eq "inactive") {<br />
Log 1, ("checkFritzMACpresent ($Device): $MAC ist >inactive<, also abwesend.");<br />
$Status = 0;<br />
} else {<br />
# Reading existiert, Rückgabewert ist nicht "inactive", also ist das Gerät per WLAN angemeldet.<br />
Log 4, ("checkFritzMACpresent ($Device): $MAC gefunden, Gerät heißt >$StatusFritz<.");<br />
$Status = 1;<br />
}<br />
return $Status<br />
}<br />
</syntaxhighlight><br />
<br />
Nutzung dieser Funktion mit dem PRESENCE Modul definieren:<br />
:<code>define <Name> PRESENCE function {checkFritzMACpresent("Fritzbox","AA:BB:CC:DD:EE:FF")} 60 60</code><br />
wobei<br />
*<Name> ein beliebig zu wählender Name für die PRESENCE-Funktion ist,<br />
*Fritzbox der Name ist, mit dem ihr die abzufragende Fritzbox als FRITZBOX definiert habt,<br />
*AA:BB:CC:DD:EE:FF die MAC-Adresse des gesuchten Geräts ist.<br />
* "60 60" sagt, dass der Anwesenheitsstatus im 60-Sekunden-Takt abgefragt wird. Das macht natürlich nur Sinn, wenn ihr mit <code>attr Fritzbox INTERVAL 60</code> den Abfrageinterval bei der Fritzbox auch entsprechend hochgesetzt habt. Der Standard ist 300.<br />
* "Log 1" führt immer zum Loggen. Das ist zum Einrichten praktisch, ohne dass man gleich für das ganze Modul oder ganz FHEM <code>attr <device> verbose 5</code> setzen muss. Wenn es läuft, können die "Log 1"-Zeilen gelöscht, auskommentiert (# an den Zeilenanfang) oder in "Log 5" geändert werden.<br />
<br />
=== Anwesenheitserkennung über mehrere Fritzboxen oder AVM Repeater und Fritzbox ===<br />
Existiert ein AVM Repeater im Netzwerk, kann der als eigenständiges Gerät mit FRITZBOX definiert werden. WLAN Geräte an der Fritzbox werden in der Instanz der Fritzbox gelistet und WLAN Geräte am Repeater in der Repeater Instanz. Um trotzdem die Anwesenheit im Netzwerk einfach zu erkennen, muss die Subroutine in 99_myUtils.pm abgewandelt werden.<br />
<br />
Existiert eine zweite Fritzbox im Accesspointmodus, werden die WLAN Geräte im Netzwerk alle in der Hauptfritzbox an einem LAN Anschluss gelistet. D.h. man sieht an der Hauptfritzbox nicht, dass sie im WLAN sind. Eine zweite Instanz mit dem FRITZBOX Modul muss wegen der Anwesenheitserkennung nicht gemacht werden. Die folgende Routine kann aber universell eingesetzt werden, unabhängig von der Anzahl der FRITZBOX Instanzen. Wer mitloggen will, kann das analog zur obigen Routine einbauen<br />
<br />
<syntaxhighlight lang='perl'>sub checkAllFritzMACpresent($) {<br />
# Benötigt: nur die zu suchende MAC ($MAC), <br />
# Es werden alle Instanzen vom Type FRITZBOX abgefragt<br />
#<br />
# Rückgabe: 1 = Gerät gefunden<br />
# 0 = Gerät nicht gefunden<br />
my ($MAC) = @_;<br />
# Wird in keiner Instanz die MAC Adresse gefunden bleibt der Status 0<br />
my $Status = 0;<br />
$MAC =~ tr/:/_/;<br />
$MAC = "mac_".uc($MAC);<br />
my @FBS = devspec2array("TYPE=FRITZBOX");<br />
foreach( @FBS ) {<br />
my $StatusFritz = ReadingsVal($_, $MAC, "weg");<br />
if ($StatusFritz eq "weg") {<br />
} elsif ($StatusFritz eq "inactive") {<br />
} else {<br />
# Reading existiert, Rückgabewert ist nicht "inactive", also ist das Gerät am Netzwerk angemeldet.<br />
$Status = 1;<br />
}<br />
}<br />
return $Status<br />
}<br />
</syntaxhighlight><br />
<br />
Da hiermit nach allen Instanzen mit dem TYPE=FRITZBOX durchsucht wird, braucht der Name der Fritzbox nicht angegeben werden.<br />
<br />
:<code>define <Name> PRESENCE function {checkAllFritzMACpresent("AA:BB:CC:DD:EE:FF")} 60 60</code><br />
<br />
Die Abfrage auf einen bestimmten Status kann einfach erweitert werden, ist aber immer vom Entwicklunsgstand der Fritzbox Firmware und des FRITZBOX Moduls abhängig. Eventuell erreicht man bessere Reaktionszeiten auf Abwesenheit durch diesen Zusatz:<br />
<syntaxhighlight lang='perl'>my $StatusFritz = ReadingsVal($_, $MAC, "weg");<br />
if ($StatusFritz eq "weg") {<br />
} elsif ($StatusFritz eq "inactive") {<br />
} elsif ($StatusFritz =~ /(.*)s, 0/) { <br />
# Dieser Zweig testet auf "<geraetename> (WLAN, 0 / 0 Mbit/s, 0)"<br />
} else {<br />
$Status = 1;<br />
}<br />
</syntaxhighlight><br />
<br />
Weitere Hinweise zu komplexeren Abfragen mehrere Boxen auf einmal etc. findet ihr auch im diesem {{Link2Forum|Topic=39433|LinkText=Forenthread}}.<br />
<br />
=== Anwesenheitserkennung per Notify ===<br />
Der von Fritzboxen und Fritz!WLAN Repeatern gespeicherte Status zum Status angemeldeter Geräte lässt sich (statt per PRESENCE, s.o.) auch per [[notify]] anfragen:<br />
<br />
<syntaxhighlight lang="perl">define <Name> notify Fritzbox:mac_AA_BB_CC_DD_EE_FF:.* {<br />
if (ReadingsVal("Fritzbox", "mac_AA_BB_CC_DD_EE_FF", "inactive") eq "inactive") <br />
{<br />
fhem("set anwesend_smartphone absent");<br />
} <br />
else <br />
{<br />
fhem("set anwesend_smartphone present");<br />
}<br />
}</syntaxhighlight><br />
<br />
Hinweise:<br />
* <code>fhem("set anwesend_smartphone absent");</code> ist nur ein Beispiel, das einen Dummy auf den Status "absent" bzw. "present" setzt. Man kann hier natürlich auch gleich entsprechende Aktionen durchführen. Wer das Beispiel übernehmen möchte, sollte den Dummy vorher definieren (<code>define anwesend_smartphone dummy</code>).<br />
* mac_AA_BB_CC_DD_EE_FF ist die MAC-Adresse des gesuchten Geräts.<br />
* "Fritzbox" ist der Name, unter dem die Fritzbox als FRITZBOX-Modul definiert wurde.<br />
* Das Notify funktioniert, weil Geräte, wenn sie sich abgemeldet haben, erst den Status "inactive" erhalten. Ist das Gerät ganz abgemeldet, verschwindet das mac_.*-Reading. Dabei löst das Notify nicht mehr aus. Da das mac-.*-Reading aber vorher auf "inactive" stand, wurde die Abwesend-Aktion schon ausgeführt.<br />
* Damit der Notify nicht andauernd losgeht, sollte man mittels <code>attr Fritzbox [[event-on-change-reading]] mac_AA_BB_CC_DD_EE_FF</code> Events nur auslösen, wenn sich der Status des Gerätes ändert. Will man mehrere Geräte abfragen, sollte man <code>attr Fritzbox event-on-change-reading mac_AA_BB_CC_DD_EE_FF,mac_GG_HH_II_JJ_KK_LL</code> setzen, damit bei der Änderung jedes Readings ein Event ausgelöst wird.<br />
<br />
=== Vergleich Anwesenheitserkennung PRESENCE/Notify ===<br />
Die Anwesenheitserkennung per regelmäßiger PRESENCE-Abfrage hat den Vorteil, dass sie im Turnus der regelmäßigen Abfragen immer einen aktuellen Status produziert. Sie hat dafür den Nachteil, dass die PRESENCE-Funktionen regelmäßig abgearbeitet werden müssen, auch wenn sich gar nichts ändert. Außerdem aktualisiert sich der Status nicht sofort, sondern erst bei der nächsten regelmäßigen Abfrage. Durch häufiges Abfragen kann dieser Nachteil verringert werden (bei entsprechend höherer Systemlast).<br />
<br />
Die Anwesenheitserkennung per Notify hat den Vorteil, dass ein sich ändernder Status sofort abgebildet wird. Ändert sich kein Status, werden keine Routinen ausgeführt, was die Systemlast gering hält. Der Nachteil ist, dass - z.B. nach einem Systemstart - die entsprechende Aktion erst bei einer Änderung des Status ausgeführt wird. D.h. ist das zu testende Gerät anwesend, wird dann FHEM beendet, das Gerät entfernt und FHEM wieder gestartet, ist der Status in FHEM immer noch "anwesend". Da das Reading für das Gerät nicht existiert, wird darauf auch erst wieder ein Notify ausgeführt, wenn sich der Status des Geräts wieder ändert, d.h. es wieder ankommt. Bis dahin ist der Status im System falsch. <br />
Der Nachteil des Notify kann verringert werden, wenn man statt <code>attr Fritzbox event-on-change-reading mac_AA_BB_CC_DD_EE_FF</code> ein <code>attr Fritzbox [[event-on-update-reading]] mac_AA_BB_CC_DD_EE_FF</code> setzt. Das erhöht allerdings die Systemlast und funktioniert auch nur für den Status "anwesend". Bei "abwesend" ist kein Reading vorhanden, so dass auch event-on-update-reading nicht ausgeführt wird.<br />
Eine weitere Möglichkeit, den Nachteil der Notify-Methode auszugleichen, ist, die Statusabfrage beim Systemstart einmal manuell auszuführen, durch ein notify auf "GLOBAL:initialized":<br />
<syntaxhighlight lang="perl"><br />
global:INITIALIZED {<br />
Reset_Variables;<br />
if (ReadingsVal("Fritzbox", "mac_AA_BB_CC_DD_EE_FF", "inactive") eq "inactive") {<br />
fhem("set anwesend_smartphone absent");<br />
} else {<br />
fhem("set anwesend_smartphone present");<br />
}<br />
}<br />
</syntaxhighlight><br />
Das hilft allerdings nur beim Systemstart. Nicht, wenn FHEM aufgrund irgendwelcher Hänger eine Aktualisierung des Status verpasst hat.<br />
<br />
=== userReadings per ''get tr064Command'' oder ''get luaQuery'' ===<br />
Um dem Gerätewert <userReadingName> den Wert von <VariabelName> aus der Rückgabe des get-Befehls ''tr064Command'' oder ''luaQuery'' zuzuordnen<br />
<pre><br />
attr <device> userReadings <userReadingName> {my $resp=fhem("get <device> tr064Command <service> <control> <action> [[<argName1> <argValue1>] ...]",1);;$resp =~/\'<VariabelName>\' => '(.*)'/;;return $1;;}<br />
</pre><br />
{{Randnotiz|RNTyp=r|RNText='''VORSICHT''': man sollte einen genaueren Trigger für diese userReadings setzen, sonst wird bei jeder Aktualierung von jedem Reading das get Kommando ausgeführt, was ganz schnell ein (für fhem blockierende) Dauerlaufer werden kann.}}<br />
<br />
Beispielsweise<br />
<pre>attr Fritzbox userReadings urMobilteil_1 {my $resp=fhem("get Fritzbox tr064Command X_AVM-DE_OnTel:1 x_contact GetDECTHandsetInfo NewDectID 1",1);;$resp =~/'NewHandsetName' => '(.*)'/;;return $1;;},<br />
urDownstreamDSLRate {my $resp=fhem("get Fritzbox tr064Command WANDSLInterfaceConfig:1 wandslifconfig1 GetInfo",1);;$resp =~/'NewDownstreamCurrRate' => '(.*)'/;;return $1;;},<br />
urUpstreamDSLRate {my $resp=fhem("get Fritzbox tr064Command WANDSLInterfaceConfig:1 wandslifconfig1 GetInfo",1);;$resp =~/'NewUpstreamCurrRate' => '(.*)'/;;return $1;;}</pre><br />
oder bei einzelnen Werte über ''get luaQuery''<pre>attr Fritzbox userReadings sip1_connect {my $resp=fhem("get Fritzbox luaQuery sip:settings/sip1/connect",1);;$resp =~/([0-9])$/;;return $1;;}</pre><br />
<br />
=== Klingelton-Einstellung und Abspielen von Sprachnachrichten bei Fritz!OS-Versionen >6.24 ===<br />
Wenn die Fritzbox weder die Telnet- noch die webcmd-Schnittstelle hat, kann der Klingelton der Fritz!Fons nicht mehr verstellt und auch keine Sprachnachricht über ein Fritz!Fon ausgegeben werden.<br />
<br />
Es gibt eine Behelfslösung über das Attribut ''useGuiHack''. Dadurch wird eine Eingabe in die WebGUI der Fritzbox simuliert. <br />
<br />
'''ACHTUNG''': Vor allem nach einem Update der FritzBox kann es durch dieses Attribut zu ungewolltem Verstellen von Werten in der Fritzbox kommen.<br />
<br />
Bei Verwendung der ring-Parameter "play:" und "say:" wird die abzuspielende URL in die M3U-Datei, die unter dem Internal ''M3U_LOCAL'' steht, eingetragen.<br> <br />
Standardmäßig wird versucht, diese Datei im image-Verzeichnis von FHEM abzulegen. Diese kann dann vom Fritz!Fon über [[FHEMWEB]] abgespielt werden (IP-Freigaben beachten). Direkt nach dem ersten Anlegen der m3u-Datei kennt [[FHEMWEB]] diese noch nicht, daher bitte entweder ''set <webdevice> rereadicons'' ausführen oder FHEM neu starten.<br><br />
<br />
Aufgrund der Beschränkungen von [[FHEMWEB]] oder auch bei Authentifizierungsanforderungen ist es empfehlenswert, die Datei über das Attribute ''m3uFileLocal'' selber vorzugeben. Am besten auf einem Webserver, der auf dem FHEM-Server läuft und dessen Seiten-Verzeichnis durch FHEM beschreibbar ist.<br><br />
Beispiel: <code>attr Fritzbox m3uFileLocal /var/www/mp3/Fritzbox.m3u</code><br />
<br />
In dem Radioeintrag ''FHEM'' muss dann '''auf der FritzBox''', die '''Web'''-Adresse der entsprechenden Datei eingetragen werden. Dieser Sender sollte zu Testzwecken dann auch einmal am Fritz!Fon von Hand gestartet werden.<br><br />
Das Modul versucht, beim Start die einzutragende Radio-URL im image-Verzeichnis selber zu ermitteln (IP-Freigabe beachten). Gelingt dies, so steht diese im Internal ''M3U_URL''.<br />
<br />
=== Ring auf mehreren Telefonen gleichzeitig ===<br />
<br />
Damit mehrere Telefone per ring gleichzeitig Klingel, muss in der Fritzbox eine Rufgruppe definiert werden.<br />
Sollte eine Türsprechanlage schon in Benutzung sein, kann die eventuell hierfür bereits eingerichtete Gruppe verwendet werden.<br />
Das anlegen der Gruppe erfolgt wie in folgender AVM Anleitung erledigt werden. [https://avm.de/service/fritzbox/fritzbox-7390/wissensdatenbank/publication/show/1148_Interne-Rufgruppe-in-FRITZ-Box-einrichten-Gruppenruf/ AVM Interne Rufgruppe anlegen]<br />
<br />
Es muss eine Kurzwahl bei der Gruppe zwingend hinterlegt sein.<br />
Danach kann mit folgendem Beispiel Code gearbeitet werden:<br />
<br />
<code>set FritzBox ring 791 15 show:Türklingel</code><br />
<br />
Name des Devices, Rufgruppen Nummer, Länge und gezeigter Text auf das gewünschte anpassen.<br />
<br />
== Bekannte Probleme / Fehlersuche ==<br />
=== Fehler nach Firmware Update ===<br />
Typischer Fehler ist hier "Error: 403 Forbidden". <br />
Nach einem Firmwareupdate der Fritzbox am besten auch FHEM neu starten.<br />
<br />
=== Modul bleibt im Status "Check APIs" hängen===<br />
Im Log steht die Meldung: "Error: Timeout when reading Fritz!Box data.".<br />
<br />
Mögliche Ursache: Nutzung des FHEM-Befehls [[rereadcfg]]. Dieser verträgt sich nicht mit dem Modul "blocking.pm", das für parallel laufende FHEM-Prozesse genutzt wird.<br />
<br />
Abhilfe schafft ein Neustart <code>shutdown restart</code> oder das Einfügen eines zusätzlichen, lokalen Telnet-Ports z.B. durch <code>define tPortLocal telnet 7073</code><br />
<br />
=== Nachtschaltung Doppel-WLAN ===<br />
Beim Abschalten des WLAN über das Modul wird (über TR064) zuerst das 2.4 GHz und dann das 5 GHz WLAN ausgeschaltet. Bei der gleichzeitigen Nutzung der WLAN-Nachtschaltung (Anschalten über das Fritz!OS) wird dann jedoch nur noch das 5 GHz WLAN wieder angeschaltet. Die Box interpretiert den TR064-Befehl anscheinend als ein komplettes Abwählen des 2.4 GHz WLAN.<br />
<br />
Abhilfe schafft hier nur ein notify auf das 5 GHz WLAN mit einem nachträglichem Anschalten des 2.4 GHz WLAN.<br />
<br />
Alternativ kann das Ausschalten des WLANs nicht direkt über TR064-Kommandos, sondern über einen indirekten Weg erfolgen: über TR064 ein set call abzusetzen und hier den Tastencode zum Ausschalten des WLANs einzugeben, bei einer FritzBox 7490 wäre dies z. B. #96*0*. <br />
Schaltet man über diese Methode das WLAN aus, kann es über die Nachtschaltung wieder automatisch auf beiden Frequenzen angeschaltet werden.<br />
<br />
=== Kabelboxen ===<br />
Bei Fritz!Boxen für den Kabelanschluss (z.B. Kabel Deutschland) scheint neben Telnet auch die TR064-API nicht zu funktionieren. Vermutlich wurde die API von AVM auf Betreiberwunsch deaktiviert, da man sonst Dinge ändern kann, die das gesamte Kabelnetz stören können.<br />
<br />
Zumindest für Unitymedia und einer FRITZ!Box 6490 Cable (lgi) mit FRITZ!OS:06.50 funktioniert TR064. <br />
<br />
Eine Rufumleitung bei Abwesenheit (Modul PRESENCE) funktioniert mit einer vorher eingerichten Telefonnummer wie folgt: <br />
<code>define Rufumleitung DOIF ([Anwesenheit.dum:state] eq "off") (set FritzBox6490 diversity 1 on) DOELSEIF ([Anwesenheit.dum:state] eq "on") (set FritzBox6490 diversity 1 off)</code><br />
<br />
=== Wenn's nicht klingelt ===<br />
Das Klingeln erfolgt über die Wählhilfe. Eventuell muss über die Weboberfläche der Fritz!Box ein anderer Port eingestellt werden. Der aktuelle steht in "box_stdDialPort".<br />
<br />
=== TR064-Transport-Error: 500 Can't connect to ...:49443 (certificate verify failed) ===<br />
Eventuell hilft es, die Perl Module Net::HTTPS, Net::SSL und IO::Socket::SSL zu aktualisieren.<br />
<br />
=== "Error: Old SID not valid anymore." nach Erlauben von IPv6 auf der Fritzbox ===<br />
Ohne hier den genauen Grund zu kennen - es hilft die Angabe der IPv4-Adresse: also statt <code>define FritzBox FRITZBOX</code> dann <code>define FritzBox FRITZBOX <IP></code> (z.B. <code>define FritzBox FRITZBOX 192.168.10.1</code>), so dass das Modul nicht über IPv6 geht.<br />
<br />
=== "Didn't get a session ID" ===<br />
Bei gleichzeitiger Nutzung anderer Modul für die Fritzbox (z.B. {{Link2CmdRef|Anker=FBAHAHTTP|Lang=en|Label=FBAHAHTTP}}) muss der Zugang über Benutzername und Password erfolgen.<br><br />
:<code>attr <DEVICE> boxUser <USER></code><br />
Da das FRITZBOX-Modul eine inoffizielle Schnittstelle benutzt, muss dann auch der normale Zugang zur Box auf "Benutzername und Password" eingestellt sein.<bR><br />
In der Firmware 6.92 wird der Zugang über die Menüs "System"->"Fritz!Box-Benutzer"->"Anmeldung im Heimnetz" eingestellt.<br />
<br />
Oft wird aber auch ein falsches oder gar kein Passwort gesetzt.<br />
<br />
:<code>set <DEVICE> password <PASSWORD></code><br />
<br />
=== TR064-Error 401:invalid action ===<br />
Eventuell ist auf der Fritzbox ein Benutzer gesetzt und im Modul nicht korrekt angegeben bzw. mit falschen Rechten versehen (attribut boxUser).<br />
<br />
== Links ==<br />
* {{Link2Forum|Topic=29725|LinkText=Forenthread}} zu diesem Modul<br />
<br />
[[Kategorie:FritzBox]] <br />
<!-- (Modulkategorie wird automatisch gesetzt) --><br />
<br />
[[Kategorie:Akustische Ausgabe]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=FRITZBOX&diff=31671FRITZBOX2019-11-10T12:19:41Z<p>Amenomade: /* userReadings per get tr064Command oder get luaQuery */</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Steuerung einer Fritz!Box über FHEM <br />
|ModType=d<br />
|ModForumArea=FRITZ!Box<br />
|ModTechName=72_FRITZBOX.pm<br />
|ModOwner=tupol/Topos ({{Link2FU|5432|Forum}} / [[Benutzer Diskussion:Topos|Wiki]])}}<br />
<br />
Das Modul [[FRITZBOX]] ermöglicht die Steuerung einer [[AVM Fritz!Box]] und von AVM FRITZ!WLAN Repeatern durch FHEM . An Fritzboxen können sowohl Geräte abgefragt werden, auf denen FHEM selbst läuft (lokaler Modus), als auch entfernte (externe) Geräte.<br />
<br />
== Voraussetzungen ==<br />
=== Remote-Zugang ===<br />
Für den Remote-Zugang müssen die Module JSON:XS, LWP und SOAP::Lite installiert sein; auf einem [[Raspberry Pi]] oder unter Ubuntu z.&nbsp;B. mit dem Befehl<br />
:<code>sudo apt-get install libjson-perl libwww-perl libsoap-lite-perl libjson-xs-perl</code><br />
<br />
Teilweise ist derzeit zusätzlich die Installation der telnet Libraries erforderlich, auch wenn der Telnet-Zugang nicht genutzt werden soll. Siehe dazu den nachfolgenden Abschnitt.<br />
<br />
=== Telnet ===<br />
Das Modul basierte ursprünglich auf dem Zugriff auf die Fritzbox per Telnet. Ab FRITZ!OS 6.2x baut AVM den abgekündigten Telnet-Zugang sowie die webcm-Schnittstelle sukzessive zurück bzw. hat dies, je nach Firmware, schon ganz abgestellt (siehe {{Link2Forum|Topic=38586|LinkText=dieses Forenthema}}). Der zukunftssichere Zugriff auf die Fritzbox sollte also per TR-064 erfolgen. Der Vollständigkeit halber und für ältere Firmwareversionen: <br />
<br />
# Wer den Zugang per Telnet (noch) nutzen (kann und) möchte, muss dies zuerst freischalten. Üblicherweise durch Eingabe von #96*7* an einem direkt an der entsprechenden FritzBox angeschlosssenen Telefon<br />
# Auf dem System, auf dem FHEM läuft ([[Systemübersicht#Server|Server]]) muss Telnet installiert sein; auf einem [[Raspberry Pi]] und unter Ubuntu z.&nbsp;B. mit dem Befehl<br />
::<code>sudo apt-get install libnet-telnet-perl</code><br />
<br />
== Installation ==<br />
=== Erste Schritte ===<br />
Zur Erstinstallation reicht ein einfaches <code>define FritzBox FRITZBOX</code>, dieses Modul funktioniert lokal (FHEM auf Fritzbox) sowie per Fernzugriff (FHEM auf einem anderen Server im Netz, siehe nächsten Schritt).<br />
<br />
==== TR-064: Modul FRITZBOX für Zugriff auf einem externen Server einrichten ====<br />
Für den Fernzugriff über TR-064 auf eine oder mehrere Fritzboxen und/oder einen FRITZ!WLAN Repeater sind die folgenden Schritte nötig (für jedes Gerät):<br />
<br />
Fritzbox definieren:<br />
:<code>define FritzBox FRITZBOX</code><br />
<br />
Wenn die Fritzbox nicht unter <nowiki>http://fritz.box</nowiki> erreichbar ist, IP im define setzen:<br />
:<code>define FritzBox FRITZBOX 192.168.168.168</code><br />
192.168.168.168 dabei natürlich durch die passende IP ersetzen... Alternativ kann statt der IP auch der Hostname eingegeben werden.<br />
<br />
Wenn ('''und nur wenn''') das Login auf der Benutzeroberfläche der FritzBox mit User und Passwort (und nicht nur per Passwort) geschieht, den User konfigurieren:<br />
:<code>attr FritzBox boxUser ''Benutzername'' </code><br />
In der Fritzbox muss dann auch "Anmeldung mit FRITZ!Box-Benutzernamen und Kennwort" ausgewählt sein.<br />
<br />
Passwort konfigurieren:<br />
:<code>set FritzBox password ''Passwort''</code> - legt das zugehörige Passwort fest (nur einmal --> gehört nicht in die cfg-Datei) <br />
<br />
Manuelle TR-064 Kommandos erlauben (Das Auslesen der Readings per TR-064 funktioniert auch ohne dieses Attribut.):<br />
:<code>attr FritzBox allowTR064Command 1</code><br />
<br />
==== Telnet: Modul FRITZBOX für Zugriff auf einem externen Server einrichten ====<br />
[[Datei:Screenshot_FritzBox_TelnetUser.png|mini|300px|rechts|Anlegen des Attributs telnetUser]]<br />
Bei Fernzugriff über Telnet sind weitere Schritte nötig:<br />
# Telnet auf der Fritzbox freischalten (Tastenkombination #96*7* am angeschlossenen Telefon (auch FritzFon)<br />
# TelnetUser definieren (wie im Screenshot gezeigt)<br />
# Passwort zum Benutzer auf der Fritzbox definieren<br />
<br />
[[Datei:Screenshot_FritzBox_Passwort.png|mini|300px|rechts|Passwort definieren]]<br />
<br />
(bitte die Buttons {{Taste|set}} und {{Taste|attr}} bei der Definition der jeweiligen Einträge nicht vergessen)<br />
<br />
Wer stattdessen lieber das [[Konfiguration|Befehl-Eingabefeld]] verwendet:<br />
<br />
:<code>define FritzBox FRITZBOX</code><br />
:<code>attr FritzBox telnetUser ''Benutzername'' </code> - legt den Benutzer fest<br />
:<code>set FritzBox password ''Passwort'' </code> - legt das zugehörige Passwort fest<br />
<br />
Wer keinen User konfiguriert hat, kann das Feld "telnetUser" leer lassen.<br />
<br />
Wer sicher gehen möchte, dass auch tatsächlich Telnet und nicht andere Zugriffe benutzt werden, sollte außerdem noch setzen:<br />
<br />
:<code>attr FritzBox forceTelnetConnection 1</code><br />
<br />
=== mögliche Fehlermeldungen ===<br />
Sollte schon bei <code>define FritzBox FRITZBOX</code> die Fehlermeldung kommen, dass dieses Modul nicht existiert, dann bitte prüfen, ob FHEM auf dem aktuellen Stand ist und ggf. [[Update|aktualisieren]].<br />
<br />
Kommt jetzt bei der erneuten Definition die Fehlermeldung <code>Error: Perl modul Net::Telnet is missing on this system</code> bitte wie oben schon erwähnt den Befehl <br />
:<code>sudo apt-get install libnet-telnet-perl</code> <br />
direkt per Telnet/SSH auf dem FHEM-Server ausführen und neu starten.<br />
Sollte alles geklappt haben, seht ihr nun eure Fritzbox und könnt diverse Einstellungen manuell vornehmen und/oder automatisch vornehmen lassen.<br />
<br />
== Anwendung ==<br />
=== Define ===<br />
Siehe {{Link2CmdRef|Lang=de|Anker=FRITZBOXdefine}}<br />
<br />
=== Attribute ===<br />
Siehe {{Link2CmdRef|Lang=de|Anker=FRITZBOXattr}}<br />
<br />
=== TR-064 ===<br />
Die offizielle Programmier-Schnittstelle der Fritz!Box läuft über das Protokoll TR-064.<br />
<br />
mit dem Attribute<br/><br />
<code>attr <device> allowTR064Command 1</code><br/><br />
kann man den Befehl<br/><br />
<code>get <device> tr064Command <service> <control> <action> [[parameterName1 parameterValue1] ...]</code><br/><br />
freischalten und damit auf diese Schnittstelle zugreifen.<br />
<br />
AVM hat die Schnittstellenbeschreibung unter [http://avm.de/service/schnittstellen/] veröffentlicht. Diese wird jedoch nur sehr sporadisch gepflegt.<br><br />
Ein besserer Einstiegspunkt befindet sich auf der Box unter http://fritz.box:49000/tr64desc.xml.<br><br />
Die möglichen TR-064-Aktionen kann man auch über den Befehl <code>get <device> tr064ServiceList</code> auslesen.<br />
<br />
Folgende Service und Controls existieren (für den get-Befehl ''tr064Command'' werden nur die fett formatierten Wörter benötigt)<br />
<br />
{| class="wikitable"<br />
|-<br />
!serviceType!!controlURL!!XML!!Dokument bei AVM<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''DeviceInfo:1'''||/upnp/control/'''deviceinfo'''||[http://fritz.box:49000/deviceinfoSCPD.xml deviceinfoSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/deviceinfoSCPD.pdf deviceinfoSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''DeviceConfig:1'''||/upnp/control/'''deviceconfig'''||[http://fritz.box:49000/deviceconfigSCPD.xml deviceconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/deviceconfigSCPD.pdf deviceconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''Layer3Forwarding:1'''||/upnp/control/'''layer3forwarding'''||[http://fritz.box:49000//layer3forwardingSCPD.xml layer3forwardingSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/layer3forwardingSCPD.pdf layer3forwardingSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''LANConfigSecurity:1'''||/upnp/control/'''lanconfigsecurity'''||[http://fritz.box:49000//lanconfigsecuritySCPD.xml lanconfigsecuritySCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/lanconfigsecuritySCPD.pdf lanconfigsecuritySCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''ManagementServer:1'''||/upnp/control/'''mgmsrv'''||[http://fritz.box:49000//mgmsrvSCPD.xml mgmsrvSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/mgmsrvSCPD.pdf mgmsrvSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''Time:1'''||/upnp/control/'''time'''||[http://fritz.box:49000//timeSCPD.xml timeSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/timeSCPD.pdf timeSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''UserInterface:1'''||/upnp/control/'''userif'''||[http://fritz.box:49000//userifSCPD.xml userifSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/userifSCPD.pdf userifSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_VoIP:1'''||/upnp/control/'''x_voip'''||[http://fritz.box:49000//x_voipSCPD.xml x_voipSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_voipSCPD.pdf x_voipSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_Storage:1'''||/upnp/control/'''x_storage'''||[http://fritz.box:49000//x_storageSCPD.xml x_storageSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_storageSCPD.pdf x_storageSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_OnTel:1'''||/upnp/control/'''x_contact'''||[http://fritz.box:49000//x_contactSCPD.xml x_contactSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_contactSCPD.pdf x_contactSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_WebDAVClient:1'''||/upnp/control/'''x_webdav'''||[http://fritz.box:49000//x_webdavSCPD.xml x_webdavSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_webdavSCPD.pdf x_webdavSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_UPnP:1'''||/upnp/control/'''x_upnp'''||[http://fritz.box:49000//x_upnpSCPD.xml x_upnpSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_upnp.pdf x_upnp.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_RemoteAccess:1'''||/upnp/control/'''x_remote'''||[http://fritz.box:49000/x_remoteSCPD.xml x_remoteSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_remoteSCPD.pdf x_remoteSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_MyFritz:1'''||/upnp/control/'''x_myfritz'''||[http://fritz.box:49000/x_myfritzSCPD.xml x_myfritzSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_myfritzSCPD.pdf x_myfritzSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_TAM:1'''||/upnp/control/'''x_tam'''||[http://fritz.box:49000/x_tamSCPD.xml x_tamSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_tam.pdf x_tam.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_AppSetup:1'''||/upnp/control/'''x_appsetup'''||[http://fritz.box:49000/x_homeautoSCPD.xml x_homeautoSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_appsetupSCPD.pdf x_appsetupSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_Homeauto:1'''||/upnp/control/'''x_homeauto'''||[http://fritz.box:49000/x_homeautoSCPD.xml x_homeautoSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_homeautoSCPD.pdf x_homeautoSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WLANConfiguration:1'''||/upnp/control/'''wlanconfig1'''||[http://fritz.box:49000/wlanconfigSCPD.xml wlanconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wlanconfigSCPD.pdf wlanconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WLANConfiguration:2'''||/upnp/control/'''wlanconfig2'''||[http://fritz.box:49000/wlanconfigSCPD.xml wlanconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wlanconfigSCPD.pdf wlanconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WLANConfiguration:3'''||/upnp/control/'''wlanconfig3'''||[http://fritz.box:49000/wlanconfigSCPD.xml wlanconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wlanconfigSCPD.pdf wlanconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''Hosts:1'''||/upnp/control/'''hosts'''||[http://fritz.box:49000/hostsSCPD.xml hostsSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/hostsSCPD.pdf hostsSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''LANEthernetInterfaceConfig:1'''||/upnp/control/'''lanethernetifcfg'''||[http://fritz.box:49000/lanifconfigSCPD.xml lanifconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/lanifconfigSCPD.pdf lanifconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''LANHostConfigManagement:1'''||/upnp/control/'''lanhostconfigmgm'''||[http://fritz.box:49000/lanhostconfigmgmSCPD.xml lanhostconfigmgmSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/lanhostconfigmgmSCPD.pdf lanhostconfigmgmSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANCommonInterfaceConfig:1'''||/upnp/control/'''wancommonifconfig1'''||[http://fritz.box:49000/wancommonifconfigSCPD.xml wancommonifconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wancommonifconfigSCPD.pdf wancommonifconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANDSLInterfaceConfig:1'''||/upnp/control/'''wandslifconfig1'''||[http://fritz.box:49000/wandslifconfigSCPD.xml wandslifconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wandslifconfigSCPD.pdf wandslifconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANDSLLinkConfig:1'''||/upnp/control/'''wandsllinkconfig1'''||[http://fritz.box:49000/wandsllinkconfigSCPD.xml wandsllinkconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wandsllinkconfigSCPD.pdf wandsllinkconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANEthernetLinkConfig:1'''||/upnp/control/'''wanethlinkconfig1'''||[http://fritz.box:49000/wanethlinkconfigSCPD.xml wanethlinkconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wanethlinkconfigSCPD.pdf wanethlinkconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANPPPConnection:1'''||/upnp/control/'''wanpppconn1'''||[http://fritz.box:49000/wanpppconnSCPD.xml wanpppconnSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wanpppconnSCPD.pdf wanpppconnSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANIPConnection:1'''||/upnp/control/'''wanipconnection1'''||[http://fritz.box:49000/wanipconnSCPD.xml wanipconnSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wanipconnSCPD.pdf wanipconnSCPD.pdf]<br />
|-<br />
|}<br />
<br />
=== Status-Symbol ===<br />
<code>attr <device> devStateIcon .*on.*off:WLAN_on_gWLAN_off .*on.*on.*:WLAN_on_gWLAN_on WLAN..off.*:WLAN_off</code><br />
<br />
Im Verzeichnis www/images/default müssen die passenden Dateien "WLAN_on_gWLAN_off.png", "WLAN_on_gWLAN_on.png" und "WLAN_off.png" liegen. Wenn die PNGs fehlen, können sie {{Link2Forum|Topic=29725|Message=318113|LinkText=hier}} heruntergeladen werden.<br />
<br />
== Anwendungsbeispiele ==<br />
[[Datei:Screenshot_FritzBox1.png|mini|300px|rechts|FRITZBOX Gerät auf der FHEM Oberfläche]]<br />
Sollte alles geklappt haben, seht ihr nun unter "Unsortiert" den im nebenstehenden Screenshot gezeigten Eintrag für das "Gerät" (hier mit dem Icon "it_router").<br />
<br />
=== TR-064 Beispiele ===<br />
*Box Reboot: <code>get <device> tr064Command DeviceConfig:1 deviceconfig Reboot</code><br />
*Internet Reconnect: <code>get <device> tr064Command WANIPConnection:1 wanipconnection1 ForceTermination</code><br />
*Daten eines Smart-Home-Gerätes auslesen: <code>get <device> tr064Command X_AVM-DE_Homeauto:1 x_homeauto GetGenericDeviceInfos NewIndex 0</code><br />
<br />
=== Klingel- und Sprachausgabe per TR-064 ===<br />
Das geht derzeit nicht, da entsprechende Kommandos per TR-064 nicht verfügbar sind. Da Telnet sukzessive abgestellt wird, sollten sich Interessenten per Feature-Request an AVM wenden, wie {{Link2Forum|Topic=38586|LinkText=hier}} beschrieben.<br />
<br />
Eine Alternative um Telefone klingeln zu lassen, ist die Nutzung des [[SIP-Client]]s.<br />
<br />
=== Anwesenheitserkennung per regelmäßiger Abfrage über das PRESENCE Modul ===<br />
Fritzboxen und die FRITZ!WLAN Repeater speichern den Status angemeldeter Geräte. Dieser Status lässt sich mittels des FRITZBOX Moduls über Readings abfragen, die das Format mac_AA_AA_AA_AA_AA_AA haben und die MAC-Adressen der jeweils angemeldeten Geräte (AA:AA:AA:AA:AA:AA) enthalten. Das Reading existiert, wenn das Gerät angemeldet ist. Wenn das Gerät abgemeldet ist, existiert es nicht mehr. Es gibt auch noch den Zwischenstatus "inactive", der anscheinend gesetzt wird, bevor das Reading gelöscht wird.<br />
<br />
Mit Hilfe des [[PRESENCE]] Moduls (vgl. [[Anwesenheitserkennung]]) kann man auf diese Weise den Anwesenheitsstatus abfragen. Anregungen dazu gibt es im zugehörigen {{Link2Forum|Topic=39433|LinkText=Forenthread}} zur Anwesenheitserkennung und in [http://heinz-otto.blogspot.de/2015/07/die-zeiten-andern-sich.html diesem Blogpost]. Auf dieser Basis könnte eine einfache Implementierung zum Beispiel so aussehen:<br />
<br />
Funktion in [[99_myUtils anlegen|99_myUtils]]:<br />
'''(Bitte beim Speichern darauf achten, dass nicht der Name 99_Utils gewählt wird.)''' <br />
<br />
<syntaxhighlight lang='perl'>sub checkFritzMACpresent($$) {<br />
# Benötigt: Name der zu testenden Fritzbox ($Device),<br />
# zu suchende MAC ($MAC), <br />
# Rückgabe: 1 = Gerät gefunden<br />
# 0 = Gerät nicht gefunden<br />
my ($Device, $MAC) = @_;<br />
my $Status = 0;<br />
$MAC =~ tr/:/_/;<br />
$MAC = "mac_".uc($MAC);<br />
my $StatusFritz = ReadingsVal($Device, $MAC, "weg");<br />
if ($StatusFritz eq "weg") {<br />
Log 1, ("checkFritzMACpresent ($Device): $MAC nicht gefunden, abwesend.");<br />
$Status = 0;<br />
} elsif ($StatusFritz eq "inactive") {<br />
Log 1, ("checkFritzMACpresent ($Device): $MAC ist >inactive<, also abwesend.");<br />
$Status = 0;<br />
} else {<br />
# Reading existiert, Rückgabewert ist nicht "inactive", also ist das Gerät per WLAN angemeldet.<br />
Log 4, ("checkFritzMACpresent ($Device): $MAC gefunden, Gerät heißt >$StatusFritz<.");<br />
$Status = 1;<br />
}<br />
return $Status<br />
}<br />
</syntaxhighlight><br />
<br />
Nutzung dieser Funktion mit dem PRESENCE Modul definieren:<br />
:<code>define <Name> PRESENCE function {checkFritzMACpresent("Fritzbox","AA:BB:CC:DD:EE:FF")} 60 60</code><br />
wobei<br />
*<Name> ein beliebig zu wählender Name für die PRESENCE-Funktion ist,<br />
*Fritzbox der Name ist, mit dem ihr die abzufragende Fritzbox als FRITZBOX definiert habt,<br />
*AA:BB:CC:DD:EE:FF die MAC-Adresse des gesuchten Geräts ist.<br />
* "60 60" sagt, dass der Anwesenheitsstatus im 60-Sekunden-Takt abgefragt wird. Das macht natürlich nur Sinn, wenn ihr mit <code>attr Fritzbox INTERVAL 60</code> den Abfrageinterval bei der Fritzbox auch entsprechend hochgesetzt habt. Der Standard ist 300.<br />
* "Log 1" führt immer zum Loggen. Das ist zum Einrichten praktisch, ohne dass man gleich für das ganze Modul oder ganz FHEM <code>attr <device> verbose 5</code> setzen muss. Wenn es läuft, können die "Log 1"-Zeilen gelöscht, auskommentiert (# an den Zeilenanfang) oder in "Log 5" geändert werden.<br />
<br />
=== Anwesenheitserkennung über mehrere Fritzboxen oder AVM Repeater und Fritzbox ===<br />
Existiert ein AVM Repeater im Netzwerk, kann der als eigenständiges Gerät mit FRITZBOX definiert werden. WLAN Geräte an der Fritzbox werden in der Instanz der Fritzbox gelistet und WLAN Geräte am Repeater in der Repeater Instanz. Um trotzdem die Anwesenheit im Netzwerk einfach zu erkennen, muss die Subroutine in 99_myUtils.pm abgewandelt werden.<br />
<br />
Existiert eine zweite Fritzbox im Accesspointmodus, werden die WLAN Geräte im Netzwerk alle in der Hauptfritzbox an einem LAN Anschluss gelistet. D.h. man sieht an der Hauptfritzbox nicht, dass sie im WLAN sind. Eine zweite Instanz mit dem FRITZBOX Modul muss wegen der Anwesenheitserkennung nicht gemacht werden. Die folgende Routine kann aber universell eingesetzt werden, unabhängig von der Anzahl der FRITZBOX Instanzen. Wer mitloggen will, kann das analog zur obigen Routine einbauen<br />
<br />
<syntaxhighlight lang='perl'>sub checkAllFritzMACpresent($) {<br />
# Benötigt: nur die zu suchende MAC ($MAC), <br />
# Es werden alle Instanzen vom Type FRITZBOX abgefragt<br />
#<br />
# Rückgabe: 1 = Gerät gefunden<br />
# 0 = Gerät nicht gefunden<br />
my ($MAC) = @_;<br />
# Wird in keiner Instanz die MAC Adresse gefunden bleibt der Status 0<br />
my $Status = 0;<br />
$MAC =~ tr/:/_/;<br />
$MAC = "mac_".uc($MAC);<br />
my @FBS = devspec2array("TYPE=FRITZBOX");<br />
foreach( @FBS ) {<br />
my $StatusFritz = ReadingsVal($_, $MAC, "weg");<br />
if ($StatusFritz eq "weg") {<br />
} elsif ($StatusFritz eq "inactive") {<br />
} else {<br />
# Reading existiert, Rückgabewert ist nicht "inactive", also ist das Gerät am Netzwerk angemeldet.<br />
$Status = 1;<br />
}<br />
}<br />
return $Status<br />
}<br />
</syntaxhighlight><br />
<br />
Da hiermit nach allen Instanzen mit dem TYPE=FRITZBOX durchsucht wird, braucht der Name der Fritzbox nicht angegeben werden.<br />
<br />
:<code>define <Name> PRESENCE function {checkAllFritzMACpresent("AA:BB:CC:DD:EE:FF")} 60 60</code><br />
<br />
Die Abfrage auf einen bestimmten Status kann einfach erweitert werden, ist aber immer vom Entwicklunsgstand der Fritzbox Firmware und des FRITZBOX Moduls abhängig. Eventuell erreicht man bessere Reaktionszeiten auf Abwesenheit durch diesen Zusatz:<br />
<syntaxhighlight lang='perl'>my $StatusFritz = ReadingsVal($_, $MAC, "weg");<br />
if ($StatusFritz eq "weg") {<br />
} elsif ($StatusFritz eq "inactive") {<br />
} elsif ($StatusFritz =~ /(.*)s, 0/) { <br />
# Dieser Zweig testet auf "<geraetename> (WLAN, 0 / 0 Mbit/s, 0)"<br />
} else {<br />
$Status = 1;<br />
}<br />
</syntaxhighlight><br />
<br />
Weitere Hinweise zu komplexeren Abfragen mehrere Boxen auf einmal etc. findet ihr auch im diesem {{Link2Forum|Topic=39433|LinkText=Forenthread}}.<br />
<br />
=== Anwesenheitserkennung per Notify ===<br />
Der von Fritzboxen und Fritz!WLAN Repeatern gespeicherte Status zum Status angemeldeter Geräte lässt sich (statt per PRESENCE, s.o.) auch per [[notify]] anfragen:<br />
<br />
<syntaxhighlight lang="perl">define <Name> notify Fritzbox:mac_AA_BB_CC_DD_EE_FF:.* {<br />
if (ReadingsVal("Fritzbox", "mac_AA_BB_CC_DD_EE_FF", "inactive") eq "inactive") <br />
{<br />
fhem("set anwesend_smartphone absent");<br />
} <br />
else <br />
{<br />
fhem("set anwesend_smartphone present");<br />
}<br />
}</syntaxhighlight><br />
<br />
Hinweise:<br />
* <code>fhem("set anwesend_smartphone absent");</code> ist nur ein Beispiel, das einen Dummy auf den Status "absent" bzw. "present" setzt. Man kann hier natürlich auch gleich entsprechende Aktionen durchführen. Wer das Beispiel übernehmen möchte, sollte den Dummy vorher definieren (<code>define anwesend_smartphone dummy</code>).<br />
* mac_AA_BB_CC_DD_EE_FF ist die MAC-Adresse des gesuchten Geräts.<br />
* "Fritzbox" ist der Name, unter dem die Fritzbox als FRITZBOX-Modul definiert wurde.<br />
* Das Notify funktioniert, weil Geräte, wenn sie sich abgemeldet haben, erst den Status "inactive" erhalten. Ist das Gerät ganz abgemeldet, verschwindet das mac_.*-Reading. Dabei löst das Notify nicht mehr aus. Da das mac-.*-Reading aber vorher auf "inactive" stand, wurde die Abwesend-Aktion schon ausgeführt.<br />
* Damit der Notify nicht andauernd losgeht, sollte man mittels <code>attr Fritzbox [[event-on-change-reading]] mac_AA_BB_CC_DD_EE_FF</code> Events nur auslösen, wenn sich der Status des Gerätes ändert. Will man mehrere Geräte abfragen, sollte man <code>attr Fritzbox event-on-change-reading mac_AA_BB_CC_DD_EE_FF,mac_GG_HH_II_JJ_KK_LL</code> setzen, damit bei der Änderung jedes Readings ein Event ausgelöst wird.<br />
<br />
=== Vergleich Anwesenheitserkennung PRESENCE/Notify ===<br />
Die Anwesenheitserkennung per regelmäßiger PRESENCE-Abfrage hat den Vorteil, dass sie im Turnus der regelmäßigen Abfragen immer einen aktuellen Status produziert. Sie hat dafür den Nachteil, dass die PRESENCE-Funktionen regelmäßig abgearbeitet werden müssen, auch wenn sich gar nichts ändert. Außerdem aktualisiert sich der Status nicht sofort, sondern erst bei der nächsten regelmäßigen Abfrage. Durch häufiges Abfragen kann dieser Nachteil verringert werden (bei entsprechend höherer Systemlast).<br />
<br />
Die Anwesenheitserkennung per Notify hat den Vorteil, dass ein sich ändernder Status sofort abgebildet wird. Ändert sich kein Status, werden keine Routinen ausgeführt, was die Systemlast gering hält. Der Nachteil ist, dass - z.B. nach einem Systemstart - die entsprechende Aktion erst bei einer Änderung des Status ausgeführt wird. D.h. ist das zu testende Gerät anwesend, wird dann FHEM beendet, das Gerät entfernt und FHEM wieder gestartet, ist der Status in FHEM immer noch "anwesend". Da das Reading für das Gerät nicht existiert, wird darauf auch erst wieder ein Notify ausgeführt, wenn sich der Status des Geräts wieder ändert, d.h. es wieder ankommt. Bis dahin ist der Status im System falsch. <br />
Der Nachteil des Notify kann verringert werden, wenn man statt <code>attr Fritzbox event-on-change-reading mac_AA_BB_CC_DD_EE_FF</code> ein <code>attr Fritzbox [[event-on-update-reading]] mac_AA_BB_CC_DD_EE_FF</code> setzt. Das erhöht allerdings die Systemlast und funktioniert auch nur für den Status "anwesend". Bei "abwesend" ist kein Reading vorhanden, so dass auch event-on-update-reading nicht ausgeführt wird.<br />
Eine weitere Möglichkeit, den Nachteil der Notify-Methode auszugleichen, ist, die Statusabfrage beim Systemstart einmal manuell auszuführen, durch ein notify auf "GLOBAL:initialized":<br />
<syntaxhighlight lang="perl"><br />
global:INITIALIZED {<br />
Reset_Variables;<br />
if (ReadingsVal("Fritzbox", "mac_AA_BB_CC_DD_EE_FF", "inactive") eq "inactive") {<br />
fhem("set anwesend_smartphone absent");<br />
} else {<br />
fhem("set anwesend_smartphone present");<br />
}<br />
}<br />
</syntaxhighlight><br />
Das hilft allerdings nur beim Systemstart. Nicht, wenn FHEM aufgrund irgendwelcher Hänger eine Aktualisierung des Status verpasst hat.<br />
<br />
=== userReadings per ''get tr064Command'' oder ''get luaQuery'' ===<br />
Um dem Gerätewert <userReadingName> den Wert von <VariabelName> aus der Rückgabe des get-Befehls ''tr064Command'' oder ''luaQuery'' zuzuordnen<br />
<pre><br />
attr <device> userReadings <userReadingName> {my $resp=fhem("get <device> tr064Command <service> <control> <action> [[<argName1> <argValue1>] ...]",1);;$resp =~/\'<VariabelName>\' => '(.*)'/;;return $1;;}<br />
</pre><br />
Beispielsweise<br />
<pre>attr Fritzbox userReadings urMobilteil_1 {my $resp=fhem("get Fritzbox tr064Command X_AVM-DE_OnTel:1 x_contact GetDECTHandsetInfo NewDectID 1",1);;$resp =~/'NewHandsetName' => '(.*)'/;;return $1;;},<br />
urDownstreamDSLRate {my $resp=fhem("get Fritzbox tr064Command WANDSLInterfaceConfig:1 wandslifconfig1 GetInfo",1);;$resp =~/'NewDownstreamCurrRate' => '(.*)'/;;return $1;;},<br />
urUpstreamDSLRate {my $resp=fhem("get Fritzbox tr064Command WANDSLInterfaceConfig:1 wandslifconfig1 GetInfo",1);;$resp =~/'NewUpstreamCurrRate' => '(.*)'/;;return $1;;}</pre><br />
oder bei einzelnen Werte über ''get luaQuery''<pre>attr Fritzbox userReadings sip1_connect {my $resp=fhem("get Fritzbox luaQuery sip:settings/sip1/connect",1);;$resp =~/([0-9])$/;;return $1;;}</pre><br />
<br />
{{Randnotiz|RNTyp=r|RNText='''VORSICHT''': man sollte einen genaueren Trigger für diese userReadings setzen, sonst wird bei jeder Aktualierung von jedem Reading das get Kommando ausgeführt, was ganz schnell ein (für fhem blockierenden) Dauerlaufer werden kann.}}<br />
<br />
=== Klingelton-Einstellung und Abspielen von Sprachnachrichten bei Fritz!OS-Versionen >6.24 ===<br />
Wenn die Fritzbox weder die Telnet- noch die webcmd-Schnittstelle hat, kann der Klingelton der Fritz!Fons nicht mehr verstellt und auch keine Sprachnachricht über ein Fritz!Fon ausgegeben werden.<br />
<br />
Es gibt eine Behelfslösung über das Attribut ''useGuiHack''. Dadurch wird eine Eingabe in die WebGUI der Fritzbox simuliert. <br />
<br />
'''ACHTUNG''': Vor allem nach einem Update der FritzBox kann es durch dieses Attribut zu ungewolltem Verstellen von Werten in der Fritzbox kommen.<br />
<br />
Bei Verwendung der ring-Parameter "play:" und "say:" wird die abzuspielende URL in die M3U-Datei, die unter dem Internal ''M3U_LOCAL'' steht, eingetragen.<br> <br />
Standardmäßig wird versucht, diese Datei im image-Verzeichnis von FHEM abzulegen. Diese kann dann vom Fritz!Fon über [[FHEMWEB]] abgespielt werden (IP-Freigaben beachten). Direkt nach dem ersten Anlegen der m3u-Datei kennt [[FHEMWEB]] diese noch nicht, daher bitte entweder ''set <webdevice> rereadicons'' ausführen oder FHEM neu starten.<br><br />
<br />
Aufgrund der Beschränkungen von [[FHEMWEB]] oder auch bei Authentifizierungsanforderungen ist es empfehlenswert, die Datei über das Attribute ''m3uFileLocal'' selber vorzugeben. Am besten auf einem Webserver, der auf dem FHEM-Server läuft und dessen Seiten-Verzeichnis durch FHEM beschreibbar ist.<br><br />
Beispiel: <code>attr Fritzbox m3uFileLocal /var/www/mp3/Fritzbox.m3u</code><br />
<br />
In dem Radioeintrag ''FHEM'' muss dann '''auf der FritzBox''', die '''Web'''-Adresse der entsprechenden Datei eingetragen werden. Dieser Sender sollte zu Testzwecken dann auch einmal am Fritz!Fon von Hand gestartet werden.<br><br />
Das Modul versucht, beim Start die einzutragende Radio-URL im image-Verzeichnis selber zu ermitteln (IP-Freigabe beachten). Gelingt dies, so steht diese im Internal ''M3U_URL''.<br />
<br />
=== Ring auf mehreren Telefonen gleichzeitig ===<br />
<br />
Damit mehrere Telefone per ring gleichzeitig Klingel, muss in der Fritzbox eine Rufgruppe definiert werden.<br />
Sollte eine Türsprechanlage schon in Benutzung sein, kann die eventuell hierfür bereits eingerichtete Gruppe verwendet werden.<br />
Das anlegen der Gruppe erfolgt wie in folgender AVM Anleitung erledigt werden. [https://avm.de/service/fritzbox/fritzbox-7390/wissensdatenbank/publication/show/1148_Interne-Rufgruppe-in-FRITZ-Box-einrichten-Gruppenruf/ AVM Interne Rufgruppe anlegen]<br />
<br />
Es muss eine Kurzwahl bei der Gruppe zwingend hinterlegt sein.<br />
Danach kann mit folgendem Beispiel Code gearbeitet werden:<br />
<br />
<code>set FritzBox ring 791 15 show:Türklingel</code><br />
<br />
Name des Devices, Rufgruppen Nummer, Länge und gezeigter Text auf das gewünschte anpassen.<br />
<br />
== Bekannte Probleme / Fehlersuche ==<br />
=== Fehler nach Firmware Update ===<br />
Typischer Fehler ist hier "Error: 403 Forbidden". <br />
Nach einem Firmwareupdate der Fritzbox am besten auch FHEM neu starten.<br />
<br />
=== Modul bleibt im Status "Check APIs" hängen===<br />
Im Log steht die Meldung: "Error: Timeout when reading Fritz!Box data.".<br />
<br />
Mögliche Ursache: Nutzung des FHEM-Befehls [[rereadcfg]]. Dieser verträgt sich nicht mit dem Modul "blocking.pm", das für parallel laufende FHEM-Prozesse genutzt wird.<br />
<br />
Abhilfe schafft ein Neustart <code>shutdown restart</code> oder das Einfügen eines zusätzlichen, lokalen Telnet-Ports z.B. durch <code>define tPortLocal telnet 7073</code><br />
<br />
=== Nachtschaltung Doppel-WLAN ===<br />
Beim Abschalten des WLAN über das Modul wird (über TR064) zuerst das 2.4 GHz und dann das 5 GHz WLAN ausgeschaltet. Bei der gleichzeitigen Nutzung der WLAN-Nachtschaltung (Anschalten über das Fritz!OS) wird dann jedoch nur noch das 5 GHz WLAN wieder angeschaltet. Die Box interpretiert den TR064-Befehl anscheinend als ein komplettes Abwählen des 2.4 GHz WLAN.<br />
<br />
Abhilfe schafft hier nur ein notify auf das 5 GHz WLAN mit einem nachträglichem Anschalten des 2.4 GHz WLAN.<br />
<br />
Alternativ kann das Ausschalten des WLANs nicht direkt über TR064-Kommandos, sondern über einen indirekten Weg erfolgen: über TR064 ein set call abzusetzen und hier den Tastencode zum Ausschalten des WLANs einzugeben, bei einer FritzBox 7490 wäre dies z. B. #96*0*. <br />
Schaltet man über diese Methode das WLAN aus, kann es über die Nachtschaltung wieder automatisch auf beiden Frequenzen angeschaltet werden.<br />
<br />
=== Kabelboxen ===<br />
Bei Fritz!Boxen für den Kabelanschluss (z.B. Kabel Deutschland) scheint neben Telnet auch die TR064-API nicht zu funktionieren. Vermutlich wurde die API von AVM auf Betreiberwunsch deaktiviert, da man sonst Dinge ändern kann, die das gesamte Kabelnetz stören können.<br />
<br />
Zumindest für Unitymedia und einer FRITZ!Box 6490 Cable (lgi) mit FRITZ!OS:06.50 funktioniert TR064. <br />
<br />
Eine Rufumleitung bei Abwesenheit (Modul PRESENCE) funktioniert mit einer vorher eingerichten Telefonnummer wie folgt: <br />
<code>define Rufumleitung DOIF ([Anwesenheit.dum:state] eq "off") (set FritzBox6490 diversity 1 on) DOELSEIF ([Anwesenheit.dum:state] eq "on") (set FritzBox6490 diversity 1 off)</code><br />
<br />
=== Wenn's nicht klingelt ===<br />
Das Klingeln erfolgt über die Wählhilfe. Eventuell muss über die Weboberfläche der Fritz!Box ein anderer Port eingestellt werden. Der aktuelle steht in "box_stdDialPort".<br />
<br />
=== TR064-Transport-Error: 500 Can't connect to ...:49443 (certificate verify failed) ===<br />
Eventuell hilft es, die Perl Module Net::HTTPS, Net::SSL und IO::Socket::SSL zu aktualisieren.<br />
<br />
=== "Error: Old SID not valid anymore." nach Erlauben von IPv6 auf der Fritzbox ===<br />
Ohne hier den genauen Grund zu kennen - es hilft die Angabe der IPv4-Adresse: also statt <code>define FritzBox FRITZBOX</code> dann <code>define FritzBox FRITZBOX <IP></code> (z.B. <code>define FritzBox FRITZBOX 192.168.10.1</code>), so dass das Modul nicht über IPv6 geht.<br />
<br />
=== "Didn't get a session ID" ===<br />
Bei gleichzeitiger Nutzung anderer Modul für die Fritzbox (z.B. {{Link2CmdRef|Anker=FBAHAHTTP|Lang=en|Label=FBAHAHTTP}}) muss der Zugang über Benutzername und Password erfolgen.<br><br />
:<code>attr <DEVICE> boxUser <USER></code><br />
Da das FRITZBOX-Modul eine inoffizielle Schnittstelle benutzt, muss dann auch der normale Zugang zur Box auf "Benutzername und Password" eingestellt sein.<bR><br />
In der Firmware 6.92 wird der Zugang über die Menüs "System"->"Fritz!Box-Benutzer"->"Anmeldung im Heimnetz" eingestellt.<br />
<br />
Oft wird aber auch ein falsches oder gar kein Passwort gesetzt.<br />
<br />
:<code>set <DEVICE> password <PASSWORD></code><br />
<br />
=== TR064-Error 401:invalid action ===<br />
Eventuell ist auf der Fritzbox ein Benutzer gesetzt und im Modul nicht korrekt angegeben bzw. mit falschen Rechten versehen (attribut boxUser).<br />
<br />
== Links ==<br />
* {{Link2Forum|Topic=29725|LinkText=Forenthread}} zu diesem Modul<br />
<br />
[[Kategorie:FritzBox]] <br />
<!-- (Modulkategorie wird automatisch gesetzt) --><br />
<br />
[[Kategorie:Akustische Ausgabe]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=FRITZBOX&diff=31670FRITZBOX2019-11-10T12:18:06Z<p>Amenomade: /* userReadings per get tr064Command oder get luaQuery */ Zu viele ungenaue zeitaufwändige userReadings können Fhem blockieren</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Steuerung einer Fritz!Box über FHEM <br />
|ModType=d<br />
|ModForumArea=FRITZ!Box<br />
|ModTechName=72_FRITZBOX.pm<br />
|ModOwner=tupol/Topos ({{Link2FU|5432|Forum}} / [[Benutzer Diskussion:Topos|Wiki]])}}<br />
<br />
Das Modul [[FRITZBOX]] ermöglicht die Steuerung einer [[AVM Fritz!Box]] und von AVM FRITZ!WLAN Repeatern durch FHEM . An Fritzboxen können sowohl Geräte abgefragt werden, auf denen FHEM selbst läuft (lokaler Modus), als auch entfernte (externe) Geräte.<br />
<br />
== Voraussetzungen ==<br />
=== Remote-Zugang ===<br />
Für den Remote-Zugang müssen die Module JSON:XS, LWP und SOAP::Lite installiert sein; auf einem [[Raspberry Pi]] oder unter Ubuntu z.&nbsp;B. mit dem Befehl<br />
:<code>sudo apt-get install libjson-perl libwww-perl libsoap-lite-perl libjson-xs-perl</code><br />
<br />
Teilweise ist derzeit zusätzlich die Installation der telnet Libraries erforderlich, auch wenn der Telnet-Zugang nicht genutzt werden soll. Siehe dazu den nachfolgenden Abschnitt.<br />
<br />
=== Telnet ===<br />
Das Modul basierte ursprünglich auf dem Zugriff auf die Fritzbox per Telnet. Ab FRITZ!OS 6.2x baut AVM den abgekündigten Telnet-Zugang sowie die webcm-Schnittstelle sukzessive zurück bzw. hat dies, je nach Firmware, schon ganz abgestellt (siehe {{Link2Forum|Topic=38586|LinkText=dieses Forenthema}}). Der zukunftssichere Zugriff auf die Fritzbox sollte also per TR-064 erfolgen. Der Vollständigkeit halber und für ältere Firmwareversionen: <br />
<br />
# Wer den Zugang per Telnet (noch) nutzen (kann und) möchte, muss dies zuerst freischalten. Üblicherweise durch Eingabe von #96*7* an einem direkt an der entsprechenden FritzBox angeschlosssenen Telefon<br />
# Auf dem System, auf dem FHEM läuft ([[Systemübersicht#Server|Server]]) muss Telnet installiert sein; auf einem [[Raspberry Pi]] und unter Ubuntu z.&nbsp;B. mit dem Befehl<br />
::<code>sudo apt-get install libnet-telnet-perl</code><br />
<br />
== Installation ==<br />
=== Erste Schritte ===<br />
Zur Erstinstallation reicht ein einfaches <code>define FritzBox FRITZBOX</code>, dieses Modul funktioniert lokal (FHEM auf Fritzbox) sowie per Fernzugriff (FHEM auf einem anderen Server im Netz, siehe nächsten Schritt).<br />
<br />
==== TR-064: Modul FRITZBOX für Zugriff auf einem externen Server einrichten ====<br />
Für den Fernzugriff über TR-064 auf eine oder mehrere Fritzboxen und/oder einen FRITZ!WLAN Repeater sind die folgenden Schritte nötig (für jedes Gerät):<br />
<br />
Fritzbox definieren:<br />
:<code>define FritzBox FRITZBOX</code><br />
<br />
Wenn die Fritzbox nicht unter <nowiki>http://fritz.box</nowiki> erreichbar ist, IP im define setzen:<br />
:<code>define FritzBox FRITZBOX 192.168.168.168</code><br />
192.168.168.168 dabei natürlich durch die passende IP ersetzen... Alternativ kann statt der IP auch der Hostname eingegeben werden.<br />
<br />
Wenn ('''und nur wenn''') das Login auf der Benutzeroberfläche der FritzBox mit User und Passwort (und nicht nur per Passwort) geschieht, den User konfigurieren:<br />
:<code>attr FritzBox boxUser ''Benutzername'' </code><br />
In der Fritzbox muss dann auch "Anmeldung mit FRITZ!Box-Benutzernamen und Kennwort" ausgewählt sein.<br />
<br />
Passwort konfigurieren:<br />
:<code>set FritzBox password ''Passwort''</code> - legt das zugehörige Passwort fest (nur einmal --> gehört nicht in die cfg-Datei) <br />
<br />
Manuelle TR-064 Kommandos erlauben (Das Auslesen der Readings per TR-064 funktioniert auch ohne dieses Attribut.):<br />
:<code>attr FritzBox allowTR064Command 1</code><br />
<br />
==== Telnet: Modul FRITZBOX für Zugriff auf einem externen Server einrichten ====<br />
[[Datei:Screenshot_FritzBox_TelnetUser.png|mini|300px|rechts|Anlegen des Attributs telnetUser]]<br />
Bei Fernzugriff über Telnet sind weitere Schritte nötig:<br />
# Telnet auf der Fritzbox freischalten (Tastenkombination #96*7* am angeschlossenen Telefon (auch FritzFon)<br />
# TelnetUser definieren (wie im Screenshot gezeigt)<br />
# Passwort zum Benutzer auf der Fritzbox definieren<br />
<br />
[[Datei:Screenshot_FritzBox_Passwort.png|mini|300px|rechts|Passwort definieren]]<br />
<br />
(bitte die Buttons {{Taste|set}} und {{Taste|attr}} bei der Definition der jeweiligen Einträge nicht vergessen)<br />
<br />
Wer stattdessen lieber das [[Konfiguration|Befehl-Eingabefeld]] verwendet:<br />
<br />
:<code>define FritzBox FRITZBOX</code><br />
:<code>attr FritzBox telnetUser ''Benutzername'' </code> - legt den Benutzer fest<br />
:<code>set FritzBox password ''Passwort'' </code> - legt das zugehörige Passwort fest<br />
<br />
Wer keinen User konfiguriert hat, kann das Feld "telnetUser" leer lassen.<br />
<br />
Wer sicher gehen möchte, dass auch tatsächlich Telnet und nicht andere Zugriffe benutzt werden, sollte außerdem noch setzen:<br />
<br />
:<code>attr FritzBox forceTelnetConnection 1</code><br />
<br />
=== mögliche Fehlermeldungen ===<br />
Sollte schon bei <code>define FritzBox FRITZBOX</code> die Fehlermeldung kommen, dass dieses Modul nicht existiert, dann bitte prüfen, ob FHEM auf dem aktuellen Stand ist und ggf. [[Update|aktualisieren]].<br />
<br />
Kommt jetzt bei der erneuten Definition die Fehlermeldung <code>Error: Perl modul Net::Telnet is missing on this system</code> bitte wie oben schon erwähnt den Befehl <br />
:<code>sudo apt-get install libnet-telnet-perl</code> <br />
direkt per Telnet/SSH auf dem FHEM-Server ausführen und neu starten.<br />
Sollte alles geklappt haben, seht ihr nun eure Fritzbox und könnt diverse Einstellungen manuell vornehmen und/oder automatisch vornehmen lassen.<br />
<br />
== Anwendung ==<br />
=== Define ===<br />
Siehe {{Link2CmdRef|Lang=de|Anker=FRITZBOXdefine}}<br />
<br />
=== Attribute ===<br />
Siehe {{Link2CmdRef|Lang=de|Anker=FRITZBOXattr}}<br />
<br />
=== TR-064 ===<br />
Die offizielle Programmier-Schnittstelle der Fritz!Box läuft über das Protokoll TR-064.<br />
<br />
mit dem Attribute<br/><br />
<code>attr <device> allowTR064Command 1</code><br/><br />
kann man den Befehl<br/><br />
<code>get <device> tr064Command <service> <control> <action> [[parameterName1 parameterValue1] ...]</code><br/><br />
freischalten und damit auf diese Schnittstelle zugreifen.<br />
<br />
AVM hat die Schnittstellenbeschreibung unter [http://avm.de/service/schnittstellen/] veröffentlicht. Diese wird jedoch nur sehr sporadisch gepflegt.<br><br />
Ein besserer Einstiegspunkt befindet sich auf der Box unter http://fritz.box:49000/tr64desc.xml.<br><br />
Die möglichen TR-064-Aktionen kann man auch über den Befehl <code>get <device> tr064ServiceList</code> auslesen.<br />
<br />
Folgende Service und Controls existieren (für den get-Befehl ''tr064Command'' werden nur die fett formatierten Wörter benötigt)<br />
<br />
{| class="wikitable"<br />
|-<br />
!serviceType!!controlURL!!XML!!Dokument bei AVM<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''DeviceInfo:1'''||/upnp/control/'''deviceinfo'''||[http://fritz.box:49000/deviceinfoSCPD.xml deviceinfoSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/deviceinfoSCPD.pdf deviceinfoSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''DeviceConfig:1'''||/upnp/control/'''deviceconfig'''||[http://fritz.box:49000/deviceconfigSCPD.xml deviceconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/deviceconfigSCPD.pdf deviceconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''Layer3Forwarding:1'''||/upnp/control/'''layer3forwarding'''||[http://fritz.box:49000//layer3forwardingSCPD.xml layer3forwardingSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/layer3forwardingSCPD.pdf layer3forwardingSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''LANConfigSecurity:1'''||/upnp/control/'''lanconfigsecurity'''||[http://fritz.box:49000//lanconfigsecuritySCPD.xml lanconfigsecuritySCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/lanconfigsecuritySCPD.pdf lanconfigsecuritySCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''ManagementServer:1'''||/upnp/control/'''mgmsrv'''||[http://fritz.box:49000//mgmsrvSCPD.xml mgmsrvSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/mgmsrvSCPD.pdf mgmsrvSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''Time:1'''||/upnp/control/'''time'''||[http://fritz.box:49000//timeSCPD.xml timeSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/timeSCPD.pdf timeSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''UserInterface:1'''||/upnp/control/'''userif'''||[http://fritz.box:49000//userifSCPD.xml userifSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/userifSCPD.pdf userifSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_VoIP:1'''||/upnp/control/'''x_voip'''||[http://fritz.box:49000//x_voipSCPD.xml x_voipSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_voipSCPD.pdf x_voipSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_Storage:1'''||/upnp/control/'''x_storage'''||[http://fritz.box:49000//x_storageSCPD.xml x_storageSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_storageSCPD.pdf x_storageSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_OnTel:1'''||/upnp/control/'''x_contact'''||[http://fritz.box:49000//x_contactSCPD.xml x_contactSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_contactSCPD.pdf x_contactSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_WebDAVClient:1'''||/upnp/control/'''x_webdav'''||[http://fritz.box:49000//x_webdavSCPD.xml x_webdavSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_webdavSCPD.pdf x_webdavSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_UPnP:1'''||/upnp/control/'''x_upnp'''||[http://fritz.box:49000//x_upnpSCPD.xml x_upnpSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_upnp.pdf x_upnp.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_RemoteAccess:1'''||/upnp/control/'''x_remote'''||[http://fritz.box:49000/x_remoteSCPD.xml x_remoteSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_remoteSCPD.pdf x_remoteSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_MyFritz:1'''||/upnp/control/'''x_myfritz'''||[http://fritz.box:49000/x_myfritzSCPD.xml x_myfritzSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_myfritzSCPD.pdf x_myfritzSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_TAM:1'''||/upnp/control/'''x_tam'''||[http://fritz.box:49000/x_tamSCPD.xml x_tamSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_tam.pdf x_tam.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_AppSetup:1'''||/upnp/control/'''x_appsetup'''||[http://fritz.box:49000/x_homeautoSCPD.xml x_homeautoSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_appsetupSCPD.pdf x_appsetupSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''X_AVM-DE_Homeauto:1'''||/upnp/control/'''x_homeauto'''||[http://fritz.box:49000/x_homeautoSCPD.xml x_homeautoSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/x_homeautoSCPD.pdf x_homeautoSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WLANConfiguration:1'''||/upnp/control/'''wlanconfig1'''||[http://fritz.box:49000/wlanconfigSCPD.xml wlanconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wlanconfigSCPD.pdf wlanconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WLANConfiguration:2'''||/upnp/control/'''wlanconfig2'''||[http://fritz.box:49000/wlanconfigSCPD.xml wlanconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wlanconfigSCPD.pdf wlanconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WLANConfiguration:3'''||/upnp/control/'''wlanconfig3'''||[http://fritz.box:49000/wlanconfigSCPD.xml wlanconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wlanconfigSCPD.pdf wlanconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''Hosts:1'''||/upnp/control/'''hosts'''||[http://fritz.box:49000/hostsSCPD.xml hostsSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/hostsSCPD.pdf hostsSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''LANEthernetInterfaceConfig:1'''||/upnp/control/'''lanethernetifcfg'''||[http://fritz.box:49000/lanifconfigSCPD.xml lanifconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/lanifconfigSCPD.pdf lanifconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''LANHostConfigManagement:1'''||/upnp/control/'''lanhostconfigmgm'''||[http://fritz.box:49000/lanhostconfigmgmSCPD.xml lanhostconfigmgmSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/lanhostconfigmgmSCPD.pdf lanhostconfigmgmSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANCommonInterfaceConfig:1'''||/upnp/control/'''wancommonifconfig1'''||[http://fritz.box:49000/wancommonifconfigSCPD.xml wancommonifconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wancommonifconfigSCPD.pdf wancommonifconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANDSLInterfaceConfig:1'''||/upnp/control/'''wandslifconfig1'''||[http://fritz.box:49000/wandslifconfigSCPD.xml wandslifconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wandslifconfigSCPD.pdf wandslifconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANDSLLinkConfig:1'''||/upnp/control/'''wandsllinkconfig1'''||[http://fritz.box:49000/wandsllinkconfigSCPD.xml wandsllinkconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wandsllinkconfigSCPD.pdf wandsllinkconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANEthernetLinkConfig:1'''||/upnp/control/'''wanethlinkconfig1'''||[http://fritz.box:49000/wanethlinkconfigSCPD.xml wanethlinkconfigSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wanethlinkconfigSCPD.pdf wanethlinkconfigSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANPPPConnection:1'''||/upnp/control/'''wanpppconn1'''||[http://fritz.box:49000/wanpppconnSCPD.xml wanpppconnSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wanpppconnSCPD.pdf wanpppconnSCPD.pdf]<br />
|-<br />
|<nowiki>urn:dslforum-org:service:</nowiki>'''WANIPConnection:1'''||/upnp/control/'''wanipconnection1'''||[http://fritz.box:49000/wanipconnSCPD.xml wanipconnSCPD.xml]||[http://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/wanipconnSCPD.pdf wanipconnSCPD.pdf]<br />
|-<br />
|}<br />
<br />
=== Status-Symbol ===<br />
<code>attr <device> devStateIcon .*on.*off:WLAN_on_gWLAN_off .*on.*on.*:WLAN_on_gWLAN_on WLAN..off.*:WLAN_off</code><br />
<br />
Im Verzeichnis www/images/default müssen die passenden Dateien "WLAN_on_gWLAN_off.png", "WLAN_on_gWLAN_on.png" und "WLAN_off.png" liegen. Wenn die PNGs fehlen, können sie {{Link2Forum|Topic=29725|Message=318113|LinkText=hier}} heruntergeladen werden.<br />
<br />
== Anwendungsbeispiele ==<br />
[[Datei:Screenshot_FritzBox1.png|mini|300px|rechts|FRITZBOX Gerät auf der FHEM Oberfläche]]<br />
Sollte alles geklappt haben, seht ihr nun unter "Unsortiert" den im nebenstehenden Screenshot gezeigten Eintrag für das "Gerät" (hier mit dem Icon "it_router").<br />
<br />
=== TR-064 Beispiele ===<br />
*Box Reboot: <code>get <device> tr064Command DeviceConfig:1 deviceconfig Reboot</code><br />
*Internet Reconnect: <code>get <device> tr064Command WANIPConnection:1 wanipconnection1 ForceTermination</code><br />
*Daten eines Smart-Home-Gerätes auslesen: <code>get <device> tr064Command X_AVM-DE_Homeauto:1 x_homeauto GetGenericDeviceInfos NewIndex 0</code><br />
<br />
=== Klingel- und Sprachausgabe per TR-064 ===<br />
Das geht derzeit nicht, da entsprechende Kommandos per TR-064 nicht verfügbar sind. Da Telnet sukzessive abgestellt wird, sollten sich Interessenten per Feature-Request an AVM wenden, wie {{Link2Forum|Topic=38586|LinkText=hier}} beschrieben.<br />
<br />
Eine Alternative um Telefone klingeln zu lassen, ist die Nutzung des [[SIP-Client]]s.<br />
<br />
=== Anwesenheitserkennung per regelmäßiger Abfrage über das PRESENCE Modul ===<br />
Fritzboxen und die FRITZ!WLAN Repeater speichern den Status angemeldeter Geräte. Dieser Status lässt sich mittels des FRITZBOX Moduls über Readings abfragen, die das Format mac_AA_AA_AA_AA_AA_AA haben und die MAC-Adressen der jeweils angemeldeten Geräte (AA:AA:AA:AA:AA:AA) enthalten. Das Reading existiert, wenn das Gerät angemeldet ist. Wenn das Gerät abgemeldet ist, existiert es nicht mehr. Es gibt auch noch den Zwischenstatus "inactive", der anscheinend gesetzt wird, bevor das Reading gelöscht wird.<br />
<br />
Mit Hilfe des [[PRESENCE]] Moduls (vgl. [[Anwesenheitserkennung]]) kann man auf diese Weise den Anwesenheitsstatus abfragen. Anregungen dazu gibt es im zugehörigen {{Link2Forum|Topic=39433|LinkText=Forenthread}} zur Anwesenheitserkennung und in [http://heinz-otto.blogspot.de/2015/07/die-zeiten-andern-sich.html diesem Blogpost]. Auf dieser Basis könnte eine einfache Implementierung zum Beispiel so aussehen:<br />
<br />
Funktion in [[99_myUtils anlegen|99_myUtils]]:<br />
'''(Bitte beim Speichern darauf achten, dass nicht der Name 99_Utils gewählt wird.)''' <br />
<br />
<syntaxhighlight lang='perl'>sub checkFritzMACpresent($$) {<br />
# Benötigt: Name der zu testenden Fritzbox ($Device),<br />
# zu suchende MAC ($MAC), <br />
# Rückgabe: 1 = Gerät gefunden<br />
# 0 = Gerät nicht gefunden<br />
my ($Device, $MAC) = @_;<br />
my $Status = 0;<br />
$MAC =~ tr/:/_/;<br />
$MAC = "mac_".uc($MAC);<br />
my $StatusFritz = ReadingsVal($Device, $MAC, "weg");<br />
if ($StatusFritz eq "weg") {<br />
Log 1, ("checkFritzMACpresent ($Device): $MAC nicht gefunden, abwesend.");<br />
$Status = 0;<br />
} elsif ($StatusFritz eq "inactive") {<br />
Log 1, ("checkFritzMACpresent ($Device): $MAC ist >inactive<, also abwesend.");<br />
$Status = 0;<br />
} else {<br />
# Reading existiert, Rückgabewert ist nicht "inactive", also ist das Gerät per WLAN angemeldet.<br />
Log 4, ("checkFritzMACpresent ($Device): $MAC gefunden, Gerät heißt >$StatusFritz<.");<br />
$Status = 1;<br />
}<br />
return $Status<br />
}<br />
</syntaxhighlight><br />
<br />
Nutzung dieser Funktion mit dem PRESENCE Modul definieren:<br />
:<code>define <Name> PRESENCE function {checkFritzMACpresent("Fritzbox","AA:BB:CC:DD:EE:FF")} 60 60</code><br />
wobei<br />
*<Name> ein beliebig zu wählender Name für die PRESENCE-Funktion ist,<br />
*Fritzbox der Name ist, mit dem ihr die abzufragende Fritzbox als FRITZBOX definiert habt,<br />
*AA:BB:CC:DD:EE:FF die MAC-Adresse des gesuchten Geräts ist.<br />
* "60 60" sagt, dass der Anwesenheitsstatus im 60-Sekunden-Takt abgefragt wird. Das macht natürlich nur Sinn, wenn ihr mit <code>attr Fritzbox INTERVAL 60</code> den Abfrageinterval bei der Fritzbox auch entsprechend hochgesetzt habt. Der Standard ist 300.<br />
* "Log 1" führt immer zum Loggen. Das ist zum Einrichten praktisch, ohne dass man gleich für das ganze Modul oder ganz FHEM <code>attr <device> verbose 5</code> setzen muss. Wenn es läuft, können die "Log 1"-Zeilen gelöscht, auskommentiert (# an den Zeilenanfang) oder in "Log 5" geändert werden.<br />
<br />
=== Anwesenheitserkennung über mehrere Fritzboxen oder AVM Repeater und Fritzbox ===<br />
Existiert ein AVM Repeater im Netzwerk, kann der als eigenständiges Gerät mit FRITZBOX definiert werden. WLAN Geräte an der Fritzbox werden in der Instanz der Fritzbox gelistet und WLAN Geräte am Repeater in der Repeater Instanz. Um trotzdem die Anwesenheit im Netzwerk einfach zu erkennen, muss die Subroutine in 99_myUtils.pm abgewandelt werden.<br />
<br />
Existiert eine zweite Fritzbox im Accesspointmodus, werden die WLAN Geräte im Netzwerk alle in der Hauptfritzbox an einem LAN Anschluss gelistet. D.h. man sieht an der Hauptfritzbox nicht, dass sie im WLAN sind. Eine zweite Instanz mit dem FRITZBOX Modul muss wegen der Anwesenheitserkennung nicht gemacht werden. Die folgende Routine kann aber universell eingesetzt werden, unabhängig von der Anzahl der FRITZBOX Instanzen. Wer mitloggen will, kann das analog zur obigen Routine einbauen<br />
<br />
<syntaxhighlight lang='perl'>sub checkAllFritzMACpresent($) {<br />
# Benötigt: nur die zu suchende MAC ($MAC), <br />
# Es werden alle Instanzen vom Type FRITZBOX abgefragt<br />
#<br />
# Rückgabe: 1 = Gerät gefunden<br />
# 0 = Gerät nicht gefunden<br />
my ($MAC) = @_;<br />
# Wird in keiner Instanz die MAC Adresse gefunden bleibt der Status 0<br />
my $Status = 0;<br />
$MAC =~ tr/:/_/;<br />
$MAC = "mac_".uc($MAC);<br />
my @FBS = devspec2array("TYPE=FRITZBOX");<br />
foreach( @FBS ) {<br />
my $StatusFritz = ReadingsVal($_, $MAC, "weg");<br />
if ($StatusFritz eq "weg") {<br />
} elsif ($StatusFritz eq "inactive") {<br />
} else {<br />
# Reading existiert, Rückgabewert ist nicht "inactive", also ist das Gerät am Netzwerk angemeldet.<br />
$Status = 1;<br />
}<br />
}<br />
return $Status<br />
}<br />
</syntaxhighlight><br />
<br />
Da hiermit nach allen Instanzen mit dem TYPE=FRITZBOX durchsucht wird, braucht der Name der Fritzbox nicht angegeben werden.<br />
<br />
:<code>define <Name> PRESENCE function {checkAllFritzMACpresent("AA:BB:CC:DD:EE:FF")} 60 60</code><br />
<br />
Die Abfrage auf einen bestimmten Status kann einfach erweitert werden, ist aber immer vom Entwicklunsgstand der Fritzbox Firmware und des FRITZBOX Moduls abhängig. Eventuell erreicht man bessere Reaktionszeiten auf Abwesenheit durch diesen Zusatz:<br />
<syntaxhighlight lang='perl'>my $StatusFritz = ReadingsVal($_, $MAC, "weg");<br />
if ($StatusFritz eq "weg") {<br />
} elsif ($StatusFritz eq "inactive") {<br />
} elsif ($StatusFritz =~ /(.*)s, 0/) { <br />
# Dieser Zweig testet auf "<geraetename> (WLAN, 0 / 0 Mbit/s, 0)"<br />
} else {<br />
$Status = 1;<br />
}<br />
</syntaxhighlight><br />
<br />
Weitere Hinweise zu komplexeren Abfragen mehrere Boxen auf einmal etc. findet ihr auch im diesem {{Link2Forum|Topic=39433|LinkText=Forenthread}}.<br />
<br />
=== Anwesenheitserkennung per Notify ===<br />
Der von Fritzboxen und Fritz!WLAN Repeatern gespeicherte Status zum Status angemeldeter Geräte lässt sich (statt per PRESENCE, s.o.) auch per [[notify]] anfragen:<br />
<br />
<syntaxhighlight lang="perl">define <Name> notify Fritzbox:mac_AA_BB_CC_DD_EE_FF:.* {<br />
if (ReadingsVal("Fritzbox", "mac_AA_BB_CC_DD_EE_FF", "inactive") eq "inactive") <br />
{<br />
fhem("set anwesend_smartphone absent");<br />
} <br />
else <br />
{<br />
fhem("set anwesend_smartphone present");<br />
}<br />
}</syntaxhighlight><br />
<br />
Hinweise:<br />
* <code>fhem("set anwesend_smartphone absent");</code> ist nur ein Beispiel, das einen Dummy auf den Status "absent" bzw. "present" setzt. Man kann hier natürlich auch gleich entsprechende Aktionen durchführen. Wer das Beispiel übernehmen möchte, sollte den Dummy vorher definieren (<code>define anwesend_smartphone dummy</code>).<br />
* mac_AA_BB_CC_DD_EE_FF ist die MAC-Adresse des gesuchten Geräts.<br />
* "Fritzbox" ist der Name, unter dem die Fritzbox als FRITZBOX-Modul definiert wurde.<br />
* Das Notify funktioniert, weil Geräte, wenn sie sich abgemeldet haben, erst den Status "inactive" erhalten. Ist das Gerät ganz abgemeldet, verschwindet das mac_.*-Reading. Dabei löst das Notify nicht mehr aus. Da das mac-.*-Reading aber vorher auf "inactive" stand, wurde die Abwesend-Aktion schon ausgeführt.<br />
* Damit der Notify nicht andauernd losgeht, sollte man mittels <code>attr Fritzbox [[event-on-change-reading]] mac_AA_BB_CC_DD_EE_FF</code> Events nur auslösen, wenn sich der Status des Gerätes ändert. Will man mehrere Geräte abfragen, sollte man <code>attr Fritzbox event-on-change-reading mac_AA_BB_CC_DD_EE_FF,mac_GG_HH_II_JJ_KK_LL</code> setzen, damit bei der Änderung jedes Readings ein Event ausgelöst wird.<br />
<br />
=== Vergleich Anwesenheitserkennung PRESENCE/Notify ===<br />
Die Anwesenheitserkennung per regelmäßiger PRESENCE-Abfrage hat den Vorteil, dass sie im Turnus der regelmäßigen Abfragen immer einen aktuellen Status produziert. Sie hat dafür den Nachteil, dass die PRESENCE-Funktionen regelmäßig abgearbeitet werden müssen, auch wenn sich gar nichts ändert. Außerdem aktualisiert sich der Status nicht sofort, sondern erst bei der nächsten regelmäßigen Abfrage. Durch häufiges Abfragen kann dieser Nachteil verringert werden (bei entsprechend höherer Systemlast).<br />
<br />
Die Anwesenheitserkennung per Notify hat den Vorteil, dass ein sich ändernder Status sofort abgebildet wird. Ändert sich kein Status, werden keine Routinen ausgeführt, was die Systemlast gering hält. Der Nachteil ist, dass - z.B. nach einem Systemstart - die entsprechende Aktion erst bei einer Änderung des Status ausgeführt wird. D.h. ist das zu testende Gerät anwesend, wird dann FHEM beendet, das Gerät entfernt und FHEM wieder gestartet, ist der Status in FHEM immer noch "anwesend". Da das Reading für das Gerät nicht existiert, wird darauf auch erst wieder ein Notify ausgeführt, wenn sich der Status des Geräts wieder ändert, d.h. es wieder ankommt. Bis dahin ist der Status im System falsch. <br />
Der Nachteil des Notify kann verringert werden, wenn man statt <code>attr Fritzbox event-on-change-reading mac_AA_BB_CC_DD_EE_FF</code> ein <code>attr Fritzbox [[event-on-update-reading]] mac_AA_BB_CC_DD_EE_FF</code> setzt. Das erhöht allerdings die Systemlast und funktioniert auch nur für den Status "anwesend". Bei "abwesend" ist kein Reading vorhanden, so dass auch event-on-update-reading nicht ausgeführt wird.<br />
Eine weitere Möglichkeit, den Nachteil der Notify-Methode auszugleichen, ist, die Statusabfrage beim Systemstart einmal manuell auszuführen, durch ein notify auf "GLOBAL:initialized":<br />
<syntaxhighlight lang="perl"><br />
global:INITIALIZED {<br />
Reset_Variables;<br />
if (ReadingsVal("Fritzbox", "mac_AA_BB_CC_DD_EE_FF", "inactive") eq "inactive") {<br />
fhem("set anwesend_smartphone absent");<br />
} else {<br />
fhem("set anwesend_smartphone present");<br />
}<br />
}<br />
</syntaxhighlight><br />
Das hilft allerdings nur beim Systemstart. Nicht, wenn FHEM aufgrund irgendwelcher Hänger eine Aktualisierung des Status verpasst hat.<br />
<br />
=== userReadings per ''get tr064Command'' oder ''get luaQuery'' ===<br />
Um dem Gerätewert <userReadingName> den Wert von <VariabelName> aus der Rückgabe des get-Befehls ''tr064Command'' oder ''luaQuery'' zuzuordnen<br />
<pre><br />
attr <device> userReadings <userReadingName> {my $resp=fhem("get <device> tr064Command <service> <control> <action> [[<argName1> <argValue1>] ...]",1);;$resp =~/\'<VariabelName>\' => '(.*)'/;;return $1;;}<br />
</pre><br />
Beispielsweise<br />
<pre>attr Fritzbox userReadings urMobilteil_1 {my $resp=fhem("get Fritzbox tr064Command X_AVM-DE_OnTel:1 x_contact GetDECTHandsetInfo NewDectID 1",1);;$resp =~/'NewHandsetName' => '(.*)'/;;return $1;;},<br />
urDownstreamDSLRate {my $resp=fhem("get Fritzbox tr064Command WANDSLInterfaceConfig:1 wandslifconfig1 GetInfo",1);;$resp =~/'NewDownstreamCurrRate' => '(.*)'/;;return $1;;},<br />
urUpstreamDSLRate {my $resp=fhem("get Fritzbox tr064Command WANDSLInterfaceConfig:1 wandslifconfig1 GetInfo",1);;$resp =~/'NewUpstreamCurrRate' => '(.*)'/;;return $1;;}</pre><br />
oder bei einzelnen Werte über ''get luaQuery''<pre>attr Fritzbox userReadings sip1_connect {my $resp=fhem("get Fritzbox luaQuery sip:settings/sip1/connect",1);;$resp =~/([0-9])$/;;return $1;;}</pre><br />
<br />
VORSICHT: man sollte einen genaueren Trigger für diese userReadings setzen, sonst wird bei jeder Aktualierung von jedem Reading das get Kommando ausgeführt, was ganz schnell ein (für fhem blockierenden) Dauerlaufer werden kann.<br />
<br />
=== Klingelton-Einstellung und Abspielen von Sprachnachrichten bei Fritz!OS-Versionen >6.24 ===<br />
Wenn die Fritzbox weder die Telnet- noch die webcmd-Schnittstelle hat, kann der Klingelton der Fritz!Fons nicht mehr verstellt und auch keine Sprachnachricht über ein Fritz!Fon ausgegeben werden.<br />
<br />
Es gibt eine Behelfslösung über das Attribut ''useGuiHack''. Dadurch wird eine Eingabe in die WebGUI der Fritzbox simuliert. <br />
<br />
'''ACHTUNG''': Vor allem nach einem Update der FritzBox kann es durch dieses Attribut zu ungewolltem Verstellen von Werten in der Fritzbox kommen.<br />
<br />
Bei Verwendung der ring-Parameter "play:" und "say:" wird die abzuspielende URL in die M3U-Datei, die unter dem Internal ''M3U_LOCAL'' steht, eingetragen.<br> <br />
Standardmäßig wird versucht, diese Datei im image-Verzeichnis von FHEM abzulegen. Diese kann dann vom Fritz!Fon über [[FHEMWEB]] abgespielt werden (IP-Freigaben beachten). Direkt nach dem ersten Anlegen der m3u-Datei kennt [[FHEMWEB]] diese noch nicht, daher bitte entweder ''set <webdevice> rereadicons'' ausführen oder FHEM neu starten.<br><br />
<br />
Aufgrund der Beschränkungen von [[FHEMWEB]] oder auch bei Authentifizierungsanforderungen ist es empfehlenswert, die Datei über das Attribute ''m3uFileLocal'' selber vorzugeben. Am besten auf einem Webserver, der auf dem FHEM-Server läuft und dessen Seiten-Verzeichnis durch FHEM beschreibbar ist.<br><br />
Beispiel: <code>attr Fritzbox m3uFileLocal /var/www/mp3/Fritzbox.m3u</code><br />
<br />
In dem Radioeintrag ''FHEM'' muss dann '''auf der FritzBox''', die '''Web'''-Adresse der entsprechenden Datei eingetragen werden. Dieser Sender sollte zu Testzwecken dann auch einmal am Fritz!Fon von Hand gestartet werden.<br><br />
Das Modul versucht, beim Start die einzutragende Radio-URL im image-Verzeichnis selber zu ermitteln (IP-Freigabe beachten). Gelingt dies, so steht diese im Internal ''M3U_URL''.<br />
<br />
=== Ring auf mehreren Telefonen gleichzeitig ===<br />
<br />
Damit mehrere Telefone per ring gleichzeitig Klingel, muss in der Fritzbox eine Rufgruppe definiert werden.<br />
Sollte eine Türsprechanlage schon in Benutzung sein, kann die eventuell hierfür bereits eingerichtete Gruppe verwendet werden.<br />
Das anlegen der Gruppe erfolgt wie in folgender AVM Anleitung erledigt werden. [https://avm.de/service/fritzbox/fritzbox-7390/wissensdatenbank/publication/show/1148_Interne-Rufgruppe-in-FRITZ-Box-einrichten-Gruppenruf/ AVM Interne Rufgruppe anlegen]<br />
<br />
Es muss eine Kurzwahl bei der Gruppe zwingend hinterlegt sein.<br />
Danach kann mit folgendem Beispiel Code gearbeitet werden:<br />
<br />
<code>set FritzBox ring 791 15 show:Türklingel</code><br />
<br />
Name des Devices, Rufgruppen Nummer, Länge und gezeigter Text auf das gewünschte anpassen.<br />
<br />
== Bekannte Probleme / Fehlersuche ==<br />
=== Fehler nach Firmware Update ===<br />
Typischer Fehler ist hier "Error: 403 Forbidden". <br />
Nach einem Firmwareupdate der Fritzbox am besten auch FHEM neu starten.<br />
<br />
=== Modul bleibt im Status "Check APIs" hängen===<br />
Im Log steht die Meldung: "Error: Timeout when reading Fritz!Box data.".<br />
<br />
Mögliche Ursache: Nutzung des FHEM-Befehls [[rereadcfg]]. Dieser verträgt sich nicht mit dem Modul "blocking.pm", das für parallel laufende FHEM-Prozesse genutzt wird.<br />
<br />
Abhilfe schafft ein Neustart <code>shutdown restart</code> oder das Einfügen eines zusätzlichen, lokalen Telnet-Ports z.B. durch <code>define tPortLocal telnet 7073</code><br />
<br />
=== Nachtschaltung Doppel-WLAN ===<br />
Beim Abschalten des WLAN über das Modul wird (über TR064) zuerst das 2.4 GHz und dann das 5 GHz WLAN ausgeschaltet. Bei der gleichzeitigen Nutzung der WLAN-Nachtschaltung (Anschalten über das Fritz!OS) wird dann jedoch nur noch das 5 GHz WLAN wieder angeschaltet. Die Box interpretiert den TR064-Befehl anscheinend als ein komplettes Abwählen des 2.4 GHz WLAN.<br />
<br />
Abhilfe schafft hier nur ein notify auf das 5 GHz WLAN mit einem nachträglichem Anschalten des 2.4 GHz WLAN.<br />
<br />
Alternativ kann das Ausschalten des WLANs nicht direkt über TR064-Kommandos, sondern über einen indirekten Weg erfolgen: über TR064 ein set call abzusetzen und hier den Tastencode zum Ausschalten des WLANs einzugeben, bei einer FritzBox 7490 wäre dies z. B. #96*0*. <br />
Schaltet man über diese Methode das WLAN aus, kann es über die Nachtschaltung wieder automatisch auf beiden Frequenzen angeschaltet werden.<br />
<br />
=== Kabelboxen ===<br />
Bei Fritz!Boxen für den Kabelanschluss (z.B. Kabel Deutschland) scheint neben Telnet auch die TR064-API nicht zu funktionieren. Vermutlich wurde die API von AVM auf Betreiberwunsch deaktiviert, da man sonst Dinge ändern kann, die das gesamte Kabelnetz stören können.<br />
<br />
Zumindest für Unitymedia und einer FRITZ!Box 6490 Cable (lgi) mit FRITZ!OS:06.50 funktioniert TR064. <br />
<br />
Eine Rufumleitung bei Abwesenheit (Modul PRESENCE) funktioniert mit einer vorher eingerichten Telefonnummer wie folgt: <br />
<code>define Rufumleitung DOIF ([Anwesenheit.dum:state] eq "off") (set FritzBox6490 diversity 1 on) DOELSEIF ([Anwesenheit.dum:state] eq "on") (set FritzBox6490 diversity 1 off)</code><br />
<br />
=== Wenn's nicht klingelt ===<br />
Das Klingeln erfolgt über die Wählhilfe. Eventuell muss über die Weboberfläche der Fritz!Box ein anderer Port eingestellt werden. Der aktuelle steht in "box_stdDialPort".<br />
<br />
=== TR064-Transport-Error: 500 Can't connect to ...:49443 (certificate verify failed) ===<br />
Eventuell hilft es, die Perl Module Net::HTTPS, Net::SSL und IO::Socket::SSL zu aktualisieren.<br />
<br />
=== "Error: Old SID not valid anymore." nach Erlauben von IPv6 auf der Fritzbox ===<br />
Ohne hier den genauen Grund zu kennen - es hilft die Angabe der IPv4-Adresse: also statt <code>define FritzBox FRITZBOX</code> dann <code>define FritzBox FRITZBOX <IP></code> (z.B. <code>define FritzBox FRITZBOX 192.168.10.1</code>), so dass das Modul nicht über IPv6 geht.<br />
<br />
=== "Didn't get a session ID" ===<br />
Bei gleichzeitiger Nutzung anderer Modul für die Fritzbox (z.B. {{Link2CmdRef|Anker=FBAHAHTTP|Lang=en|Label=FBAHAHTTP}}) muss der Zugang über Benutzername und Password erfolgen.<br><br />
:<code>attr <DEVICE> boxUser <USER></code><br />
Da das FRITZBOX-Modul eine inoffizielle Schnittstelle benutzt, muss dann auch der normale Zugang zur Box auf "Benutzername und Password" eingestellt sein.<bR><br />
In der Firmware 6.92 wird der Zugang über die Menüs "System"->"Fritz!Box-Benutzer"->"Anmeldung im Heimnetz" eingestellt.<br />
<br />
Oft wird aber auch ein falsches oder gar kein Passwort gesetzt.<br />
<br />
:<code>set <DEVICE> password <PASSWORD></code><br />
<br />
=== TR064-Error 401:invalid action ===<br />
Eventuell ist auf der Fritzbox ein Benutzer gesetzt und im Modul nicht korrekt angegeben bzw. mit falschen Rechten versehen (attribut boxUser).<br />
<br />
== Links ==<br />
* {{Link2Forum|Topic=29725|LinkText=Forenthread}} zu diesem Modul<br />
<br />
[[Kategorie:FritzBox]] <br />
<!-- (Modulkategorie wird automatisch gesetzt) --><br />
<br />
[[Kategorie:Akustische Ausgabe]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=TR%C3%85DFRI&diff=31342TRÅDFRI2019-10-12T21:40:05Z<p>Amenomade: Änderung 31341 von Amenomade (Diskussion) rückgängig gemacht.</p>
<hr />
<div><div style="float:right">{{Infobox Modul<br />
|Name=tradfri<br />
|ModPurpose=Anbindung IKEA TRÅDFRI Gateway<br />
|ModType=d<br />
<!-- |ModCategory= (noch?) nicht verwendet --><br />
|ModCmdRef=tradfri<br />
|ModForumArea=Zigbee<br />
|ModTechName=30_tradfri.pm<br />
|ModOwner=Andre ([http://forum.fhem.de/index.php?action=profile;u=430 Forum] / [[Benutzer Diskussion:justme|Wiki]])<br />
}}<br />
</div><br />
<br />
'''TRÅDFRI''' bzw. '''IKEA Home smart''' ist die Serie smarter Beleuchtungslösungen von IKEA auf ZigBee-Basis , ähnlich Phillips Hue.<br />
<br />
== tradfri ==<br />
<br />
TRÅDFRI (nach Umbenneng jetzt '''IKEA Home smart''') ist die Serie smarter Beleuchtungslösungen von IKEA. Ähnlich von Phillips [[Hue]] gibt es diverse LEDs in Glühbirnenform, LED-Streifen-Treiber, Flächenleuchten, Wandtaster, Bewegungsmelder, Fernbedienung, Dimmer, etc. und alles via Funk gekoppelt. Außerdem ein Gateway, das sich via Ethernetstecker ins heimische LAN einbinden lässt und die Bedienung via IKEA-App auf dem Handy ermöglicht. Daneben ist auch eine Anbindung in FHEM möglich, dazu funktionieren zwei alternative Lösungen:<br />
<br />
<br />
=== IKEA Trådfri Modul ===<br />
IKEA Trådfri Modul (TYPE ''TradfriDevice'' und ''TradfriGateway'', mehr Infos: https://forum.fhem.de/index.php/topic,70653.0.html seit April 2017)<br />
* Erkennt Lampen<br />
* Fernbedienung erscheint zwar in der Geräteliste, lässt sich aber nicht als Gerät anlegen oder Status lesen<br />
<br />
Die Weiterentwicklung des Moduls durch den ursprünglichen Entwickler scheint Stand 07.19 eingestellt. Inwieweit andere am Modul weiter arbeiten ist unklar.<br />
<br />
=== tradfri-fhem Modul ===<br />
tradfri-fhem Modul (TYPE ''HUEDevice'' und ''tradfri'' Gateway, mehr Infos: https://forum.fhem.de/index.php/topic,96125.0.html seit Januar 2019, Beschreibung folgt auf dieser Seite)<br />
* Erkennt Lampen (als [[Hue#HUE-Device|HUE-Device]])<br />
* Erkennt Fernbedienung jedoch zur Zeit Batteriestatus als einziges Reading<br />
* Erstellt (wenn gewünscht) automatisch Gruppen<br />
* Bewegungsmelder scheinen nicht unterstützt<br />
<br />
====Einrichtung in FHEM====<br />
<br />
# node installieren (mindestens version 8)<br />
# sudo npm install -g tradfri-fhem<br />
# <code>define <tradfri> tradfri</code><br />
# <code>attr <tradfri> tradfriFHEM-securityCode <security code></code><br />
<br />
wenn das gateway nicht automatisch erkannt wird:<br />
<code>attr <tradfri> tradfriFHEM-params --ip <ip></code><br />
<br />
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.<br />
<br />
==== HUE-Device ====<br />
Alle auf dem Gateway bekannten Geräte automatisch als [[Hue#HUE-Device|HUEDevice]] in FHEM angelegt:<br />
* Lampen, Stecker, Trafos, ...<br />
: Hiermit werden die einzelnen Leuchten gesteuert<br />
* Gruppen<br />
: Hiermit lassen sich ganze Gruppen und Räume steuern<br />
* Fernbedienungen<br />
: aktuell gibt es nur ein Battery-Reading<br />
<br />
==== Darstellung im Webfrontend ====<br />
Wenn man die SVG Icons verwendet ist es sinnvoll, das Attribut color-icons zu setzen. Mit <code>attr HUEDevice1 color-icons 2</code> werden z.B. die Farben und der Dimmzustand der Lampe als Icon dargestellt.<br />
Damit das ganze funktioniert, müsst ihr auch noch das <code>attr WEB iconPath fhemSVG:openautomation:default</code> setzen.<br />
<br />
== Links ==<br />
<br />
Githubeintrag über Einstellung der Feature-Entwicklung des IKEA Trådfri Moduls[https://github.com/peterkappelt/Tradfri-FHEM/issues/16#issuecomment-445461242 GITHUB].<br />
[[Kategorie:ZigBee]]<br />
[[Kategorie:Lichteffektgeräte]]<br />
[[Kategorie:IP Components]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=TR%C3%85DFRI&diff=31341TRÅDFRI2019-10-12T21:38:05Z<p>Amenomade: /* IKEA Trådfri Modul */ wird doch weiter entwickelt</p>
<hr />
<div><div style="float:right">{{Infobox Modul<br />
|Name=tradfri<br />
|ModPurpose=Anbindung IKEA TRÅDFRI Gateway<br />
|ModType=d<br />
<!-- |ModCategory= (noch?) nicht verwendet --><br />
|ModCmdRef=tradfri<br />
|ModForumArea=Zigbee<br />
|ModTechName=30_tradfri.pm<br />
|ModOwner=Andre ([http://forum.fhem.de/index.php?action=profile;u=430 Forum] / [[Benutzer Diskussion:justme|Wiki]])<br />
}}<br />
</div><br />
<br />
'''TRÅDFRI''' bzw. '''IKEA Home smart''' ist die Serie smarter Beleuchtungslösungen von IKEA auf ZigBee-Basis , ähnlich Phillips Hue.<br />
<br />
== tradfri ==<br />
<br />
TRÅDFRI (nach Umbenneng jetzt '''IKEA Home smart''') ist die Serie smarter Beleuchtungslösungen von IKEA. Ähnlich von Phillips [[Hue]] gibt es diverse LEDs in Glühbirnenform, LED-Streifen-Treiber, Flächenleuchten, Wandtaster, Bewegungsmelder, Fernbedienung, Dimmer, etc. und alles via Funk gekoppelt. Außerdem ein Gateway, das sich via Ethernetstecker ins heimische LAN einbinden lässt und die Bedienung via IKEA-App auf dem Handy ermöglicht. Daneben ist auch eine Anbindung in FHEM möglich, dazu funktionieren zwei alternative Lösungen:<br />
<br />
<br />
=== IKEA Trådfri Modul ===<br />
IKEA Trådfri Modul (TYPE ''TradfriDevice'' und ''TradfriGateway'', mehr Infos: https://forum.fhem.de/index.php/topic,70653.0.html seit April 2017)<br />
* Erkennt Lampen<br />
* Fernbedienung erscheint zwar in der Geräteliste, lässt sich aber nicht als Gerät anlegen oder Status lesen<br />
<br />
=== tradfri-fhem Modul ===<br />
tradfri-fhem Modul (TYPE ''HUEDevice'' und ''tradfri'' Gateway, mehr Infos: https://forum.fhem.de/index.php/topic,96125.0.html seit Januar 2019, Beschreibung folgt auf dieser Seite)<br />
* Erkennt Lampen (als [[Hue#HUE-Device|HUE-Device]])<br />
* Erkennt Fernbedienung jedoch zur Zeit Batteriestatus als einziges Reading<br />
* Erstellt (wenn gewünscht) automatisch Gruppen<br />
* Bewegungsmelder scheinen nicht unterstützt<br />
<br />
====Einrichtung in FHEM====<br />
<br />
# node installieren (mindestens version 8)<br />
# sudo npm install -g tradfri-fhem<br />
# <code>define <tradfri> tradfri</code><br />
# <code>attr <tradfri> tradfriFHEM-securityCode <security code></code><br />
<br />
wenn das gateway nicht automatisch erkannt wird:<br />
<code>attr <tradfri> tradfriFHEM-params --ip <ip></code><br />
<br />
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.<br />
<br />
==== HUE-Device ====<br />
Alle auf dem Gateway bekannten Geräte automatisch als [[Hue#HUE-Device|HUEDevice]] in FHEM angelegt:<br />
* Lampen, Stecker, Trafos, ...<br />
: Hiermit werden die einzelnen Leuchten gesteuert<br />
* Gruppen<br />
: Hiermit lassen sich ganze Gruppen und Räume steuern<br />
* Fernbedienungen<br />
: aktuell gibt es nur ein Battery-Reading<br />
<br />
==== Darstellung im Webfrontend ====<br />
Wenn man die SVG Icons verwendet ist es sinnvoll, das Attribut color-icons zu setzen. Mit <code>attr HUEDevice1 color-icons 2</code> werden z.B. die Farben und der Dimmzustand der Lampe als Icon dargestellt.<br />
Damit das ganze funktioniert, müsst ihr auch noch das <code>attr WEB iconPath fhemSVG:openautomation:default</code> setzen.<br />
<br />
== Links ==<br />
<br />
Githubeintrag über Einstellung der Feature-Entwicklung des IKEA Trådfri Moduls[https://github.com/peterkappelt/Tradfri-FHEM/issues/16#issuecomment-445461242 GITHUB].<br />
[[Kategorie:ZigBee]]<br />
[[Kategorie:Lichteffektgeräte]]<br />
[[Kategorie:IP Components]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=HM-RC-2-PBU-FM_Unterputz-Wandsender&diff=30695HM-RC-2-PBU-FM Unterputz-Wandsender2019-06-06T20:04:27Z<p>Amenomade: Korrektur ELV Link</p>
<hr />
<div>{{Infobox Hardware<br />
|Bild=HM-RC-2-PBU-FM.JPG<br />
|Bildbeschreibung=Vorderseite des HM-RC-2-PBU-FM<br />
|HWProtocol=BidCoS ([[HomeMatic]])<br />
|HWType=[[HomeMatic Type Remote|remote]]<br />
|HWCategory=[[:Kategorie:Schalter (Sender)|Schalter (Sender)]]<br />
|HWComm=868,3&nbsp;MHz<br />
|HWChannels=2<br />
|HWVoltage=230&nbsp;V<br />
|HWPowerConsumption=0,22&nbsp;W (Ruhebetrieb)<br />
|HWPoweredBy=Netz<br />
|HWSize=71x71x37 mm<br />
|HWDeviceFHEM=[[CUL_HM]]<br />
|HWManufacturer=ELV / eQ-3 <br />
}}<br />
<br />
Der [[HM-RC-2-PBU-FM Unterputz-Wandsender]] ist ein 2-Kanal-Sender zur Unterputz-Montage, der sich in Schalterprogramme einiger Hersteller integrieren lässt. Aus Sicht von FHEM verhält er sich wie eine [[HomeMatic Type Remote|Fernbedienung]] mit zwei Tasten.<br />
<br />
== Hinweise zur Hardware-Installation ==<br />
<br />
* Zur Integration in ein bestehendes Schalterprogramm bitte den entsprechenden Adapter mit bestellen.<br />
* Der HM-RC-2-PBU-FM besitzt nur Anschlüsse für Phase (L) und Neutralleiter (N). Diese können ''nicht'' durch das Gerät "durchgeschleift" werden, das heißt für weitere Verbraucher muss gegebenenfalls Platz für eine Wagoklemme oder ähnliches eingeplant werden. 40mm-tiefe Schalterdosen sind dafür ''sehr'' knapp bemessen.<br />
<br />
<gallery><br />
Datei:HM-RC-2-PBU-FM (Rueckseite).JPG|Rückseite<br />
</gallery><br />
<br />
== Links ==<br />
<br />
* [https://files.elv.com/Assets/Produkte/14/1422/142237/Downloads/142237_um.pdf Bedienungsanleitung] (PDF)<br />
<br />
[[Kategorie:HomeMatic Components]]<br />
[[Kategorie:Schalter (Sender)]]<br />
[[Kategorie:868MHz]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=HTTPMOD&diff=29905HTTPMOD2019-03-14T18:25:53Z<p>Amenomade: /* Links */ weitere Beispiele</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Extract information from devices with an HTTP interface (or, more generic, from any URL) or send information to such devices <br />
|ModType=d<br />
|ModCmdRef=HTTPMOD<br />
|ModForumArea=Sonstiges<br />
|ModTechName=98_HTTPMOD.pm<br />
|ModOwner=StefanStrobel ({{Link2FU|3960|Forum}} / [[Benutzer:StefanStrobel|Wiki]])<br />
}}<br />
<br />
HTTPMOD provides a generic way to retrieve information from devices with an HTTP Interface and store them in Readings or send information to such devices. It queries a given URL with Headers and data defined by attributes. <br />
<br />
From the HTTP response it extracts readings named in attributes using Regexes, JSON or XPath parsing also defined by attributes.<br />
<br />
In an advanced [[Konfiguration|configuration]] the module can also send information to devices. To do this, a generic <code>set</code> option can be configured using attributes. <br />
<br />
== Availability == <br />
The module is part of the regular FHEM distribution.<br />
<br />
== Prerequisites ==<br />
This module uses the non blocking HTTP function <code>HttpUtils_NonblockingGet</code> provided by FHEM's [[HttpUtils]] in a new version published in December 2013.<br />
If not already installed in your environment, please [[update]] FHEM or install it manually using appropriate commands from your environment.<br />
Please also note that FHEM HttpUtils need the global attribute dnsServer to be set in order to work really non blocking even when dns requests can not be answered.<br />
<br />
== Define ==<br />
<syntaxhighlight lang="perl"><br />
define <name> HTTPMOD <URL> <Interval><br />
</syntaxhighlight><br />
The module connects to the given <code>URL</code> every <code>Interval</code> seconds, sends optional headers and data and then parses the response with regular expressions, xpath or json to set readings.<br />
<br />
URL can be "none" and Interval can be 0 if you prefer to only query data with a get command and not in a defined interval.<br />
<br />
Example:<br />
<syntaxhighlight lang="perl"><br />
define PM HTTPMOD http://MyPoolManager/cgi-bin/webgui.fcgi 60<br />
</syntaxhighlight><br />
<br />
== Set-Commands ==<br />
can be defined using attributes, see advanced configuration<br />
<br />
If you set the attribute enableControlSet to 1, the following additional built in set commands are available:<br />
;interval<br />
:set new interval time in seconds and restart the timer<br />
;reread<br />
:request the defined URL and try to parse it just like the automatic update would do it every Interval seconds without modifying the running timer.<br />
;stop<br />
:stop interval timer.<br />
;start<br />
:restart interval timer to call GetUpdate after interval seconds<br />
;upgradeAttributes<br />
:convert outdated attributes for older HTTPMOD-Versions that are still defined for this device from the old syntax to the new one.<br />
:attributes with the description "this attribute should not be used anymore" or similar will be translated to the new syntax, e.g. readingsName1 to reading01Name.<br />
;storeKeyValue<br />
:stores a key value pair in an obfuscated form in the file system. Such values can then be used in replacements where the mode is "key" e.g. to avoid storing passwords in the configuration in clear text<br />
<br />
== Get-Commands ==<br />
can be defined using attributes, see advanced configuration<br />
<br />
== simple Attributes ==<br />
;enableControlSet<br />
:enables the built in set commands ''interval'', ''stop'', ''start'', ''reread'', ''upgradeAttributes'', ''storeKeyValue''<br />
<br />
;enableCookies<br />
:enables the cookie handling inside HTTPMOD. It is advisable to always set this attribute and allow HTTPMOD to track the state of cookies and set them for following HTTP-requests<br />
<br />
;enforceGoodReadingNames<br />
:makes sure that HTTPMOD only creates readings that are allowd for Fhem (especially if reading names are dynamically created from JSON object names with extractAllJSON. It is advisable to always set this attribute.<br />
<br />
;handleRedirects<br />
:enables the redirect handling inside HTTPMOD which should be used together with the cookie handling of HTTPMOD. HTTPMOD will then automatically follow redirects from a web server and keep track of cookies at the same time. It is advisable to always set this attribute.<br />
<br />
;requestHeader.* <br />
:Define an additional HTTP Header to set in the HTTP request<br />
<br />
;requestData<br />
:POST Data to be sent in the request. If not defined, it will be a GET request as defined in HttpUtils used by this module<br />
<br />
;reading[0-9]+(-[0-9]+)?Name<br />
:the name of a reading to extract with the corresponding readingRegex<br />
<br />
;reading[0-9]*(-[0-9]+)?OExpr<br />
:defines an expression that is used in an eval to compute the readings value. The raw value will be in the variable $val.<br />
<br />
;reading[0-9]*(-[0-9]+)?OMap<br />
:Output Map. Defines a mapping from raw to visible values like "0:mittig, 1:oberhalb, 2:unterhalb". If specified as readingOMap then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*OMap.<br />
<br />
;reading[0-9]*(-[0-9]+)?Format<br />
:Defines a format string that will be used in sprintf to format a reading value. If specified as readingFormat then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Format.<br />
<br />
;reading[0-9]*(-[0-9]+)?Decode<br />
:defines an encoding to be used in a call to the perl function decode to convert the raw data string read from the device to a reading. This can be used if the device delivers strings in an encoding like cp850 instead of utf8.<br />
<br />
;reading[0-9]*(-[0-9]+)?Encode<br />
:defines an encoding to be used in a call to the perl function encode to convert the raw data string read from the device to a reading. This can be used if the device delivers strings in an encoding like cp850 and after decoding it you want to reencode it to e.g. utf8.<br />
<br />
;reading[0-9]+Regex<br />
:defines the regex to be used for extracting the reading. The value to extract should be in a capture group / sub expression <br />
:e.g. ([\d\.]+) in the above example. Multiple capture groups will create multiple readings (see explanation above)<br />
<br />
;reading[0-9]+XPath<br />
:defines an xpath to one or more readings when parsing HTML data (see examples below)<br />
<br />
;reading[0-9]+XPath-Strict<br />
:defines an xpath to one or more readings when parsing XML data (see examples below)<br />
<br />
;reading[0-9]+JSON<br />
:defines a path to the JSON object wanted by concatenating the object names with an underscore as delimiter (see the example below)<br />
<br />
;noShutdown<br />
:pass the noshutdown flag to HTTPUtils for webservers that need it (some embedded webservers only deliver empty pages otherwise)<br />
<br />
;disable<br />
:stop doing automatic HTTP requests while this attribute is set to 1<br />
<br />
;timeout<br />
:time in seconds to wait for an answer. Default value is 2<br />
<br />
;do_not_notify<br />
<br />
;readingFnAttributes<br />
<br />
== Simple Configuration of HTTP Devices ==<br />
If your device expects special HTTP-headers then specify them as <code>attr requestHeader1</code> to <code>attr requestHeaderX</code>.<br />
If your Device expects an HTTP POST instead of HTTP GET then the POST-data can be specified as <code>attr requestData</code>.<br />
To get the readings, specify pairs of <code>attr readingXName</code> and <code>attr readingXRegex</code>, <code>attr readingXXPath</code>, <code>attr readingXXPath-Strict</code> or <code>attr readingXJSON</code> to define which readings you want to extract from the HTTP response and how to extract them. (The old syntax <code>attr readingsNameX</code> and <code>attr readingsRegexX</code> is still supported but the new one with <code>attr readingXName</code> and <code>attr readingXRegex</code> should be preferred. The actual values to be extracted have to be sub expressions within () in the regex (see example below)<br />
<br />
=== Example for a PoolManager 5: ===<br />
The PoolManager Web GUI can be queried with HTTP POST Requests like this one:<br />
<br />
<syntaxhighlight lang="perl"><br />
POST /cgi-bin/webgui.fcgi HTTP/1.1<br />
Host: 192.168.70.90<br />
Accept: */*<br />
Content-Type: application/json;charset=UTF-8<br />
Content-Length: 60<br />
<br />
{"get" :["34.4001.value" ,"34.4008.value" ,"34.4033.value"]}<br />
</syntaxhighlight><br />
<br />
The resulting HTTP Response would look like this:<br />
<br />
<syntaxhighlight lang="perl"><br />
HTTP/1.1 200 OK<br />
Content-type: application/json; charset=UTF-8<br />
Expires: 0<br />
Cache-Control: no-cache<br />
Date: Sun, 12 Jan 2014 12:23:11 GMT<br />
Server: lighttpd/1.4.26<br />
Content-Length: 179<br />
<br />
{<br />
"data": {<br />
"34.4001.value": "7.00",<br />
"34.4008.value": "0.52",<br />
"34.4033.value": "24.8"<br />
},<br />
"status": {<br />
"code": 0<br />
},<br />
"event": {<br />
"type": 1,<br />
"data": "48.30000.0"<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
To configure HTTPMOD for a PoolManager one would first define a PoolManager device with e.g. the name PM, the URL and an interval of e.g. 60 seconds. <br />
<br />
Then the data to be sent in the request needs to be defined because in this example the device expects a POST request so the query is not contained in the URL but in the request data.<br />
<br />
Also as seen above the device expects special HTTP headers in the request so these headers also need to be defined as <code>attr PM requestHeader1</code> and <code>attr PM requestHeader2</code><br />
<br />
Then the names of the readings to be extracted would be set with attributes<br />
<br />
Then for each reading value to be extracted a regular expression needs to be set that will match the value in question within ().<br />
<br />
Example:<br />
<syntaxhighlight lang="perl"><br />
define PM HTTPMOD http://MyPoolManager/cgi-bin/webgui.fcgi 60<br />
<br />
attr PM enableControlSet 1<br />
attr PM enableCookies 1<br />
attr PM enforceGoodReadingNames 1<br />
attr PM handleRedirects 1<br />
<br />
attr PM reading01Name PH<br />
attr PM reading01Regex 34.4001.value":[ \t]+"([\d\.]+)"<br />
<br />
attr PM reading02Name CL<br />
attr PM reading02Regex 34.4008.value":[ \t]+"([\d\.]+)"<br />
<br />
attr PM reading03Name3TEMP<br />
attr PM reading03Regex 34.4033.value":[ \t]+"([\d\.]+)"<br />
<br />
attr PM requestData {"get" :["34.4001.value" ,"34.4008.value" ,"34.4033.value", "14.16601.value", "14.16602.value"]}<br />
attr PM requestHeader1 Content-Type: application/json<br />
attr PM requestHeader2 Accept: */*<br />
attr PM stateFormat {sprintf("%.1f Grad, PH %.1f, %.1f mg/l Chlor", ReadingsVal($name,"TEMP",0), ReadingsVal($name,"PH",0), ReadingsVal($name,"CL",0))}<br />
</syntaxhighlight><br />
<br />
=== Example for AmbientMonitor ===<br />
AmbientMonitor is a webbased visualisation for sensors connected to an Arduino device. Its web interface can also be queried with HTTMOD to grab the data into readings.<br />
<br />
This example was provided by locutus. The hardware configuration is an Arduino + Ethercard with ENC28J60 Controller + DHT22 Sensor and software can be downloaded from https://github.com/lucadentella/AmbientMonitor<br />
<br />
In this example an HTTP GET is sufficent, so no <code>requestData</code> is needed. The device provides temperature and humidity readings in an HTTP response that looks like:<br />
<syntaxhighlight lang="perl"><br />
HTTP/1.0 200 OK <br />
Content-Type: text/html <br />
<br />
myCB({'temperature':22.00,'humidity':46.00})<br />
</syntaxhighlight><br />
<br />
the definition could be:<br />
<syntaxhighlight lang="perl"><br />
define AmbientMonitor HTTPMOD http://192.168.1.221/?callback=? 300<br />
<br />
attr AmbientMonitor enableControlSet 1<br />
attr AmbientMonitor enableCookies 1<br />
attr AmbientMonitor enforceGoodReadingNames 1<br />
attr AmbientMonitor handleRedirects 1<br />
<br />
attr AmbientMonitor requestHeader Content-Type: application/json<br />
attr AmbientMonitor reading1Name Temperatur<br />
attr AmbientMonitor reading1Regex temperature':([\d\.]+)<br />
attr AmbientMonitor reading2Name Feuchtigkeit<br />
attr AmbientMonitor reading2Regex humidity':([\d\.]+)<br />
attr AmbientMonitor stateFormat {sprintf("Temperatur %.1f C, Feuchtigkeit %.1f %", ReadingsVal($name,"Temperatur",0), ReadingsVal($name,"Feuchtigkeit",0))}<br />
</syntaxhighlight><br />
<br />
== formatting and manipulating values / readings ==<br />
Values that are parsed from an HTTP response can be further treated or formatted with the following attributes:<br />
<br />
* <code>(reading|get)[0-9]*(-[0-9]+)?OExpr</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?OMap</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?Format</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?Decode</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?Encode</code><br />
<br />
They can all be specified for an individual reading, for all readings in one match (e.g. if a regular expression has several capture groups) or for all readings in a get command (defined by getXX) or for all readings in the main reading list (defined by readingXX):<br />
<syntaxhighlight lang="perl"><br />
reading01Format %.1f<br />
</syntaxhighlight><br />
<br />
will format the reading with the name specified by the attribute reading01Name to be numerical with one digit after the decimal point.<br />
If the attribute reading01Regex is used and contains several capture groups then the format will be applied to all readings parsed by this regex unless these readings have their own format specified by reading01-1Format, reading01-2Format and so on.<br />
<br />
<syntaxhighlight lang="perl"><br />
reading01-2Format %.1f<br />
</syntaxhighlight><br />
<br />
Can be used in cases where a regular expression specified as reading01regex contains several capture groups or an xpath specified as reading01XPath creates several readings. <br />
In this case reading01-2Format specifies the format to be applied to the second match.<br />
<br />
<syntaxhighlight lang="perl"><br />
readingFormat %.1f<br />
</syntaxhighlight><br />
<br />
applies to all readings defined by a reading-Attribute that have no more specific format.<br />
<br />
If you need to do some calculation on a raw value before it is used as a reading, you can define the attribute <code>readingOExpr</code>.<br />
It defines a Perl expression that is used in an eval to compute the readings value. The raw value will be in the variable $val.<br />
<br />
Example for an expression:<br />
<syntaxhighlight lang="perl"><br />
attr PM reading03OExpr $val * 10<br />
</syntaxhighlight><br />
Just like in the above example of the readingFormat attributes, readingOExpr and the other following attributes can be applied on several levels.<br />
<br />
To map a numerical value to a name, you can use the readingOMap attribute. <br />
It defines a mapping from raw to visible values like "0:mittig, 1:oberhalb, 2:unterhalb".<br />
<br />
Example for a map:<br />
<syntaxhighlight lang="perl"><br />
attr PM reading02-3OMap 0:kalt, 1:warm, 2:sehr warm<br />
</syntaxhighlight><br />
<br />
To convert character sets, the module can first decode a string read from the device and then encode it again. For example:<br />
<syntaxhighlight lang="perl"><br />
attr PM getDecode UTF-8<br />
</syntaxhighlight><br />
<br />
This applies to all readings defined for Get-Commands.<br />
<br />
== Some help with Regular Expressions ==<br />
{{Randnotiz|RNTyp=y|RNText=Starting with version ''2018-02-10'' the internal that holds the HTTP response is no longer called '''''buf''''' but rather '''''httpbody''''', and it is only displayed when attribute '''''showBody''''' is set to "1".}}<br />
If HTTPMOD seems not to work and the FHEM Logfile contains a message like <br />
:<code>HTTPMOD: Response didn't match Reading ...</code><br />
then you should check if the value you want to extract is read into the internal with the name buf. Internals are visible when you click on the defined HTTPMOD Device. buf is an internal variable that contains the HTTP Response read. If the value is there and you get the mentioned message then probably something is wrong with your regular expression. Please note that buf might contain special characters like newlines but they are not shown in fhemweb. If you are new to regular expressions then the introduction at http://perldoc.perl.org/perlretut.html might be helpful. <br />
<br />
For a typical HTTPMOD use case where you want to extract a number out of a HTTP-Response you can use something like <code>[\d\.]+</code> to match the number itself. The expression matches the number characters (<code>\d</code>) or a <code>.</code> if one of these characters occurs at least once. <br />
<br />
To tell HTTPMOD that the number is what you want to use for the reading, you have to put the expression in between <code>()</code>. A <code>([\d\.]+)</code> alone would match the longest number in the HTTP Response which is very likely not the number you are looking for so you need to add something to the expression to give it a context and define how to find the number that you are looking for.<br />
<br />
If there is a title text before the number or a special text after the number you can put this in the regex. In one of the examples above <code>humidity':([\d\.]+)</code> is looking for the number that immediately follows the text <code>humidity':</code> without any blanks in between.<br />
Be careful if the text you are getting from your device contains special characters like newline. You don't see such special characters in the fhem webinterface as contents of the internal buf but they might cause your regular expression to fail. <br />
<br />
If you have trouble defining a regular expression that matches a certain name, then many complicated characters and then a number, it might be helpful to use a negation in matching like <code>temp[^\d]+([\d\.]).*</code>. In this examle <code>[^\d]+</code> means any character that is not a numerical digit, more than once.<br />
<br />
=== Regular Expressions with multiple capture Groups ===<br />
The regular expressions used in the above example for a Poolmanager will take the value that matches one capture group. This is the part of the regular expression inside (). In the above example "([\d\.]+)" refers to numerical digits or points between double quotation marks. Only the string consiting of digits and points will match inside (). This piece is assigned to the reading.<br />
<br />
You can also use regular expressions that have several capture groups which might be helpful when parsing tables. In this case an attribute like <br />
<br />
<syntaxhighlight lang="perl"><br />
reading02Regex something[ \t]+([\d\.]+)[ \t]+([\d\.]+)<br />
</syntaxhighlight><br />
<br />
could match two numbers. When you specify only one reading02Name like <br />
<syntaxhighlight lang="perl"><br />
reading02Name Temp<br />
</syntaxhighlight><br />
<br />
the name Temp will be used with the extension -1 and -2 thus giving a reading Temp-1 for the first number and Temp-2 for the second. You can also specify individual names for several readings that get parsed from one regular expression with several capture groups by defining attributes <br />
<br />
<syntaxhighlight lang="perl"><br />
reading02-1Name<br />
reading02-2Name<br />
...<br />
</syntaxhighlight><br />
The same notation can be used for formatting attributes like readingXOMap, readingXFormat and so on.<br />
<br />
The usual way to define readings is however to have an individual regular expression with just one capture group per reading as shown in the above example.<br />
<br />
== Parsing JSON ==<br />
<br />
If a webservice delivers data in JSON format, HTTPMOD can directly parse JSON which might be easier in this case than definig regular expressions.<br />
The next example shows the data that can be requested from a Poolmanager with the following partial configuration:<br />
<br />
<syntaxhighlight lang="perl"><br />
define test2 HTTPMOD none 0<br />
attr test2 get01Name Chlor<br />
attr test2 getURL http://192.168.70.90/cgi-bin/webgui.fcgi<br />
attr test2 getHeader1 Content-Type: application/json<br />
attr test2 getHeader2 Accept: */*<br />
attr test2 getData {"get" :["34.4008.value"]}<br />
</syntaxhighlight><br />
<br />
The data in the HTTP response looks like this:<br />
<br />
<syntaxhighlight lang="perl"><br />
{<br />
"data": {<br />
"34.4008.value": "0.25"<br />
},<br />
"status": {<br />
"code": 0<br />
},<br />
"event": {<br />
"type": 1,<br />
"data": "48.30000.0"<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
the classic way to extract the value 0.25 into a reading with the name Chlor with a regex would have been<br />
<syntaxhighlight lang="perl"><br />
attr test2 get01Regex 34.4008.value":[ \t]+"([\d\.]+)"<br />
</syntaxhighlight><br />
<br />
with JSON you can write <br />
<syntaxhighlight lang="perl"><br />
attr test2 get01JSON data_34.4008.value <br />
</syntaxhighlight><br />
which will create a reading with the Name "Chlor" (as shown above) and take the value 0.25 from the JSON string.<br />
<br />
or if you don't care about the naming of your readings, you can simply extract all JSON data with <br />
<syntaxhighlight lang="perl"><br />
attr test2 extractAllJSON<br />
</syntaxhighlight><br />
<br />
which would apply to all data read from this device and create the following readings out of the HTTP response shown above:<br />
<br />
{| class="wikitable"<br />
| data_34.4008.value || 0.25<br />
|-<br />
| event_data || 48.30000.0<br />
|-<br />
| event_type || 1<br />
|-<br />
| status_code || 0<br />
|}<br />
<br />
or you can specify<br />
<syntaxhighlight lang="perl"><br />
attr test2 get01ExtractAllJSON<br />
</syntaxhighlight><br />
which would only apply to all data read as response to the get command defined as get01. <br />
<br />
It might seem very simple at first sight to use extractAllJSON but if you prefer readings with a meaningful name you should instead define these readings with readingXXName and readingXXJSON or getXXName and getXXJSON individually. Of Course it would be possible to create additional user readings outside HTTPMOD but doing calculations, naming and formatting inside HTTPMOD is more efficient.<br />
<br />
=== JSON Lists ===<br />
<br />
imagine the HTTP Response contains:<br />
<br />
<syntaxhighlight lang="perl"><br />
{ "power":"0",<br />
"modes":["Off","SimpleColor","RainbowChase"],<br />
"code1":3,<br />
"code2":4<br />
}<br />
</syntaxhighlight><br />
<br />
then a configuration like <br />
<br />
<syntaxhighlight lang="perl"><br />
attr device reading01JSON modes <br />
attr device reading01Name Mode <br />
</syntaxhighlight><br />
<br />
will create a list of Subreadings just like a regex with multiple matches can create multiple subreadings:<br />
<br />
{| class="wikitable"<br />
| Mode-1 || Off<br />
|-<br />
| Mode-2 || SimpleColor<br />
|-<br />
| Mode-3 || RainbowChase <br />
|}<br />
<br />
if you don't want several subreadings but one reading that contains the list of modes, you can specify a recombine expression:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr device reading01Name Modes <br />
attr device reading01RecombineExpr join ",", @matchlist <br />
</syntaxhighlight><br />
<br />
which will create one reading containing a list:<br />
<br />
{| class="wikitable"<br />
| Modes || Off,SimpleColor,RainbowChase<br />
|}<br />
<br />
JSON parsing specifications also don't Need to match exactly. If there is no exact match for a defined reading, the HTTPMOD will try to Interpret the specification as a regex and look for json object paths that match the specification as a regex. For example:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr device reading01Name CodeElem<br />
attr device reading01JSON code<br />
</syntaxhighlight><br />
<br />
which will create a list of readings:<br />
<br />
{| class="wikitable"<br />
| CodeElem-1|| 3<br />
|-<br />
| CodeElem-2 || 4<br />
|}<br />
<br />
and of course they could also be recombined into one reading with a RecombineExpr Attribute.<br />
<br />
== Parsing http / XML using xpath ==<br />
Another alternative to regex parsing is the use of XPath to extract values from HTTP responses.<br />
The following example shows how XML data can be parsed with XPath-Strict or HTML Data can be parsed with XPath.<br />
Both work similar and the example uses XML Data parsed with the XPath-Strict option:<br />
<br />
If The XML data in the HTTP response looks like this:<br />
<br />
<syntaxhighlight lang="xml"><br />
<root xmlns:foo="http://www.foo.org/" xmlns:bar="http://www.bar.org"><br />
<actors><br />
<actor id="1">Peter X</actor><br />
<actor id="2">Charles Y</actor><br />
<actor id="3">John Doe</actor><br />
</actor><br />
</root><br />
</syntaxhighlight><br />
<br />
with XPath you can write <br />
<syntaxhighlight lang="perl"><br />
attr htest reading01Name Actor<br />
attr htest reading01XPath-Strict //actor[2]/text()<br />
</syntaxhighlight><br />
<br />
This will create a reading with the Name "Actor" and the value "Charles Y".<br />
<br />
Since XPath specifications can define several values / matches, HTTPMOD can also interpret these and store them in multiple readings:<br />
<syntaxhighlight lang="perl"><br />
attr htest reading01Name Actor<br />
attr htest reading01XPath-Strict //actor/text()<br />
</syntaxhighlight><br />
<br />
will create the readings <br />
<br />
{| class="wikitable"<br />
| Actor-1 || Peter X<br />
|-<br />
| Actor-2 || Charles Y<br />
|-<br />
| Actor-3 || John Doe<br />
|}<br />
<br />
== Further replacements of URL, header or post data ==<br />
sometimes it might be helpful to dynamically change parts of a URL, HTTP header or post data depending on existing readings, internals or <br />
perl expressions at runtime. This might be needed to pass further variables to a server, a current date or other things. <br />
<br />
To support this HTTPMOD offers generic replacements that are applied to a request before it is sent to the server. A replacement can be defined with the attributes <br />
<br />
* <code>replacement[0-9]*Regex</code><br />
* <code>replacement[0-9]*Mode</code><br />
* <code>replacement[0-9]*Value</code><br />
* <code>[gs]et[0-9]*Replacement[0-9]*Value</code><br />
<br />
a replacement always replaces a match of a regular expression. <br />
<br />
'''replacement[0-9]*Mode:'''<br />
The way the replacement value is defined can be specified with the replacement mode.<br />
* If the <code>replacement[0-9]*Mode</code> is <code>reading</code>, then the corresponding <code>replacement[0-9]*Value</code> is interpreted as the name of a ''reading'' of the same device or as ''device:reading'' to refer to another device.<br />
* If the <code>replacement[0-9]*Mode</code> is <code>internal</code>, then the corresponding <code>replacement[0-9]*Value</code> is interpreted as the name of an ''internal'' of the same device or as ''device:internal'' to refer to another device.<br />
* If the <code>replacement[0-9]*Mode</code> is <code>text</code>, then the corresponding <code>replacement[0-9]*Value</code> is interpreted as a static text<br />
* If the <code>replacement[0-9]*Mode</code> is <code>expression</code>, then the corresponding <code>replacement[0-9]*Value</code> is evaluated as a perl expression to compute the replacement. Inside such a replacement expression it is possible to refer to capture groups of the replacement regex.<br />
* If the <code>replacement[0-9]*Mode</code> is <code>key</code>, then the module will use a value from a key / value pair that is stored in an obfuscated form in the file system with the set storeKeyValue command. This might be useful for storing passwords.<br />
<br />
<br />
Example:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr mydevice getData {"get" :["%%value%%.value"]}<br />
attr mydevice replacement01Mode text<br />
attr mydevice replacement01Regex %%value%%<br />
<br />
attr mydevice get01Name Chlor<br />
attr mydevice get01Replacement01Value 34.4008<br />
<br />
attr mydevice get02Name Something<br />
attr mydevice get02Replacement01Value 31.4024<br />
<br />
attr mydevice get05Name profile<br />
attr mydevice get05URL http://www.mydevice.local/getprofile?password=%%password%%<br />
attr mydevice replacement02Mode key<br />
attr mydevice replacement02Regex %%password%%<br />
attr mydevice get05Replacement02Value password<br />
</syntaxhighlight> <br />
<br />
defines that <code>%%value%%</code> will be replaced by a static text.<br />
<br />
All Get commands will be HTTP post requests of a similar form. Only the <code>%%value%%</code> will be different from get to get.<br />
The first get will set the reading named Chlor and for the request it will take the generic getData and replace %%value%% with 34.4008.<br />
<br />
A second get will look the same except a different name and replacement value.<br />
<br />
With the command <code>set storeKeyValue password geheim</code> you can store the password geheim in an obfuscated form in the file system. <br />
To use this password and send it in a request you can use the above replacement with mode key. The value password will then refer to the ofuscated string stored with the key password.<br />
<br />
The mode <code>expression</code> allows you to define your own replacement syntax:<br />
<syntaxhighlight lang="perl"> <br />
attr mydevice replacement01Mode expression<br />
attr mydevice replacement01Regex {{([^}]+)}}<br />
attr mydevice replacement01Value ReadingsVal("mydevice", $1, "")<br />
attr mydevice getData {"get" :["{{temp}}.value"]}<br />
</syntaxhighlight> <br />
<br />
In this example any <code><nowiki>{{name}}</nowiki></code> in a URL, header or post data will be passed on to the perl function ReadingsVal <br />
which uses the string between <code><nowiki>{{}}</nowiki></code> as second parameter. This way one defined replacement can be used for many different<br />
readings.<br />
<br />
HTTPMOD has two built in replacements: One for session Ids and another one for the input value in a set command.<br />
The placeholder $sid is always replaced with the internal <code>$hash->{sid}</code> which contains the session id after it is extracted from a previous HTTP response. <br />
If you don't like to use the placeholder $sid then you can define your own replacement for example like:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr mydevice replacement01Mode internal<br />
attr mydevice replacement01Regex %session%<br />
attr mydevice replacement01Value sid<br />
</syntaxhighlight> <br />
<br />
Now the internal <code>$hash->{sid}</code> will be used as a replacement for the placeholder %session%.<br />
<br />
In the same way a value that is passed to a set-command can be put into a request with a user defined replacement. <br />
In this case the internal <code>$hash->{value}</code> will contain the value passed to the set command. <br />
<code>$hash->{value}</code> might even be a string containing several values that could be put into several different positions in a request by using user defined replacements.<br />
<br />
'''Other example : steering a pellet stove from Rika'''<br />
<br />
The stove API of Rika on https://www.rika-firenet.com/web/ delivers a JSON string with all settings and values, and can be piloted with a data string containing all the "set" values at once.<br />
<br />
Delivered JSON on get https://www.rika-firenet.com/api/client/xxxxxxxx/status : (xxxxxxxx must be replaced with the unique stove ID)<br />
<syntaxhighlight lang="perl"><br />
{<br />
"name": "Vorzimmer",<br />
"stoveID": "xxxxxxxxx",<br />
"lastSeenMinutes": 1,<br />
"lastConfirmedRevision": 1504385700,<br />
"controls": {<br />
"revision": 1504385700,<br />
"onOff": true,<br />
"operatingMode": 2,<br />
"heatingPower": 65,<br />
"targetTemperature": 24,<br />
"heatingTimesActive": false,<br />
"heatingTimesActiveForComfort": true,<br />
"setBackTemperature": 18,<br />
"convectionFan1Active": false,<br />
"convectionFan1Level": 0,<br />
"convectionFan1Area": 0,<br />
"convectionFan2Active": false,<br />
"convectionFan2Level": 0,<br />
"convectionFan2Area": 0,<br />
"frostProtectionActive": false,<br />
"frostProtectionTemperature": 5<br />
},<br />
"sensors": {<br />
"statusError": 0,<br />
"statusWarning": 0,<br />
"statusService": 0,<br />
"statusMainState": 1,<br />
"statusSubState": 3,<br />
"statusFrostStarted": false,<br />
"inputFlameTemperature": 21,<br />
"inputRoomTemperature": 21,<br />
"inputExternalRequest": true,<br />
"outputDischargeMotor": 0,<br />
"outputInsertionMotor": 0,<br />
"outputIDFan": 0,<br />
"outputAirFlaps": 0,<br />
"outputIgnition": false,<br />
"parameterStoveTypeNumber": 13,<br />
"parameterVersionMainBoard": 223,<br />
"parameterVersionTFT": 223,<br />
"parameterRuntimePellets": 11,<br />
"parameterRuntimeLogs": 0,<br />
"parameterFeedRateTotal": 17,<br />
"parameterFeedRateService": 683,<br />
"parameterOnOffCycles": 2<br />
},<br />
"stoveType": "DOMO MultiAir",<br />
"stoveFeatures": {<br />
"multiAir1": true,<br />
"multiAir2": true,<br />
"insertionMotor": false,<br />
"airFlaps": false,<br />
"logRuntime": false<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
Data string to send to https://www.rika-firenet.com/api/client/xxxxxxxx/controls in order to set values:<br />
<syntaxhighlight lang="perl"><br />
heatingTimesActiveForComfort=true&frostProtectionTemperature=3&setBackTemperature=18&targetTemperature=24&convectionFan2Level=0&convectionFan2Active=false&convectionFan1Level=0&onOff=true&convectionFan1Active=false&convectionFan2Area=0&revision=1505550101&heatingTimesActive=false&convectionFan1Area=0&frostProtectionActive=false&operatingMode=2&heatingPower=65<br />
</syntaxhighlight><br />
<br />
Code in 99_myUtils.pm:<br />
<syntaxhighlight lang="perl"><br />
use JSON;<br />
...<br />
sub<br />
replaceJSON ($$) {<br />
my ($valToReplace, $value) = @_;<br />
<br />
#$value in the parameters is a default value<br />
#It has to be replaced through the real value nnn passed in the set command "set <device> valToset nnn"<br />
$value = InternalVal("Ofen", "value", $value);<br />
Log3 ("Ofen", 3, "replaceJSON Internalvalue: $value");<br />
<br />
#Force an update to avoid outdated revision number<br />
fhem ("get Ofen revision");<br />
<br />
#Get all the controls as json<br />
my $json = ReadingsVal("Ofen", "controlsJSON","");<br />
Log3 ("Ofen", 3, "replaceJSON configsJSON: $json");<br />
<br />
# When starting FHEM or rereading config, the reading controlsJSON is empty<br />
return if ($json eq ""); <br />
<br />
my $decoded = decode_json($json);<br />
my $result;<br />
for my $key ( keys %$decoded ) {<br />
$result .= "$key=";<br />
if ($key eq $valToReplace) {<br />
$result .= $value."&";<br />
} else {<br />
$result .= $decoded->{$key}."&";<br />
}<br />
}<br />
chop($result); #remove last &<br />
Log3("Ofen", 3, "replaceJSON Result: $result");<br />
return $result;<br />
}<br />
</syntaxhighlight><br />
<br />
Define stove in fhem:<br />
<syntaxhighlight lang="perl"><br />
defmod Ofen HTTPMOD https://www.rika-firenet.com/api/client/xxxxxxxx/status 60<br />
<br />
attr Ofen enableCookies 1<br />
attr Ofen reAuthRegex id="login"|Unauthorized<br />
attr Ofen sid01Data email=xx@xx&password=xx<br />
attr Ofen sid01URL https://www.rika-firenet.com/web/login<br />
<br />
attr Ofen reading01JSON sensors_inputRoomTemperature<br />
attr Ofen reading01Name RaumTemp<br />
attr Ofen reading02JSON controls_setBackTemperature<br />
attr Ofen reading02Name Absenkung<br />
attr Ofen reading03JSON controls_frostProtectionTemperature<br />
attr Ofen reading03Name Frostschutz<br />
attr Ofen reading10Name controlsJSON<br />
attr Ofen reading10Regex (?s)controls.*?({.*?})<br />
<br />
attr Ofen get09Name revision<br />
attr Ofen get09URL https://www.rika-firenet.com/api/client/xxxxxxxx/status<br />
<br />
attr Ofen setURL https://www.rika-firenet.com/api/client/xxxxxxxx/controls<br />
attr Ofen setData {{data}}<br />
attr Ofen replacement01Mode expression<br />
attr Ofen replacement01Regex {{data}}<br />
<br />
attr Ofen set11Name frostProtectionTemperature<br />
attr Ofen set11Replacement01Value replaceJSON("frostProtectionTemperature", 2)<br />
<br />
attr Ofen set12Name targetTemperature<br />
attr Ofen set12Replacement01Value replaceJSON("targetTemperature", 24)<br />
</syntaxhighlight><br />
<br />
A detailed explanation (in german) of the login process can be found here: [https://forum.fhem.de/index.php/topic,76220.msg682514.html#msg682514]<br />
and the explanation of the other parameters here: [https://forum.fhem.de/index.php/topic,76220.msg685710.html#msg685710]<br />
<br />
== replacing reading values when they have not been updated / the device did not respond ==<br />
If a device does not respond then the values stored in readings will keep the same and only their timestamp shows that they are outdated. <br />
If you want to modify reading values that have not been updated for a number of seconds, you can use the attributes<br />
<br />
* <code>(reading|get)[0-9]*(-[0-9]+)?MaxAge</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?MaxAgeReplacementMode</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?MaxAgeReplacement</code><br />
<br />
Every time the module tries to read from a device, it will also check if readings have not been updated <br />
for longer than the <code>MaxAge</code> attributes allow. If readings are outdated, the <code>MaxAgeReplacementMode</code> defines how the affected<br />
reading values should be replaced. <code>MaxAgeReplacementMode</code> can be <code>text</code>, <code>reading</code>, <code>internal</code>, <code>expression</code> or <code>delete</code>.<br />
<br />
<code>MaxAge</code> specifies the number of seconds that a reading should remain untouched before it is replaced. <br />
<br />
<code>MaxAgeReplacement</code> contains either a static text that is used as replacement value or a Perl expression that is evaluated to <br />
give the replacement value. This can be used for example to replace a temperature that has not bee updated for more than 5 minutes <br />
with the string "outdated - was 12": <br />
<syntaxhighlight lang="perl"><br />
attr PM readingMaxAge 300<br />
attr PM readingMaxAgeReplacement "outdated - was " . $val<br />
attr PM readingMaxAgeReplacementMode expression<br />
</syntaxhighlight><br />
The variable <code>$val</code> contains the value of the reading before it became outdated.<br />
<br />
Or to show that a device was offline:<br />
<syntaxhighlight lang="perl"><br />
attr MyLight reading01Name color<br />
attr MyLight reading01JSON result_02_color<br />
attr MyLight reading01MaxAge 300<br />
attr MyLight reading01MaxAgeReplacement "offline"<br />
attr MyLight reading01MaxAgeReplacementMode text<br />
</syntaxhighlight><br />
<br />
<br />
== Note on determining how to send requests to a special device ==<br />
If you don't know which URLs, headers or POST data your web GUI uses, you might try a local proxy like BurpSuite [http://portswigger.net/burp/ BurpSuite] to track requests and responses. This is a tedious task but probably the best way to achieve a successful result. <br />
<br />
Let us consider an example. The Telekom Speedport W724V has a login-site that is famous for being cumbersome. Burp allows to monitor each step in the login procedure. In the case of a speedport the following steps occur:<br />
<br />
First burp shows that a get command is issued<br />
################################################################################################## <br />
GET / HTTP/1.1<br />
Host: speedport.ip<br />
Cache-Control: max-age=0<br />
Upgrade-Insecure-Requests: 1<br />
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36<br />
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8<br />
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4<br />
Cookie: lang=de<br />
Connection: close <br />
In order to mimic the behavior of a real person calling the website HTTPMOD should copy all necessary steps. Host, Cookie and the GET-command are usually necessary. The same cannot be said of the User-Agent because the website can be called from any mobile or desktop computer. <br />
<br />
Then, the speedport will answer with a command that consists of several lines. By going through every line for every step in the login procedure one will finally arrive at the information that is necessary to successfully enter the login of the speedport (in case of the W724V, for example, it is necessary to copy a token called _httoken and to include the referer).<br />
<br />
== Advanced configuration to define a <code>set</code> command and send data to a device ==<br />
<br />
When a set option is defined by attributes, the module will use the value given to the set command and integrate it into an HTTP-Request that sends the value to the device. The definitions for URL, headers and post data can contain the placeholder $val which will be replaced by the value given to the set command.<br />
<br />
This can be as simple as:<br />
<syntaxhighlight lang="perl"><br />
# No cyclic requests and no main URL needed in this example<br />
define MyDevice HTTPMOD none 0<br />
<br />
attr MyDevice set01Name Licht<br />
attr MyDevice set01URL http://192.168.1.22/switch=$val<br />
</syntaxhighlight><br />
<br />
A user command <br />
<syntaxhighlight lang="perl"><br />
set MyDevice Licht 1<br />
</syntaxhighlight><br />
<br />
will be translated into the http GET request<br />
<syntaxhighlight lang="perl"><br />
http://192.168.1.22/switch=1<br />
</syntaxhighlight><br />
<br />
In this example a map would also be helpful, that translates on / off to 0 or 1 and allows the user to select on/of in fhemweb:<br />
<syntaxhighlight lang="perl"><br />
attr MyDevive set01IMap 0:off, 1:on<br />
</syntaxhighlight><br />
This also provides input validation to make sure that only on and off can be used with the set command.<br />
<br />
In more complex Scenarios you might need to login before sending a command and the Login might create a session id that has to be part of further requests either in the URL, in headers or in the post data.<br />
<br />
Extension to the above example for a PoolManager 5 where a set needs a session id in the URL and the values have to be passed in JSON strings as post data:<br />
<syntaxhighlight lang="perl"><br />
attr PM set01Name HeizungSoll<br />
attr PM set01URL http://MyPoolManager/cgi-bin/webgui.fcgi?sid=$sid<br />
attr PM set01Hint 6,10,20,30<br />
attr PM set01Min 6<br />
attr PM set01Max 30<br />
attr PM setHeader1 Content-Type: application/json<br />
attr PM set01Data {"set" :{"34.3118.value" :"$val" }}<br />
</syntaxhighlight><br />
<br />
This example defines a set option with the name HeizungSoll.<br />
By issuing <code>set PM HeizungSoll 10</code> in FHEM, the value 10 will be sent in the defined HTTP<br />
Post to URL <code>http://MyPoolManager/cgi-bin/webgui.fcgi</code> in the Post Data as<br />
<br />
<syntaxhighlight lang="html4strict"><br />
{"set" :{"34.3118.value" :"10" }}<br />
</syntaxhighlight><br />
<br />
The optional attributes set01Min and set01Max define input validations that will be checked in the set function. <br />
The optional attribute set01Hint will define a selection list for the FHEMweb GUI.<br />
<br />
The HTTP response to such a request will be ignored unless you specify the attribute <code>setParseResponse</code> <br />
for all set commands or <code>set01ParseResponse</code> for the set command with number 01.<br />
If the HTTP response to a set command is parsed then this is done like the parsing of responses to get commands and you can use the attributes ending e.g. on Format, Encode, Decode, OMap and OExpr to manipulate / format the values read.<br />
<br />
If a parameter to a set command is not numeric but should be passed on to the device as text, then you can specify the attribute setTextArg. For example: <br />
<syntaxhighlight lang="perl"><br />
attr PM set01TextArg<br />
</syntaxhighlight><br />
<br />
If a set command should not require a parameter at all, then you can specify the attribute NoArg. For example: <br />
<syntaxhighlight lang="perl"><br />
attr PM set03Name On<br />
attr PM set03NoArg<br />
</syntaxhighlight><br />
<br />
== Advanced configuration to create a valid session id that might be necessary ==<br />
In simple cases logging in works with basic authentication. In the case HTTPMOD accepts a username and password as part of the URL in the form <br />
<syntaxhighlight lang="perl"><br />
http://User:Password@192.168.1.18/something<br />
</syntaxhighlight><br />
<br />
However basic auth is seldom used. If you need to fill in a username and password in a HTML form and the session is then managed by a session id, here is how to configure this:<br />
<br />
when sending data to an HTTP-Device in a set, HTTPMOD will replace any <code>$sid</code> in the URL, Headers and Post data with the internal <code>$hash->{sid}</code>. To authenticate towards the device and give this internal a value, you can use an optional multi step login procedure defined by the following attributes: <br />
<br />
* <code>sid[0-9]*URL</code><br />
* <code>sid[0-9]*Data.*</code><br />
* <code>sid[0-9]*Header.*</code><br />
* <code>sid[0-9]*IgnoreRedirects</code><br />
* <code>idRegex</code><br />
* <code>idJSON</code><br />
* <code>idXPath</code><br />
* <code>idXPath-Strict</code><br />
* <code>(get|set|sid)[0-9]*IdRegex</code><br />
* <code>(get|set|sid)[0-9]*IdJSON</code><br />
* <code>(get|set|sid)[0-9]*IdXPath</code><br />
* <code>(get|set|sid)[0-9]*IdXPath-Strict</code><br />
<br />
Each step can have a URL, Headers, Post Data pieces and a Regex to extract a resulting Session ID into <code>$hash->{sid}</code>.<br />
HTTPMOD will create a sorted list of steps (the numbers between sid and URL / Data / Header) and the loop through these steps and send the corresponding requests to the device. For each step a $sid in a Header or Post Data will be replaced with the current content of <code>$hash->{sid}</code>.<br />
<br />
Using this feature, HTTPMOD can perform a forms based authentication and send user name, password or other necessary data to the device and save the session id for further requests.<br />
<br />
To determine when this login procedure is necessary, HTTPMOD will first try to send a request without <br />
doing the login procedure. If the result contains an error that authentication is necessary, then a login is performed. <br />
To detect such an error in the HTTP response, you can again use a regular expression, JSON or XPath, this time with the attributes <br />
<br />
* <code>reAuthRegex</code><br />
* <code>reAuthJSON</code><br />
* <code>reAuthXPath</code><br />
* <code>reAuthXPath-Strict</code><br />
* <code>(get|set)[0-9]*ReAuthRegex</code><br />
* <code>(get|set)[0-9]*ReAuthJSON</code><br />
* <code>(get|set)[0-9]*ReAuthXPath</code><br />
* <code>(get|set)[0-9]*ReAuthXPath-Strict</code><br />
<br />
reAuthJSON or reAuthXPath typically only extract one piece of data from a response. <br />
If the existence of the specified piece of data is sufficent to start a login procedure, then nothing more needs to be defined to detect this situation. <br />
If however the indicator is a status code that contains different values depending on a successful request and a failed request if a new authentication is needed, <br />
then you can combine things like reAuthJSON with reAuthRegex. In this case the regex is only matched to the data extracted by JSON (or XPath). <br />
This way you can easily extract the status code using JSON parsing and then specify the code that means "authentication needed" as a regular expression.<br />
<br />
If for one step not all of the URL, Data or Header Attributes are set, then HTTPMOD tries to use a <br />
<code>sidURL</code>, <code>sidData.*</code> or <code>sidHeader.*</code> Attribute (without the step number after sid). This way parts that are the same for all steps don't need to be defined redundantly.<br />
<br />
=== Example for a multi step login procedure: ===<br />
<syntaxhighlight lang="perl"><br />
attr PM reAuthRegex /html/dummy_login.htm <br />
attr PM sidURL http://192.168.70.90/cgi-bin/webgui.fcgi?sid=$sid<br />
attr PM sidHeader1 Content-Type: application/json<br />
attr PM sid1IDRegex wui.init\('([^']+)'<br />
attr PM sid2Data {"set" :{"9.17401.user" :"fhem" ,"9.17401.pass" :"password" }}<br />
attr PM sid3Data {"set" :{"35.5062.value" :"128" }}<br />
attr PM sid4Data {"set" :{"42.8026.code" :"pincode" }}<br />
</syntaxhighlight><br />
<br />
In this case HTTPMOD detects that a login is necessary by looking for the pattern /html/dummy_login.htm in the HTTP response. <br />
If it matches, it starts a login sequence. In the above example all steps request the same URL. In step 1 only the defined Header is sent in an HTTP get request. The response will contain a session id that is extraced with the regex wui.init\('([^']+)'.<br />
<br />
In the next step this session id is sent in a post request to the same URL where tha post data contains a username and password. The a third and a fourth request follow that set a value and a code. The result will be a valid and authorized session id that can be used in other requests where $sid is part of a URL, header or post data and will be replaced with the session id extracted above.<br />
<br />
In the special case where a session id is set as a HTTP-Cookie (with the header Set-cookie: in the HTTP response) HTTPMOD offers an even simpler way. With the attribute enableCookies a very basic cookie handling mechanism is activated that stores all cookies that the server sends to the HTTPMOD device and puts them back as cookie headers in the following requests.<br />
<br />
For such cases no sidIdRegex and no $sid in a user defined header is necessary.<br />
<br />
== Advanced configuration to define a <code>get</code> and request additional data with its own request from a device ==<br />
<br />
The normal automatic HTTP request that is done repeatedly after the defined interval has elapsed works well in cases where all required readings can be requested in one common HTTP request. If however a device needs individual requests with different URLs or different POST data for each value, then another method is necessary. <br />
For such cases a <code>get</code> option can be defined and the user can either issue FHEM <code>get</code> commands each time he needs the reading or the user can set an attribute to request the reading automatically together with the normal iteration.<br />
For each <code>get</code> option attributes define an individual URL, optional headers, and post data as well as individual regular expressions and formatting options. <br />
<br />
When a get option is defined by attributes, the module allows querying additional values from the device that require individual HTTP-Requests or special parameters to be sent<br />
<br />
Extension to the above example:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr PM get01Name MyGetValue <br><br />
attr PM get01URL http://MyPoolManager/cgi-bin/directory/webgui.fcgi?special=1?sid=$sid <br><br />
attr PM getHeader1 Content-Type: application/json <br><br />
attr PM get01Data {"get" :{"30.1234.value"}} <br><br />
</syntaxhighlight><br />
<br />
This example defines a get option with the name MyGetValue.<br />
By issuing <code>get PM MyGetValue</code> in FHEM, the defined HTTP request is sent to the device.<br />
The HTTP response is then parsed using the same readingXXName and readingXXRegex attributes as above so<br />
additional pairs will probably be needed there for additional values.<br />
<br />
if you prefer to define the parsing and formatting of readings individually per get command, you can use <br />
attributes like get01Regex, get01XPath, get01Format, get01OMap and so on just like for reading01...<br />
<br />
You can also include parameters / values that are passed to the get command in the request just like for set commands.<br />
The placeholder $val will be replaced with the value given to the get command or you can specify your own replacement as described above.<br />
<br />
If the new get parameter should also be queried regularly, you can define the following optional attributes:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr PM get01Poll 1<br />
attr PM get01PollDelay 300<br />
</syntaxhighlight><br />
<br />
The first attribute includes this reading in the automatic update cycle and the second defines an alternative lower update frequency. When the interval defined initially in the define is over and the normal readings are read from the device, the update function will check for additional get parameters that should be included in the update cycle.<br />
<br />
If a PollDelay is specified for a get parameter, the update function also checks if the time passed since it has last read this value is more than the given PollDelay. If not, this reading is skipped and it will be rechecked in the next cycle when interval is over again. So the effective PollDelay will always be a multiple of the interval specified in the initial define.<br />
<br />
Please note that each defined get command that is included in the regular update cycle will create its own HTTP request. So if you want to extract several values from the same request, it is much more efficient to do this by defining readingXXName and readingXXRegex, XPath or JSON attributes and to specify an interval and a URL in the define of the HTTPMOD device. <br />
<br />
Example for a Siemens webserver provided by Lanhydrock:<br />
<syntaxhighlight lang="perl"><br />
define ozw672 HTTPMOD https://192.168.178.8/api/auth/login.json?user=test&pwd=test 300<br />
<br />
attr ozw672 get1Name tempAussen<br />
attr ozw672 get1URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1960<br />
attr ozw672 get1Poll 1<br />
attr ozw672 get1PollDelay 1800<br />
<br />
attr ozw672 get2Name tempAussenGemischt<br />
attr ozw672 get2URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1964<br />
attr ozw672 get2Poll 1<br />
attr ozw672 get2PollDelay 1800<br />
<br />
attr ozw672 get3Name tempTWW<br />
attr ozw672 get3URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1996<br />
attr ozw672 get3Poll 1<br />
<br />
attr ozw672 get4Name tempKesselSoll<br />
attr ozw672 get4URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1910<br />
attr ozw672 get4Poll 1<br />
<br />
attr ozw672 get5Name tempKesselRuecklauf<br />
attr ozw672 get5URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1915<br />
attr ozw672 get5Poll 1<br />
<br />
attr ozw672 get6Name tempKesselRuecklaufSoll<br />
attr ozw672 get6URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1916<br />
attr ozw672 get6Poll 1<br />
<br />
attr ozw672 get7Name anzahlStartsBrenner<br />
attr ozw672 get7URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1927<br />
attr ozw672 get7PollDelay 1800<br />
attr ozw672 get7Poll 1<br />
<br />
attr ozw672 get8Name statusKessel<br />
attr ozw672 get8URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1898<br />
attr ozw672 get8Poll 1<br />
attr ozw672 get8Regex Value": "([a-zA-Zü ]*)"<br />
attr ozw672 get8OMap Aus:0, Nachlauf aktiv:5, Freigegeben für TWW:10, Freigegeben für HK:20, In Teillastbetrieb für TWW:40, In Teillastbetrieb für HK:50, In Betrieb für Trinkwasser:90, In Betrieb für Heizkreis:100<br />
<br />
attr ozw672 getRegex Value": "[ ]*([-.0-9]*)"<br />
<br />
attr ozw672 reAuthRegex .*session not valid.*<br />
attr ozw672 sid1IDRegex .*"(.*-.*-.*-[0-9a-z]*).*<br />
attr ozw672 sid1URL https://192.168.178.8/api/auth/login.json?user=test&pwd=test<br />
</syntaxhighlight><br />
<br />
== All attributes ==<br />
;reading[0-9]+Name<br />
:the name of a reading to extract with the corresponding readingRegex, readingJSON, readingXPath or readingXPath-Strict<br />
:Please note that the old syntax <b>readingsName.*</b> does not work with all features of HTTPMOD and should be avoided. It might go away in a future version of HTTPMOD.<br />
<br />
;(get|set)[0-9]+Name<br />
:Name of a get or set command<br />
:If the HTTP response that is received after the command is parsed with an individual parse option then this name is also used as a reading name. Please note that no individual parsing needs to be defined for a get or set. If no regex, XPath or JSON is specified for the command, then HTTPMOD will try to parse the response using all the defined readingRegex, reading XPath or readingJSON attributes.<br />
<br />
;(get|set|reading)[0-9]+Regex<br />
:If this attribute is specified, the Regex defined here is used to extract the value from the HTTP Response and assign it to a Reading with the name defined in the (get|set|reading)[0-9]+Name attribute.<br />
:If this attribute is not specified for an individual Reading or get or set but without the numbers in the middle, e.g. as getRegex or readingRegex, then it applies to all the other readings / get / set commands where no specific Regex is defined.<br><br />
:The value to extract should be in a capture group / sub expression e.g. ([\d\.]+) in the above example. Multiple capture groups will create multiple readings (see explanation above)<br />
:Using this attribute for a set command (setXXRegex) only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
:Please note that the old syntax <code>readingsRegex.*</code> does not work with all features of HTTPMOD and should be avoided. It might go away in a future version of HTTPMOD.<br />
:If for get or set commands neither a generic Regex attribute without numbers nor a specific (get|set)[0-9]+Regex attribute is specified and also no XPath or JSON parsing specification is given for the get or set command, then HTTPMOD tries to use the parsing definitions for general readings defined in reading[0-9]+Name, reading[0-9]+Regex or XPath or JSON attributes and assigns the Readings that match here.<br />
<br />
;(get|set|reading)[0-9]+RegOpt<br />
:Lets the user specify regular expression modifiers. For example if the same regular expression should be matched as often as possible in the HTTP response, then you can specify RegOpt g which will case the matching to be done as /regex/g<br />
:The results will be trated the same way as multiple capture groups so the reading name will be extended with -number. <br />
:For other possible regular expression modifiers see http://perldoc.perl.org/perlre.html#Modifiers<br />
<br />
;(get|set|reading)[0-9]+XPath<br />
:defines an xpath to one or more values when parsing HTML data (see examples above)<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;get|set|reading[0-9]+XPath-Strict<br />
:defines an xpath to one or more values when parsing XML data (see examples above)<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;(get|set|reading)[0-9]+AutoNumLen<br />
:In cases where a regular expression or an XPath results in multiple results and these results are stored in a common reading name with extension -number, then you can modify the format of this number to have a fixed length with leading zeros. AutoNumLen 3 for example will lead to reading names ending with -001 -002 and so on.<br />
<br />
;(get|set|reading)[0-9]+AlwaysNum<br />
:if set to 1 this attributes forces reading names to end with a -1, -01 (depending on the above described AutoNumLen) even if just one value is parsed.<br />
<br />
;get|set|reading[0-9]+JSON<br />
:defines a path to the JSON object wanted by concatenating the object names. See the above example.<br />
:If you don't know the paths, then start by using extractAllJSON and the use the names of the readings as values for the JSON attribute.<br><br />
:Please don't forget to also specify a name for a reading, get or set. <br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;(get|set|reading)[0-9]*RecombineExpr<br />
:defines an expression that is used in an eval to compute one reading value out of the list of matches.<br />
:This is supposed to be used for regexes or xpath specifications that produce multiple results if only one result that combines them is wanted. The list of matches will be in the variable @matchlist.<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;get[0-9]*CheckAllReadings<br />
:this attribute modifies the behavior of HTTPMOD when the HTTP Response of a get command is parsed. <br><br />
:If this attribute is set to 1, then additionally to the matching of the corresponding get specific regex (get[0-9]*Regex), XPath or JSON attribute also all the reading names and parse definitions defined in Reading[0-9]+Name and Reading[0-9]+Regex, XPath or JSON attributes are checked and if they match, the coresponding Readings are assigned as well.<br />
:Please note that this does not mean that get01CheckAllReadings will cause a get02Regex to be used. Only the corresponding get01Regex will be used but additionally all the readingXYRegex attributes.<br />
:This is automatically done if a get or set command is defined without its own parse attributes.<br />
<br />
;(get|reading)[0-9]*OExpr<br />
:defines an optional expression that is used in an eval to compute / format a readings value after parsing an HTTP response<br />
:The raw value from the parsing will be in the variable $val.<br />
:If specified as readingOExpr then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Expr.<br />
:Please note that the old syntax <b>readingsExpr.*</b> does not work with all features of HTTPMOD and should be avoided. It might go away in a future version of HTTPMOD.<br />
<br />
;(get|reading)[0-9]*Expr<br />
:This is the old syntax for (get|reading)[0-9]*OExpr. It should be replaced by (get|reading)[0-9]*OExpr. The set command upgradeAttributes which becomes visible when the attribute enableControlSet is set to 1, can do this renaming automatically.<br />
<br />
;(get|reading)[0-9]*OMap<br />
:Map that defines a mapping from raw value parsed to visible values like "0:mittig, 1:oberhalb, 2:unterhalb".<br />
:If specified as readingOMap then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Map.<br><br />
:The individual options in a map are separated by a komma and an optional space. Spaces are allowed to appear in a visible value however kommas are not possible.<br />
<br />
;(get|reading)[0-9]*Map<br />
:This is the old syntax for (get|reading)[0-9]*OMap. It should be replaced by (get|reading)[0-9]*OMap. The set command upgradeAttributes which becomes visible when the attribute enableControlSet is set to 1, can do this renaming automatically.<br />
<br />
;(get|set|reading)[0-9]*Format<br />
:Defines a format string that will be used in sprintf to format a reading value.<br />
:If specified without the numbers in the middle e.g. as readingFormat then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Format.<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br><br />
<br />
;(get|set|reading)[0-9]*Decode<br />
:defines an encoding to be used in a call to the perl function decode to convert the raw data string read from the device to a reading. <br />
:This can be used if the device delivers strings in an encoding like cp850 instead of utf8.<br />
:If your reading values contain Umlauts and they are shown as strange looking icons then you probably need to use this feature.<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;(get|set|reading)[0-9]*Encode<br />
:defines an encoding to be used in a call to the perl function encode to convert the raw data string read from the device to a reading. <br />
:This can be used if the device delivers strings in an encoding like cp850 and after decoding it you want to reencode it to e.g. utf8.<br />
:If your reading values contain Umlauts and they are shown as strange looking icons then you probably need to use this feature.<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;(get|set)[0-9]*URL<br />
:URL to be requested for the set or get command. If this option is missing, the URL specified during define will be used.<br />
<br />
;(get|set)[0-9]*Data<br />
:Data to be sent to the device as POST data when the get or set command is executed. if this attribute is not specified, an HTTP GET method will be used instead of an HTTP POST<br />
<br />
;(get|set)[0-9]*NoData<br />
:can be used to override a more generic attribute that specifies POST data for all get or set commands. With NoData no data is sent and therefor the request will be an HTTP GET.<br />
<br />
;(get|set)[0-9]*Header.*<br />
:HTTP Headers to be sent to the device when the set is executed<br />
<br />
;requestHeader.*<br />
:Define an optional additional HTTP Header to set in the HTTP request of the main loop<br />
<br />
;requestData<br />
:optional POST Data to be sent in the request of the main loop. If not defined, it will be an HTTP GET request as defined in HttpUtils which is used by this module<br />
<br />
;get[0-9]+Poll<br />
:if set to 1 the get is executed automatically during the normal update cycle (after the interval provided in the define command has elapsed)<br />
<br />
;get[0-9]+PollDelay<br />
:if the value should not be read in each iteration (after the interval given to the define command), then a minimum delay can be specified with this attribute. This has only an effect if the above Poll attribute has also been set. Every time the update function is called, it checks if since this get has been read the last time, the defined delay has elapsed. If not, then it is skipped this time.<br />
:PollDelay can be specified as seconds or as x[0-9]+ which means a multiple of the interval in the define command.<br />
<br />
;(get|set)[0-9]*TextArg<br />
:For a get command this defines that the command accepts a text value after the option name. By default a get command doesn't accept optional values after the command name. <br />
:If TextArg is specified and a value is passed after the get name then this value can then be used in a request URL, header or data as replacement for $val or in a user defined replacement that uses the internal "value" ($hash->{value}).<br />
:If used for a set command then it defines that the value to be set doesn't require any validation / conversion. <br />
:The raw value is passed on as text to the device. By default a set command expects a numerical value or a text value that is converted to a numeric value using a map.<br />
<br />
;set[0-9]+Min<br />
:Minimum value for input validation. <br />
<br />
;set[0-9]+Max<br />
:Maximum value for input validation. <br />
<br />
;set[0-9]+IExpr<br />
:Perl Expression to compute the raw value to be sent to the device from the input value passed to the set.<br />
<br />
;set[0-9]+Expr<br />
:This is the old syntax for (get|reading)[0-9]*IExpr. It should be replaced by (get|reading)[0-9]*IExpr. The set command upgradeAttributes which becomes visible when the attribute enableControlSet is set to 1, can do this renaming automatically.<br />
<br />
;set[0-9]+IMap<br />
:Map that defines a mapping from raw to input values like "0:mittig, 1:oberhalb, 2:unterhalb". This attribute atomatically creates a hint for FHEMWEB so the user can choose one of the input values.<br />
<br />
;set[0-9]+Map<br />
:This is the old syntax for (get|reading)[0-9]*IMap. It should be replaced by (get|reading)[0-9]*IMap. The set command upgradeAttributes which becomes visible when the attribute enableControlSet is set to 1, can do this renaming automatically.<br />
<br />
;set[0-9]+Hint<br />
:Explicit hint for fhemWEB that will be returned when set ? is seen. Can be used to get a slider or a list of values to choose from.<br />
<br />
;set[0-9]*NoArg<br />
:Defines that this set option doesn't require arguments. It allows sets like "on" or "off" without further values.<br />
<br />
;set[0-9]*ParseResponse<br />
:defines that the HTTP response to the set will be parsed as if it was the response to a get command.<br />
<br />
<br />
;(get|set)[0-9]*URLExpr<br />
:Defines a Perl expression to specify the HTTP Headers for this request. This overwrites any other header specification and should be used carefully only if needed. The original Header is availabe as $old. Typically this feature is not needed and it might go away in future versions of HTTPMOD. Please use the "replacement" attributes if you want to pass additional variable data to a web service. <br />
<br />
;(get|set)[0-9]*DatExpr<br />
:Defines a Perl expression to specify the HTTP Post data for this request. This overwrites any other post data specification and should be used carefully only if needed. The original Data is availabe as $old. Typically this feature is not needed and it might go away in future versions of HTTPMOD. Please use the "replacement" attributes if you want to pass additional variable data to a web service. <br />
<br />
;(get|set)[0-9]*HdrExpr<br />
:Defines a Perl expression to specify the URL for this request. This overwrites any other URL specification and should be used carefully only if needed. The original URL is availabe as $old. Typically this feature is not needed and it might go away in future versions of HTTPMOD. Please use the "replacement" attributes if you want to pass additional variable data to a web service. <br />
<br />
;ReAuthRegex<br />
:regular Expression to match an error page indicating that a session has expired and a new authentication for read access needs to be done. <br />
:This attribute only makes sense if you need a forms based authentication for reading data and if you specify a multi step login procedure based on the sid.. attributes.<br />
:This attribute is used for all requests. For set and get operations you can however specify individual reAuthRegexes with the (get|set)[0-9]*ReAuthRegex attributes.<br />
<br />
;(get|set)[0-9]*ReAuthRegex<br />
:Regex that will detect when a session has expired during a set operation and a new login needs to be performed.<br />
:It works like the global reAuthRegex but is used for set operations.<br />
<br />
;sid[0-9]*URL<br />
:different URLs or one common URL to be used for each step of an optional login procedure. <br />
<br />
;sid[0-9]*IDRegex<br />
:different Regexes per login procedure step or one common Regex for all steps to extract the session ID from the HTTP response<br />
<br />
;sid[0-9]*Data.*<br />
:data part for each step to be sent as POST data to the corresponding URL<br />
<br />
;sid[0-9]*Header.*<br />
:HTTP Headers to be sent to the URL for the corresponding step<br />
<br />
;sid[0-9]*IgnoreRedirects<br />
:Tells the HttpUtils to not follow HTTP Redirects for this Request. Might be needed for some devices that set a session cookie within a 303 Redirect.<br />
<br />
;clearSIdBeforeAuth<br />
:will set the session id to "" before doing the authentication steps<br />
<br />
;authRetries<br />
:number of retries for authentication procedure - defaults to 1<br />
<br />
;replacement[0-9]*Regex<br />
:Defines a replacement to be applied to an HTTP request header, data or URL before it is sent. This allows any part of the request to be modified based on a reading, an internal or an expression.<br />
:The regex defines which part of a header, data or URL should be replaced. The replacement is defined with the following attributes:<br />
<br />
;replacement[0-9]*Mode<br />
:Defines how the replacement should be done and what replacementValue means. Valid options are text, reading, internal and expression.<br />
<br />
;replacement[0-9]*Value<br />
:Defines the replacement. If the corresponding replacementMode is <code>text</code>, then value is a static text that is used as the replacement.<br />
:If replacementMode is <code>reading</code> then Value can be the name of a reading of this device or it can be a reading of a different device referred to by devicename:reading.<br />
:If replacementMode is <code>internal</code> the Value can be the name of an internal of this device or it can be an internal of a different device referred to by devicename:internal.<br />
:If replacementMode is <code>expression</code> the the Value is treated as a Perl expression that computes the replacement value. The expression can use $1, $2 and so on to refer to capture groups of the corresponding regex that is matched against the original URL, header or post data.<br />
:If replacementMode is <code>key</code> then the module will use a value from a key / value pair that is stored in an obfuscated form in the file system with the set storeKeyValue command. This might be useful for storing passwords.<br />
<br />
;[gs]et[0-9]*Replacement[0-9]*Value<br />
:This attribute can be used to override the replacement value for a specific get or set.<br />
<br />
;get|reading[0-9]*MaxAge<br />
:Defines how long a reading is valid before it is automatically overwritten with a replacement when the read function is called the next time.<br />
<br />
;get|reading[0-9]*MaxAgeReplacement<br />
:specifies the replacement for MaxAge - either as a static text or as a perl expression.<br />
<br />
;get|reading[0-9]*MaxAgeReplacementMode<br />
:specifies how the replacement is interpreted: can be text, expression and delete.<br />
<br />
;get|reading[0-9]*DeleteIfUnmatched<br />
:If set to 1 this attribute causes certain readings to be deleted when the parsing of the website does not match the specified reading. Internally HTTPMOD remembers which kind of operation created a reading (update, Get01, Get02 and so on). Specified readings will only be deleted if the same operation does not parse this reading again. This is especially useful for parsing that creates several matches / readings and the number of matches can vary from request to request. For example if reading01Regex creates 4 readings in one update cycle and in the next cycle it only matches two times then the readings containing the remaining values from the last round will be deleted.<br />
:Please note that this mechanism will not work in all cases after a restart. Especially when a get definition does not contain its own parsing definition but ExtractAllJSON or relies on HTTPMOD to use all defined reading.* attributes to parse the responsee to a get command, old readings might not be deleted after a restart of fhem.<br />
;get|reading[0-9]*DeleteOnError<br />
:If set to 1 this attribute causes certain readings to be deleted when the website can not be reached and the HTTP request returns an error. Internally HTTPMOD remembers which kind of operation created a reading (update, Get01, Get02 and so on). Specified readings will only be deleted if the same operation returns an error.<br />
The same restrictions as for DeleteIfUnmatched apply regarding a fhem restart.<br />
<br />
<br />
;httpVersion<br />
:defines the HTTP-Version to be sent to the server. This defaults to 1.0.<br />
<br />
;sslVersion<br />
:defines the SSL Version for the negotiation with the server. The attribute is evaluated by HttpUtils. If it is not specified, HttpUtils assumes SSLv23:!SSLv3:!SSLv2<br />
<br />
;sslArgs<br />
:defines a list that is converted to a key / value hash and gets passed to HttpUtils. To avoid certificate validation for broken servers you can for example specify <br />
:<code>attr myDevice sslArgs SSL_verify_mode,SSL_VERIFY_NONE</code><br />
<br />
;alignTime<br />
:Aligns each periodic read request for the defined interval to this base time. This is typcally something like 00:00 (see the FHEM at command)<br />
<br />
;noShutdown<br />
:pass the noshutdown flag to HTTPUtils for webservers that need it (some embedded webservers only deliver empty pages otherwise)<br />
<br />
;disable<br />
:stop doing automatic HTTP requests while this attribute is set to 1<br />
<br />
;enableControlSet<br />
:enables the built in set commands interval, stop, start, reread, upgradeAttributes, storeKeyValue.<br />
<br />
;enableCookies<br />
:enables the built in cookie handling if set to 1. With cookie handling each HTTPMOD device will remember cookies that the server sets and send them back to the server in the following requests. <br />
:This simplifies session magamenet in cases where the server uses a session ID in a cookie. In such cases enabling cookies should be sufficient and no sidRegex and no manual definition of a cookie header should be necessary.<br />
<br />
;showMatched<br />
:if set to 1 then HTTPMOD will create a reading with the name MATCHED_READINGS that contains the names of all readings that could be matched in the last request as well as UNMATCHED_READINGS and LAST_REQUEST.<br />
<br />
;showError<br />
:if set to 1 then HTTPMOD will create a reading and event with the Name LAST_ERROR that contains the error message of the last error returned from HttpUtils. <br />
<br />
;removeBuf<br />
:if set to 1 then HTTPMOD removes the internal named buf when a HTTP-response has been received. <br />
:$hash->{buf} is used internally be Fhem httpUtils and in some use cases it is desireable to remove this internal after reception <br />
:because it contains a very long response which looks ugly in Fhemweb.<br />
<br />
;timeout<br />
:time in seconds to wait for an answer. Default value is 2<br />
<br />
;queueDelay<br />
:HTTP Requests will be sent from a queue in order to avoid blocking when several Requests have to be sent in sequence. This attribute defines the delay between calls to the function that handles the send queue. It defaults to one second.<br />
<br />
;queueMax<br />
:Defines the maximum size of the send queue. If it is reached then further HTTP Requests will be dropped and not be added to the queue<br />
<br />
;minSendDelay<br />
:Defines the minimum time between two HTTP Requests.<br />
<br />
== Links ==<br />
* Example: [[Wetter_und_Wettervorhersagen#Wetter_von_Weather_Underground|Extract weather information from WeatherUnderground]]<br />
* Example: [[Pollenflug|Pollen count]]<br />
* Example: [[HTTPMOD Beispielkonfiguration zur Anbindung einer Daikin Klimaanlage mit WLAN-Modul|Connect Daikin aircondition to FHEM]]<br />
* Example: [[Go-eCharger|Extract information from go-eCharger]]<br />
* Example: [[Sonnenspeicher|Integration of energy supplies from sonnen (https://sonnenbatterie.de/en/start)]]<br />
* Example: [https://forum.fhem.de/index.php/topic,95989.msg915870.html#msg915870 Miele 3rd party API für Miele Smarthome Geräte]<br />
* Example: [https://forum.fhem.de/index.php/topic,84215.msg918662.html#msg918662 Honeywell Evohome Totalconnect]<br />
* Example: [https://forum.fhem.de/index.php/topic,78613.msg889015.html#msg889015 Tigo Energy Integration]<br />
* Example: [https://forum.fhem.de/index.php/topic,78613.msg708518.html#msg708518 Ecowater]<br />
* {{Link2Forum|Topic=17804|LinkText=Thread}} in FHEM Forum that discusses the first version of this module <br />
* {{Link2Forum|Topic=29471|LinkText=Thread}} in FHEM Forum that discusses the second major version of this module <br />
* {{Link2Forum|Topic=45176|LinkText=Thread}} in FHEM Forum that discusses the third major version of this module <br />
* [http://perldoc.perl.org/perlretut.html Introduction to regular expressions]<br />
* [http://portswigger.net/burp/ BurpSuite]: Tool (local proxy) to help analyze http traffic<br />
<br />
[[Kategorie:IP Components]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=HTTPMOD&diff=29904HTTPMOD2019-03-14T18:18:40Z<p>Amenomade: /* Links */ Weitere Beispiele</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Extract information from devices with an HTTP interface (or, more generic, from any URL) or send information to such devices <br />
|ModType=d<br />
|ModCmdRef=HTTPMOD<br />
|ModForumArea=Sonstiges<br />
|ModTechName=98_HTTPMOD.pm<br />
|ModOwner=StefanStrobel ({{Link2FU|3960|Forum}} / [[Benutzer:StefanStrobel|Wiki]])<br />
}}<br />
<br />
HTTPMOD provides a generic way to retrieve information from devices with an HTTP Interface and store them in Readings or send information to such devices. It queries a given URL with Headers and data defined by attributes. <br />
<br />
From the HTTP response it extracts readings named in attributes using Regexes, JSON or XPath parsing also defined by attributes.<br />
<br />
In an advanced [[Konfiguration|configuration]] the module can also send information to devices. To do this, a generic <code>set</code> option can be configured using attributes. <br />
<br />
== Availability == <br />
The module is part of the regular FHEM distribution.<br />
<br />
== Prerequisites ==<br />
This module uses the non blocking HTTP function <code>HttpUtils_NonblockingGet</code> provided by FHEM's [[HttpUtils]] in a new version published in December 2013.<br />
If not already installed in your environment, please [[update]] FHEM or install it manually using appropriate commands from your environment.<br />
Please also note that FHEM HttpUtils need the global attribute dnsServer to be set in order to work really non blocking even when dns requests can not be answered.<br />
<br />
== Define ==<br />
<syntaxhighlight lang="perl"><br />
define <name> HTTPMOD <URL> <Interval><br />
</syntaxhighlight><br />
The module connects to the given <code>URL</code> every <code>Interval</code> seconds, sends optional headers and data and then parses the response with regular expressions, xpath or json to set readings.<br />
<br />
URL can be "none" and Interval can be 0 if you prefer to only query data with a get command and not in a defined interval.<br />
<br />
Example:<br />
<syntaxhighlight lang="perl"><br />
define PM HTTPMOD http://MyPoolManager/cgi-bin/webgui.fcgi 60<br />
</syntaxhighlight><br />
<br />
== Set-Commands ==<br />
can be defined using attributes, see advanced configuration<br />
<br />
If you set the attribute enableControlSet to 1, the following additional built in set commands are available:<br />
;interval<br />
:set new interval time in seconds and restart the timer<br />
;reread<br />
:request the defined URL and try to parse it just like the automatic update would do it every Interval seconds without modifying the running timer.<br />
;stop<br />
:stop interval timer.<br />
;start<br />
:restart interval timer to call GetUpdate after interval seconds<br />
;upgradeAttributes<br />
:convert outdated attributes for older HTTPMOD-Versions that are still defined for this device from the old syntax to the new one.<br />
:attributes with the description "this attribute should not be used anymore" or similar will be translated to the new syntax, e.g. readingsName1 to reading01Name.<br />
;storeKeyValue<br />
:stores a key value pair in an obfuscated form in the file system. Such values can then be used in replacements where the mode is "key" e.g. to avoid storing passwords in the configuration in clear text<br />
<br />
== Get-Commands ==<br />
can be defined using attributes, see advanced configuration<br />
<br />
== simple Attributes ==<br />
;enableControlSet<br />
:enables the built in set commands ''interval'', ''stop'', ''start'', ''reread'', ''upgradeAttributes'', ''storeKeyValue''<br />
<br />
;enableCookies<br />
:enables the cookie handling inside HTTPMOD. It is advisable to always set this attribute and allow HTTPMOD to track the state of cookies and set them for following HTTP-requests<br />
<br />
;enforceGoodReadingNames<br />
:makes sure that HTTPMOD only creates readings that are allowd for Fhem (especially if reading names are dynamically created from JSON object names with extractAllJSON. It is advisable to always set this attribute.<br />
<br />
;handleRedirects<br />
:enables the redirect handling inside HTTPMOD which should be used together with the cookie handling of HTTPMOD. HTTPMOD will then automatically follow redirects from a web server and keep track of cookies at the same time. It is advisable to always set this attribute.<br />
<br />
;requestHeader.* <br />
:Define an additional HTTP Header to set in the HTTP request<br />
<br />
;requestData<br />
:POST Data to be sent in the request. If not defined, it will be a GET request as defined in HttpUtils used by this module<br />
<br />
;reading[0-9]+(-[0-9]+)?Name<br />
:the name of a reading to extract with the corresponding readingRegex<br />
<br />
;reading[0-9]*(-[0-9]+)?OExpr<br />
:defines an expression that is used in an eval to compute the readings value. The raw value will be in the variable $val.<br />
<br />
;reading[0-9]*(-[0-9]+)?OMap<br />
:Output Map. Defines a mapping from raw to visible values like "0:mittig, 1:oberhalb, 2:unterhalb". If specified as readingOMap then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*OMap.<br />
<br />
;reading[0-9]*(-[0-9]+)?Format<br />
:Defines a format string that will be used in sprintf to format a reading value. If specified as readingFormat then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Format.<br />
<br />
;reading[0-9]*(-[0-9]+)?Decode<br />
:defines an encoding to be used in a call to the perl function decode to convert the raw data string read from the device to a reading. This can be used if the device delivers strings in an encoding like cp850 instead of utf8.<br />
<br />
;reading[0-9]*(-[0-9]+)?Encode<br />
:defines an encoding to be used in a call to the perl function encode to convert the raw data string read from the device to a reading. This can be used if the device delivers strings in an encoding like cp850 and after decoding it you want to reencode it to e.g. utf8.<br />
<br />
;reading[0-9]+Regex<br />
:defines the regex to be used for extracting the reading. The value to extract should be in a capture group / sub expression <br />
:e.g. ([\d\.]+) in the above example. Multiple capture groups will create multiple readings (see explanation above)<br />
<br />
;reading[0-9]+XPath<br />
:defines an xpath to one or more readings when parsing HTML data (see examples below)<br />
<br />
;reading[0-9]+XPath-Strict<br />
:defines an xpath to one or more readings when parsing XML data (see examples below)<br />
<br />
;reading[0-9]+JSON<br />
:defines a path to the JSON object wanted by concatenating the object names with an underscore as delimiter (see the example below)<br />
<br />
;noShutdown<br />
:pass the noshutdown flag to HTTPUtils for webservers that need it (some embedded webservers only deliver empty pages otherwise)<br />
<br />
;disable<br />
:stop doing automatic HTTP requests while this attribute is set to 1<br />
<br />
;timeout<br />
:time in seconds to wait for an answer. Default value is 2<br />
<br />
;do_not_notify<br />
<br />
;readingFnAttributes<br />
<br />
== Simple Configuration of HTTP Devices ==<br />
If your device expects special HTTP-headers then specify them as <code>attr requestHeader1</code> to <code>attr requestHeaderX</code>.<br />
If your Device expects an HTTP POST instead of HTTP GET then the POST-data can be specified as <code>attr requestData</code>.<br />
To get the readings, specify pairs of <code>attr readingXName</code> and <code>attr readingXRegex</code>, <code>attr readingXXPath</code>, <code>attr readingXXPath-Strict</code> or <code>attr readingXJSON</code> to define which readings you want to extract from the HTTP response and how to extract them. (The old syntax <code>attr readingsNameX</code> and <code>attr readingsRegexX</code> is still supported but the new one with <code>attr readingXName</code> and <code>attr readingXRegex</code> should be preferred. The actual values to be extracted have to be sub expressions within () in the regex (see example below)<br />
<br />
=== Example for a PoolManager 5: ===<br />
The PoolManager Web GUI can be queried with HTTP POST Requests like this one:<br />
<br />
<syntaxhighlight lang="perl"><br />
POST /cgi-bin/webgui.fcgi HTTP/1.1<br />
Host: 192.168.70.90<br />
Accept: */*<br />
Content-Type: application/json;charset=UTF-8<br />
Content-Length: 60<br />
<br />
{"get" :["34.4001.value" ,"34.4008.value" ,"34.4033.value"]}<br />
</syntaxhighlight><br />
<br />
The resulting HTTP Response would look like this:<br />
<br />
<syntaxhighlight lang="perl"><br />
HTTP/1.1 200 OK<br />
Content-type: application/json; charset=UTF-8<br />
Expires: 0<br />
Cache-Control: no-cache<br />
Date: Sun, 12 Jan 2014 12:23:11 GMT<br />
Server: lighttpd/1.4.26<br />
Content-Length: 179<br />
<br />
{<br />
"data": {<br />
"34.4001.value": "7.00",<br />
"34.4008.value": "0.52",<br />
"34.4033.value": "24.8"<br />
},<br />
"status": {<br />
"code": 0<br />
},<br />
"event": {<br />
"type": 1,<br />
"data": "48.30000.0"<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
To configure HTTPMOD for a PoolManager one would first define a PoolManager device with e.g. the name PM, the URL and an interval of e.g. 60 seconds. <br />
<br />
Then the data to be sent in the request needs to be defined because in this example the device expects a POST request so the query is not contained in the URL but in the request data.<br />
<br />
Also as seen above the device expects special HTTP headers in the request so these headers also need to be defined as <code>attr PM requestHeader1</code> and <code>attr PM requestHeader2</code><br />
<br />
Then the names of the readings to be extracted would be set with attributes<br />
<br />
Then for each reading value to be extracted a regular expression needs to be set that will match the value in question within ().<br />
<br />
Example:<br />
<syntaxhighlight lang="perl"><br />
define PM HTTPMOD http://MyPoolManager/cgi-bin/webgui.fcgi 60<br />
<br />
attr PM enableControlSet 1<br />
attr PM enableCookies 1<br />
attr PM enforceGoodReadingNames 1<br />
attr PM handleRedirects 1<br />
<br />
attr PM reading01Name PH<br />
attr PM reading01Regex 34.4001.value":[ \t]+"([\d\.]+)"<br />
<br />
attr PM reading02Name CL<br />
attr PM reading02Regex 34.4008.value":[ \t]+"([\d\.]+)"<br />
<br />
attr PM reading03Name3TEMP<br />
attr PM reading03Regex 34.4033.value":[ \t]+"([\d\.]+)"<br />
<br />
attr PM requestData {"get" :["34.4001.value" ,"34.4008.value" ,"34.4033.value", "14.16601.value", "14.16602.value"]}<br />
attr PM requestHeader1 Content-Type: application/json<br />
attr PM requestHeader2 Accept: */*<br />
attr PM stateFormat {sprintf("%.1f Grad, PH %.1f, %.1f mg/l Chlor", ReadingsVal($name,"TEMP",0), ReadingsVal($name,"PH",0), ReadingsVal($name,"CL",0))}<br />
</syntaxhighlight><br />
<br />
=== Example for AmbientMonitor ===<br />
AmbientMonitor is a webbased visualisation for sensors connected to an Arduino device. Its web interface can also be queried with HTTMOD to grab the data into readings.<br />
<br />
This example was provided by locutus. The hardware configuration is an Arduino + Ethercard with ENC28J60 Controller + DHT22 Sensor and software can be downloaded from https://github.com/lucadentella/AmbientMonitor<br />
<br />
In this example an HTTP GET is sufficent, so no <code>requestData</code> is needed. The device provides temperature and humidity readings in an HTTP response that looks like:<br />
<syntaxhighlight lang="perl"><br />
HTTP/1.0 200 OK <br />
Content-Type: text/html <br />
<br />
myCB({'temperature':22.00,'humidity':46.00})<br />
</syntaxhighlight><br />
<br />
the definition could be:<br />
<syntaxhighlight lang="perl"><br />
define AmbientMonitor HTTPMOD http://192.168.1.221/?callback=? 300<br />
<br />
attr AmbientMonitor enableControlSet 1<br />
attr AmbientMonitor enableCookies 1<br />
attr AmbientMonitor enforceGoodReadingNames 1<br />
attr AmbientMonitor handleRedirects 1<br />
<br />
attr AmbientMonitor requestHeader Content-Type: application/json<br />
attr AmbientMonitor reading1Name Temperatur<br />
attr AmbientMonitor reading1Regex temperature':([\d\.]+)<br />
attr AmbientMonitor reading2Name Feuchtigkeit<br />
attr AmbientMonitor reading2Regex humidity':([\d\.]+)<br />
attr AmbientMonitor stateFormat {sprintf("Temperatur %.1f C, Feuchtigkeit %.1f %", ReadingsVal($name,"Temperatur",0), ReadingsVal($name,"Feuchtigkeit",0))}<br />
</syntaxhighlight><br />
<br />
== formatting and manipulating values / readings ==<br />
Values that are parsed from an HTTP response can be further treated or formatted with the following attributes:<br />
<br />
* <code>(reading|get)[0-9]*(-[0-9]+)?OExpr</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?OMap</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?Format</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?Decode</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?Encode</code><br />
<br />
They can all be specified for an individual reading, for all readings in one match (e.g. if a regular expression has several capture groups) or for all readings in a get command (defined by getXX) or for all readings in the main reading list (defined by readingXX):<br />
<syntaxhighlight lang="perl"><br />
reading01Format %.1f<br />
</syntaxhighlight><br />
<br />
will format the reading with the name specified by the attribute reading01Name to be numerical with one digit after the decimal point.<br />
If the attribute reading01Regex is used and contains several capture groups then the format will be applied to all readings parsed by this regex unless these readings have their own format specified by reading01-1Format, reading01-2Format and so on.<br />
<br />
<syntaxhighlight lang="perl"><br />
reading01-2Format %.1f<br />
</syntaxhighlight><br />
<br />
Can be used in cases where a regular expression specified as reading01regex contains several capture groups or an xpath specified as reading01XPath creates several readings. <br />
In this case reading01-2Format specifies the format to be applied to the second match.<br />
<br />
<syntaxhighlight lang="perl"><br />
readingFormat %.1f<br />
</syntaxhighlight><br />
<br />
applies to all readings defined by a reading-Attribute that have no more specific format.<br />
<br />
If you need to do some calculation on a raw value before it is used as a reading, you can define the attribute <code>readingOExpr</code>.<br />
It defines a Perl expression that is used in an eval to compute the readings value. The raw value will be in the variable $val.<br />
<br />
Example for an expression:<br />
<syntaxhighlight lang="perl"><br />
attr PM reading03OExpr $val * 10<br />
</syntaxhighlight><br />
Just like in the above example of the readingFormat attributes, readingOExpr and the other following attributes can be applied on several levels.<br />
<br />
To map a numerical value to a name, you can use the readingOMap attribute. <br />
It defines a mapping from raw to visible values like "0:mittig, 1:oberhalb, 2:unterhalb".<br />
<br />
Example for a map:<br />
<syntaxhighlight lang="perl"><br />
attr PM reading02-3OMap 0:kalt, 1:warm, 2:sehr warm<br />
</syntaxhighlight><br />
<br />
To convert character sets, the module can first decode a string read from the device and then encode it again. For example:<br />
<syntaxhighlight lang="perl"><br />
attr PM getDecode UTF-8<br />
</syntaxhighlight><br />
<br />
This applies to all readings defined for Get-Commands.<br />
<br />
== Some help with Regular Expressions ==<br />
{{Randnotiz|RNTyp=y|RNText=Starting with version ''2018-02-10'' the internal that holds the HTTP response is no longer called '''''buf''''' but rather '''''httpbody''''', and it is only displayed when attribute '''''showBody''''' is set to "1".}}<br />
If HTTPMOD seems not to work and the FHEM Logfile contains a message like <br />
:<code>HTTPMOD: Response didn't match Reading ...</code><br />
then you should check if the value you want to extract is read into the internal with the name buf. Internals are visible when you click on the defined HTTPMOD Device. buf is an internal variable that contains the HTTP Response read. If the value is there and you get the mentioned message then probably something is wrong with your regular expression. Please note that buf might contain special characters like newlines but they are not shown in fhemweb. If you are new to regular expressions then the introduction at http://perldoc.perl.org/perlretut.html might be helpful. <br />
<br />
For a typical HTTPMOD use case where you want to extract a number out of a HTTP-Response you can use something like <code>[\d\.]+</code> to match the number itself. The expression matches the number characters (<code>\d</code>) or a <code>.</code> if one of these characters occurs at least once. <br />
<br />
To tell HTTPMOD that the number is what you want to use for the reading, you have to put the expression in between <code>()</code>. A <code>([\d\.]+)</code> alone would match the longest number in the HTTP Response which is very likely not the number you are looking for so you need to add something to the expression to give it a context and define how to find the number that you are looking for.<br />
<br />
If there is a title text before the number or a special text after the number you can put this in the regex. In one of the examples above <code>humidity':([\d\.]+)</code> is looking for the number that immediately follows the text <code>humidity':</code> without any blanks in between.<br />
Be careful if the text you are getting from your device contains special characters like newline. You don't see such special characters in the fhem webinterface as contents of the internal buf but they might cause your regular expression to fail. <br />
<br />
If you have trouble defining a regular expression that matches a certain name, then many complicated characters and then a number, it might be helpful to use a negation in matching like <code>temp[^\d]+([\d\.]).*</code>. In this examle <code>[^\d]+</code> means any character that is not a numerical digit, more than once.<br />
<br />
=== Regular Expressions with multiple capture Groups ===<br />
The regular expressions used in the above example for a Poolmanager will take the value that matches one capture group. This is the part of the regular expression inside (). In the above example "([\d\.]+)" refers to numerical digits or points between double quotation marks. Only the string consiting of digits and points will match inside (). This piece is assigned to the reading.<br />
<br />
You can also use regular expressions that have several capture groups which might be helpful when parsing tables. In this case an attribute like <br />
<br />
<syntaxhighlight lang="perl"><br />
reading02Regex something[ \t]+([\d\.]+)[ \t]+([\d\.]+)<br />
</syntaxhighlight><br />
<br />
could match two numbers. When you specify only one reading02Name like <br />
<syntaxhighlight lang="perl"><br />
reading02Name Temp<br />
</syntaxhighlight><br />
<br />
the name Temp will be used with the extension -1 and -2 thus giving a reading Temp-1 for the first number and Temp-2 for the second. You can also specify individual names for several readings that get parsed from one regular expression with several capture groups by defining attributes <br />
<br />
<syntaxhighlight lang="perl"><br />
reading02-1Name<br />
reading02-2Name<br />
...<br />
</syntaxhighlight><br />
The same notation can be used for formatting attributes like readingXOMap, readingXFormat and so on.<br />
<br />
The usual way to define readings is however to have an individual regular expression with just one capture group per reading as shown in the above example.<br />
<br />
== Parsing JSON ==<br />
<br />
If a webservice delivers data in JSON format, HTTPMOD can directly parse JSON which might be easier in this case than definig regular expressions.<br />
The next example shows the data that can be requested from a Poolmanager with the following partial configuration:<br />
<br />
<syntaxhighlight lang="perl"><br />
define test2 HTTPMOD none 0<br />
attr test2 get01Name Chlor<br />
attr test2 getURL http://192.168.70.90/cgi-bin/webgui.fcgi<br />
attr test2 getHeader1 Content-Type: application/json<br />
attr test2 getHeader2 Accept: */*<br />
attr test2 getData {"get" :["34.4008.value"]}<br />
</syntaxhighlight><br />
<br />
The data in the HTTP response looks like this:<br />
<br />
<syntaxhighlight lang="perl"><br />
{<br />
"data": {<br />
"34.4008.value": "0.25"<br />
},<br />
"status": {<br />
"code": 0<br />
},<br />
"event": {<br />
"type": 1,<br />
"data": "48.30000.0"<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
the classic way to extract the value 0.25 into a reading with the name Chlor with a regex would have been<br />
<syntaxhighlight lang="perl"><br />
attr test2 get01Regex 34.4008.value":[ \t]+"([\d\.]+)"<br />
</syntaxhighlight><br />
<br />
with JSON you can write <br />
<syntaxhighlight lang="perl"><br />
attr test2 get01JSON data_34.4008.value <br />
</syntaxhighlight><br />
which will create a reading with the Name "Chlor" (as shown above) and take the value 0.25 from the JSON string.<br />
<br />
or if you don't care about the naming of your readings, you can simply extract all JSON data with <br />
<syntaxhighlight lang="perl"><br />
attr test2 extractAllJSON<br />
</syntaxhighlight><br />
<br />
which would apply to all data read from this device and create the following readings out of the HTTP response shown above:<br />
<br />
{| class="wikitable"<br />
| data_34.4008.value || 0.25<br />
|-<br />
| event_data || 48.30000.0<br />
|-<br />
| event_type || 1<br />
|-<br />
| status_code || 0<br />
|}<br />
<br />
or you can specify<br />
<syntaxhighlight lang="perl"><br />
attr test2 get01ExtractAllJSON<br />
</syntaxhighlight><br />
which would only apply to all data read as response to the get command defined as get01. <br />
<br />
It might seem very simple at first sight to use extractAllJSON but if you prefer readings with a meaningful name you should instead define these readings with readingXXName and readingXXJSON or getXXName and getXXJSON individually. Of Course it would be possible to create additional user readings outside HTTPMOD but doing calculations, naming and formatting inside HTTPMOD is more efficient.<br />
<br />
=== JSON Lists ===<br />
<br />
imagine the HTTP Response contains:<br />
<br />
<syntaxhighlight lang="perl"><br />
{ "power":"0",<br />
"modes":["Off","SimpleColor","RainbowChase"],<br />
"code1":3,<br />
"code2":4<br />
}<br />
</syntaxhighlight><br />
<br />
then a configuration like <br />
<br />
<syntaxhighlight lang="perl"><br />
attr device reading01JSON modes <br />
attr device reading01Name Mode <br />
</syntaxhighlight><br />
<br />
will create a list of Subreadings just like a regex with multiple matches can create multiple subreadings:<br />
<br />
{| class="wikitable"<br />
| Mode-1 || Off<br />
|-<br />
| Mode-2 || SimpleColor<br />
|-<br />
| Mode-3 || RainbowChase <br />
|}<br />
<br />
if you don't want several subreadings but one reading that contains the list of modes, you can specify a recombine expression:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr device reading01Name Modes <br />
attr device reading01RecombineExpr join ",", @matchlist <br />
</syntaxhighlight><br />
<br />
which will create one reading containing a list:<br />
<br />
{| class="wikitable"<br />
| Modes || Off,SimpleColor,RainbowChase<br />
|}<br />
<br />
JSON parsing specifications also don't Need to match exactly. If there is no exact match for a defined reading, the HTTPMOD will try to Interpret the specification as a regex and look for json object paths that match the specification as a regex. For example:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr device reading01Name CodeElem<br />
attr device reading01JSON code<br />
</syntaxhighlight><br />
<br />
which will create a list of readings:<br />
<br />
{| class="wikitable"<br />
| CodeElem-1|| 3<br />
|-<br />
| CodeElem-2 || 4<br />
|}<br />
<br />
and of course they could also be recombined into one reading with a RecombineExpr Attribute.<br />
<br />
== Parsing http / XML using xpath ==<br />
Another alternative to regex parsing is the use of XPath to extract values from HTTP responses.<br />
The following example shows how XML data can be parsed with XPath-Strict or HTML Data can be parsed with XPath.<br />
Both work similar and the example uses XML Data parsed with the XPath-Strict option:<br />
<br />
If The XML data in the HTTP response looks like this:<br />
<br />
<syntaxhighlight lang="xml"><br />
<root xmlns:foo="http://www.foo.org/" xmlns:bar="http://www.bar.org"><br />
<actors><br />
<actor id="1">Peter X</actor><br />
<actor id="2">Charles Y</actor><br />
<actor id="3">John Doe</actor><br />
</actor><br />
</root><br />
</syntaxhighlight><br />
<br />
with XPath you can write <br />
<syntaxhighlight lang="perl"><br />
attr htest reading01Name Actor<br />
attr htest reading01XPath-Strict //actor[2]/text()<br />
</syntaxhighlight><br />
<br />
This will create a reading with the Name "Actor" and the value "Charles Y".<br />
<br />
Since XPath specifications can define several values / matches, HTTPMOD can also interpret these and store them in multiple readings:<br />
<syntaxhighlight lang="perl"><br />
attr htest reading01Name Actor<br />
attr htest reading01XPath-Strict //actor/text()<br />
</syntaxhighlight><br />
<br />
will create the readings <br />
<br />
{| class="wikitable"<br />
| Actor-1 || Peter X<br />
|-<br />
| Actor-2 || Charles Y<br />
|-<br />
| Actor-3 || John Doe<br />
|}<br />
<br />
== Further replacements of URL, header or post data ==<br />
sometimes it might be helpful to dynamically change parts of a URL, HTTP header or post data depending on existing readings, internals or <br />
perl expressions at runtime. This might be needed to pass further variables to a server, a current date or other things. <br />
<br />
To support this HTTPMOD offers generic replacements that are applied to a request before it is sent to the server. A replacement can be defined with the attributes <br />
<br />
* <code>replacement[0-9]*Regex</code><br />
* <code>replacement[0-9]*Mode</code><br />
* <code>replacement[0-9]*Value</code><br />
* <code>[gs]et[0-9]*Replacement[0-9]*Value</code><br />
<br />
a replacement always replaces a match of a regular expression. <br />
<br />
'''replacement[0-9]*Mode:'''<br />
The way the replacement value is defined can be specified with the replacement mode.<br />
* If the <code>replacement[0-9]*Mode</code> is <code>reading</code>, then the corresponding <code>replacement[0-9]*Value</code> is interpreted as the name of a ''reading'' of the same device or as ''device:reading'' to refer to another device.<br />
* If the <code>replacement[0-9]*Mode</code> is <code>internal</code>, then the corresponding <code>replacement[0-9]*Value</code> is interpreted as the name of an ''internal'' of the same device or as ''device:internal'' to refer to another device.<br />
* If the <code>replacement[0-9]*Mode</code> is <code>text</code>, then the corresponding <code>replacement[0-9]*Value</code> is interpreted as a static text<br />
* If the <code>replacement[0-9]*Mode</code> is <code>expression</code>, then the corresponding <code>replacement[0-9]*Value</code> is evaluated as a perl expression to compute the replacement. Inside such a replacement expression it is possible to refer to capture groups of the replacement regex.<br />
* If the <code>replacement[0-9]*Mode</code> is <code>key</code>, then the module will use a value from a key / value pair that is stored in an obfuscated form in the file system with the set storeKeyValue command. This might be useful for storing passwords.<br />
<br />
<br />
Example:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr mydevice getData {"get" :["%%value%%.value"]}<br />
attr mydevice replacement01Mode text<br />
attr mydevice replacement01Regex %%value%%<br />
<br />
attr mydevice get01Name Chlor<br />
attr mydevice get01Replacement01Value 34.4008<br />
<br />
attr mydevice get02Name Something<br />
attr mydevice get02Replacement01Value 31.4024<br />
<br />
attr mydevice get05Name profile<br />
attr mydevice get05URL http://www.mydevice.local/getprofile?password=%%password%%<br />
attr mydevice replacement02Mode key<br />
attr mydevice replacement02Regex %%password%%<br />
attr mydevice get05Replacement02Value password<br />
</syntaxhighlight> <br />
<br />
defines that <code>%%value%%</code> will be replaced by a static text.<br />
<br />
All Get commands will be HTTP post requests of a similar form. Only the <code>%%value%%</code> will be different from get to get.<br />
The first get will set the reading named Chlor and for the request it will take the generic getData and replace %%value%% with 34.4008.<br />
<br />
A second get will look the same except a different name and replacement value.<br />
<br />
With the command <code>set storeKeyValue password geheim</code> you can store the password geheim in an obfuscated form in the file system. <br />
To use this password and send it in a request you can use the above replacement with mode key. The value password will then refer to the ofuscated string stored with the key password.<br />
<br />
The mode <code>expression</code> allows you to define your own replacement syntax:<br />
<syntaxhighlight lang="perl"> <br />
attr mydevice replacement01Mode expression<br />
attr mydevice replacement01Regex {{([^}]+)}}<br />
attr mydevice replacement01Value ReadingsVal("mydevice", $1, "")<br />
attr mydevice getData {"get" :["{{temp}}.value"]}<br />
</syntaxhighlight> <br />
<br />
In this example any <code><nowiki>{{name}}</nowiki></code> in a URL, header or post data will be passed on to the perl function ReadingsVal <br />
which uses the string between <code><nowiki>{{}}</nowiki></code> as second parameter. This way one defined replacement can be used for many different<br />
readings.<br />
<br />
HTTPMOD has two built in replacements: One for session Ids and another one for the input value in a set command.<br />
The placeholder $sid is always replaced with the internal <code>$hash->{sid}</code> which contains the session id after it is extracted from a previous HTTP response. <br />
If you don't like to use the placeholder $sid then you can define your own replacement for example like:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr mydevice replacement01Mode internal<br />
attr mydevice replacement01Regex %session%<br />
attr mydevice replacement01Value sid<br />
</syntaxhighlight> <br />
<br />
Now the internal <code>$hash->{sid}</code> will be used as a replacement for the placeholder %session%.<br />
<br />
In the same way a value that is passed to a set-command can be put into a request with a user defined replacement. <br />
In this case the internal <code>$hash->{value}</code> will contain the value passed to the set command. <br />
<code>$hash->{value}</code> might even be a string containing several values that could be put into several different positions in a request by using user defined replacements.<br />
<br />
'''Other example : steering a pellet stove from Rika'''<br />
<br />
The stove API of Rika on https://www.rika-firenet.com/web/ delivers a JSON string with all settings and values, and can be piloted with a data string containing all the "set" values at once.<br />
<br />
Delivered JSON on get https://www.rika-firenet.com/api/client/xxxxxxxx/status : (xxxxxxxx must be replaced with the unique stove ID)<br />
<syntaxhighlight lang="perl"><br />
{<br />
"name": "Vorzimmer",<br />
"stoveID": "xxxxxxxxx",<br />
"lastSeenMinutes": 1,<br />
"lastConfirmedRevision": 1504385700,<br />
"controls": {<br />
"revision": 1504385700,<br />
"onOff": true,<br />
"operatingMode": 2,<br />
"heatingPower": 65,<br />
"targetTemperature": 24,<br />
"heatingTimesActive": false,<br />
"heatingTimesActiveForComfort": true,<br />
"setBackTemperature": 18,<br />
"convectionFan1Active": false,<br />
"convectionFan1Level": 0,<br />
"convectionFan1Area": 0,<br />
"convectionFan2Active": false,<br />
"convectionFan2Level": 0,<br />
"convectionFan2Area": 0,<br />
"frostProtectionActive": false,<br />
"frostProtectionTemperature": 5<br />
},<br />
"sensors": {<br />
"statusError": 0,<br />
"statusWarning": 0,<br />
"statusService": 0,<br />
"statusMainState": 1,<br />
"statusSubState": 3,<br />
"statusFrostStarted": false,<br />
"inputFlameTemperature": 21,<br />
"inputRoomTemperature": 21,<br />
"inputExternalRequest": true,<br />
"outputDischargeMotor": 0,<br />
"outputInsertionMotor": 0,<br />
"outputIDFan": 0,<br />
"outputAirFlaps": 0,<br />
"outputIgnition": false,<br />
"parameterStoveTypeNumber": 13,<br />
"parameterVersionMainBoard": 223,<br />
"parameterVersionTFT": 223,<br />
"parameterRuntimePellets": 11,<br />
"parameterRuntimeLogs": 0,<br />
"parameterFeedRateTotal": 17,<br />
"parameterFeedRateService": 683,<br />
"parameterOnOffCycles": 2<br />
},<br />
"stoveType": "DOMO MultiAir",<br />
"stoveFeatures": {<br />
"multiAir1": true,<br />
"multiAir2": true,<br />
"insertionMotor": false,<br />
"airFlaps": false,<br />
"logRuntime": false<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
Data string to send to https://www.rika-firenet.com/api/client/xxxxxxxx/controls in order to set values:<br />
<syntaxhighlight lang="perl"><br />
heatingTimesActiveForComfort=true&frostProtectionTemperature=3&setBackTemperature=18&targetTemperature=24&convectionFan2Level=0&convectionFan2Active=false&convectionFan1Level=0&onOff=true&convectionFan1Active=false&convectionFan2Area=0&revision=1505550101&heatingTimesActive=false&convectionFan1Area=0&frostProtectionActive=false&operatingMode=2&heatingPower=65<br />
</syntaxhighlight><br />
<br />
Code in 99_myUtils.pm:<br />
<syntaxhighlight lang="perl"><br />
use JSON;<br />
...<br />
sub<br />
replaceJSON ($$) {<br />
my ($valToReplace, $value) = @_;<br />
<br />
#$value in the parameters is a default value<br />
#It has to be replaced through the real value nnn passed in the set command "set <device> valToset nnn"<br />
$value = InternalVal("Ofen", "value", $value);<br />
Log3 ("Ofen", 3, "replaceJSON Internalvalue: $value");<br />
<br />
#Force an update to avoid outdated revision number<br />
fhem ("get Ofen revision");<br />
<br />
#Get all the controls as json<br />
my $json = ReadingsVal("Ofen", "controlsJSON","");<br />
Log3 ("Ofen", 3, "replaceJSON configsJSON: $json");<br />
<br />
# When starting FHEM or rereading config, the reading controlsJSON is empty<br />
return if ($json eq ""); <br />
<br />
my $decoded = decode_json($json);<br />
my $result;<br />
for my $key ( keys %$decoded ) {<br />
$result .= "$key=";<br />
if ($key eq $valToReplace) {<br />
$result .= $value."&";<br />
} else {<br />
$result .= $decoded->{$key}."&";<br />
}<br />
}<br />
chop($result); #remove last &<br />
Log3("Ofen", 3, "replaceJSON Result: $result");<br />
return $result;<br />
}<br />
</syntaxhighlight><br />
<br />
Define stove in fhem:<br />
<syntaxhighlight lang="perl"><br />
defmod Ofen HTTPMOD https://www.rika-firenet.com/api/client/xxxxxxxx/status 60<br />
<br />
attr Ofen enableCookies 1<br />
attr Ofen reAuthRegex id="login"|Unauthorized<br />
attr Ofen sid01Data email=xx@xx&password=xx<br />
attr Ofen sid01URL https://www.rika-firenet.com/web/login<br />
<br />
attr Ofen reading01JSON sensors_inputRoomTemperature<br />
attr Ofen reading01Name RaumTemp<br />
attr Ofen reading02JSON controls_setBackTemperature<br />
attr Ofen reading02Name Absenkung<br />
attr Ofen reading03JSON controls_frostProtectionTemperature<br />
attr Ofen reading03Name Frostschutz<br />
attr Ofen reading10Name controlsJSON<br />
attr Ofen reading10Regex (?s)controls.*?({.*?})<br />
<br />
attr Ofen get09Name revision<br />
attr Ofen get09URL https://www.rika-firenet.com/api/client/xxxxxxxx/status<br />
<br />
attr Ofen setURL https://www.rika-firenet.com/api/client/xxxxxxxx/controls<br />
attr Ofen setData {{data}}<br />
attr Ofen replacement01Mode expression<br />
attr Ofen replacement01Regex {{data}}<br />
<br />
attr Ofen set11Name frostProtectionTemperature<br />
attr Ofen set11Replacement01Value replaceJSON("frostProtectionTemperature", 2)<br />
<br />
attr Ofen set12Name targetTemperature<br />
attr Ofen set12Replacement01Value replaceJSON("targetTemperature", 24)<br />
</syntaxhighlight><br />
<br />
A detailed explanation (in german) of the login process can be found here: [https://forum.fhem.de/index.php/topic,76220.msg682514.html#msg682514]<br />
and the explanation of the other parameters here: [https://forum.fhem.de/index.php/topic,76220.msg685710.html#msg685710]<br />
<br />
== replacing reading values when they have not been updated / the device did not respond ==<br />
If a device does not respond then the values stored in readings will keep the same and only their timestamp shows that they are outdated. <br />
If you want to modify reading values that have not been updated for a number of seconds, you can use the attributes<br />
<br />
* <code>(reading|get)[0-9]*(-[0-9]+)?MaxAge</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?MaxAgeReplacementMode</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?MaxAgeReplacement</code><br />
<br />
Every time the module tries to read from a device, it will also check if readings have not been updated <br />
for longer than the <code>MaxAge</code> attributes allow. If readings are outdated, the <code>MaxAgeReplacementMode</code> defines how the affected<br />
reading values should be replaced. <code>MaxAgeReplacementMode</code> can be <code>text</code>, <code>reading</code>, <code>internal</code>, <code>expression</code> or <code>delete</code>.<br />
<br />
<code>MaxAge</code> specifies the number of seconds that a reading should remain untouched before it is replaced. <br />
<br />
<code>MaxAgeReplacement</code> contains either a static text that is used as replacement value or a Perl expression that is evaluated to <br />
give the replacement value. This can be used for example to replace a temperature that has not bee updated for more than 5 minutes <br />
with the string "outdated - was 12": <br />
<syntaxhighlight lang="perl"><br />
attr PM readingMaxAge 300<br />
attr PM readingMaxAgeReplacement "outdated - was " . $val<br />
attr PM readingMaxAgeReplacementMode expression<br />
</syntaxhighlight><br />
The variable <code>$val</code> contains the value of the reading before it became outdated.<br />
<br />
Or to show that a device was offline:<br />
<syntaxhighlight lang="perl"><br />
attr MyLight reading01Name color<br />
attr MyLight reading01JSON result_02_color<br />
attr MyLight reading01MaxAge 300<br />
attr MyLight reading01MaxAgeReplacement "offline"<br />
attr MyLight reading01MaxAgeReplacementMode text<br />
</syntaxhighlight><br />
<br />
<br />
== Note on determining how to send requests to a special device ==<br />
If you don't know which URLs, headers or POST data your web GUI uses, you might try a local proxy like BurpSuite [http://portswigger.net/burp/ BurpSuite] to track requests and responses. This is a tedious task but probably the best way to achieve a successful result. <br />
<br />
Let us consider an example. The Telekom Speedport W724V has a login-site that is famous for being cumbersome. Burp allows to monitor each step in the login procedure. In the case of a speedport the following steps occur:<br />
<br />
First burp shows that a get command is issued<br />
################################################################################################## <br />
GET / HTTP/1.1<br />
Host: speedport.ip<br />
Cache-Control: max-age=0<br />
Upgrade-Insecure-Requests: 1<br />
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36<br />
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8<br />
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4<br />
Cookie: lang=de<br />
Connection: close <br />
In order to mimic the behavior of a real person calling the website HTTPMOD should copy all necessary steps. Host, Cookie and the GET-command are usually necessary. The same cannot be said of the User-Agent because the website can be called from any mobile or desktop computer. <br />
<br />
Then, the speedport will answer with a command that consists of several lines. By going through every line for every step in the login procedure one will finally arrive at the information that is necessary to successfully enter the login of the speedport (in case of the W724V, for example, it is necessary to copy a token called _httoken and to include the referer).<br />
<br />
== Advanced configuration to define a <code>set</code> command and send data to a device ==<br />
<br />
When a set option is defined by attributes, the module will use the value given to the set command and integrate it into an HTTP-Request that sends the value to the device. The definitions for URL, headers and post data can contain the placeholder $val which will be replaced by the value given to the set command.<br />
<br />
This can be as simple as:<br />
<syntaxhighlight lang="perl"><br />
# No cyclic requests and no main URL needed in this example<br />
define MyDevice HTTPMOD none 0<br />
<br />
attr MyDevice set01Name Licht<br />
attr MyDevice set01URL http://192.168.1.22/switch=$val<br />
</syntaxhighlight><br />
<br />
A user command <br />
<syntaxhighlight lang="perl"><br />
set MyDevice Licht 1<br />
</syntaxhighlight><br />
<br />
will be translated into the http GET request<br />
<syntaxhighlight lang="perl"><br />
http://192.168.1.22/switch=1<br />
</syntaxhighlight><br />
<br />
In this example a map would also be helpful, that translates on / off to 0 or 1 and allows the user to select on/of in fhemweb:<br />
<syntaxhighlight lang="perl"><br />
attr MyDevive set01IMap 0:off, 1:on<br />
</syntaxhighlight><br />
This also provides input validation to make sure that only on and off can be used with the set command.<br />
<br />
In more complex Scenarios you might need to login before sending a command and the Login might create a session id that has to be part of further requests either in the URL, in headers or in the post data.<br />
<br />
Extension to the above example for a PoolManager 5 where a set needs a session id in the URL and the values have to be passed in JSON strings as post data:<br />
<syntaxhighlight lang="perl"><br />
attr PM set01Name HeizungSoll<br />
attr PM set01URL http://MyPoolManager/cgi-bin/webgui.fcgi?sid=$sid<br />
attr PM set01Hint 6,10,20,30<br />
attr PM set01Min 6<br />
attr PM set01Max 30<br />
attr PM setHeader1 Content-Type: application/json<br />
attr PM set01Data {"set" :{"34.3118.value" :"$val" }}<br />
</syntaxhighlight><br />
<br />
This example defines a set option with the name HeizungSoll.<br />
By issuing <code>set PM HeizungSoll 10</code> in FHEM, the value 10 will be sent in the defined HTTP<br />
Post to URL <code>http://MyPoolManager/cgi-bin/webgui.fcgi</code> in the Post Data as<br />
<br />
<syntaxhighlight lang="html4strict"><br />
{"set" :{"34.3118.value" :"10" }}<br />
</syntaxhighlight><br />
<br />
The optional attributes set01Min and set01Max define input validations that will be checked in the set function. <br />
The optional attribute set01Hint will define a selection list for the FHEMweb GUI.<br />
<br />
The HTTP response to such a request will be ignored unless you specify the attribute <code>setParseResponse</code> <br />
for all set commands or <code>set01ParseResponse</code> for the set command with number 01.<br />
If the HTTP response to a set command is parsed then this is done like the parsing of responses to get commands and you can use the attributes ending e.g. on Format, Encode, Decode, OMap and OExpr to manipulate / format the values read.<br />
<br />
If a parameter to a set command is not numeric but should be passed on to the device as text, then you can specify the attribute setTextArg. For example: <br />
<syntaxhighlight lang="perl"><br />
attr PM set01TextArg<br />
</syntaxhighlight><br />
<br />
If a set command should not require a parameter at all, then you can specify the attribute NoArg. For example: <br />
<syntaxhighlight lang="perl"><br />
attr PM set03Name On<br />
attr PM set03NoArg<br />
</syntaxhighlight><br />
<br />
== Advanced configuration to create a valid session id that might be necessary ==<br />
In simple cases logging in works with basic authentication. In the case HTTPMOD accepts a username and password as part of the URL in the form <br />
<syntaxhighlight lang="perl"><br />
http://User:Password@192.168.1.18/something<br />
</syntaxhighlight><br />
<br />
However basic auth is seldom used. If you need to fill in a username and password in a HTML form and the session is then managed by a session id, here is how to configure this:<br />
<br />
when sending data to an HTTP-Device in a set, HTTPMOD will replace any <code>$sid</code> in the URL, Headers and Post data with the internal <code>$hash->{sid}</code>. To authenticate towards the device and give this internal a value, you can use an optional multi step login procedure defined by the following attributes: <br />
<br />
* <code>sid[0-9]*URL</code><br />
* <code>sid[0-9]*Data.*</code><br />
* <code>sid[0-9]*Header.*</code><br />
* <code>sid[0-9]*IgnoreRedirects</code><br />
* <code>idRegex</code><br />
* <code>idJSON</code><br />
* <code>idXPath</code><br />
* <code>idXPath-Strict</code><br />
* <code>(get|set|sid)[0-9]*IdRegex</code><br />
* <code>(get|set|sid)[0-9]*IdJSON</code><br />
* <code>(get|set|sid)[0-9]*IdXPath</code><br />
* <code>(get|set|sid)[0-9]*IdXPath-Strict</code><br />
<br />
Each step can have a URL, Headers, Post Data pieces and a Regex to extract a resulting Session ID into <code>$hash->{sid}</code>.<br />
HTTPMOD will create a sorted list of steps (the numbers between sid and URL / Data / Header) and the loop through these steps and send the corresponding requests to the device. For each step a $sid in a Header or Post Data will be replaced with the current content of <code>$hash->{sid}</code>.<br />
<br />
Using this feature, HTTPMOD can perform a forms based authentication and send user name, password or other necessary data to the device and save the session id for further requests.<br />
<br />
To determine when this login procedure is necessary, HTTPMOD will first try to send a request without <br />
doing the login procedure. If the result contains an error that authentication is necessary, then a login is performed. <br />
To detect such an error in the HTTP response, you can again use a regular expression, JSON or XPath, this time with the attributes <br />
<br />
* <code>reAuthRegex</code><br />
* <code>reAuthJSON</code><br />
* <code>reAuthXPath</code><br />
* <code>reAuthXPath-Strict</code><br />
* <code>(get|set)[0-9]*ReAuthRegex</code><br />
* <code>(get|set)[0-9]*ReAuthJSON</code><br />
* <code>(get|set)[0-9]*ReAuthXPath</code><br />
* <code>(get|set)[0-9]*ReAuthXPath-Strict</code><br />
<br />
reAuthJSON or reAuthXPath typically only extract one piece of data from a response. <br />
If the existence of the specified piece of data is sufficent to start a login procedure, then nothing more needs to be defined to detect this situation. <br />
If however the indicator is a status code that contains different values depending on a successful request and a failed request if a new authentication is needed, <br />
then you can combine things like reAuthJSON with reAuthRegex. In this case the regex is only matched to the data extracted by JSON (or XPath). <br />
This way you can easily extract the status code using JSON parsing and then specify the code that means "authentication needed" as a regular expression.<br />
<br />
If for one step not all of the URL, Data or Header Attributes are set, then HTTPMOD tries to use a <br />
<code>sidURL</code>, <code>sidData.*</code> or <code>sidHeader.*</code> Attribute (without the step number after sid). This way parts that are the same for all steps don't need to be defined redundantly.<br />
<br />
=== Example for a multi step login procedure: ===<br />
<syntaxhighlight lang="perl"><br />
attr PM reAuthRegex /html/dummy_login.htm <br />
attr PM sidURL http://192.168.70.90/cgi-bin/webgui.fcgi?sid=$sid<br />
attr PM sidHeader1 Content-Type: application/json<br />
attr PM sid1IDRegex wui.init\('([^']+)'<br />
attr PM sid2Data {"set" :{"9.17401.user" :"fhem" ,"9.17401.pass" :"password" }}<br />
attr PM sid3Data {"set" :{"35.5062.value" :"128" }}<br />
attr PM sid4Data {"set" :{"42.8026.code" :"pincode" }}<br />
</syntaxhighlight><br />
<br />
In this case HTTPMOD detects that a login is necessary by looking for the pattern /html/dummy_login.htm in the HTTP response. <br />
If it matches, it starts a login sequence. In the above example all steps request the same URL. In step 1 only the defined Header is sent in an HTTP get request. The response will contain a session id that is extraced with the regex wui.init\('([^']+)'.<br />
<br />
In the next step this session id is sent in a post request to the same URL where tha post data contains a username and password. The a third and a fourth request follow that set a value and a code. The result will be a valid and authorized session id that can be used in other requests where $sid is part of a URL, header or post data and will be replaced with the session id extracted above.<br />
<br />
In the special case where a session id is set as a HTTP-Cookie (with the header Set-cookie: in the HTTP response) HTTPMOD offers an even simpler way. With the attribute enableCookies a very basic cookie handling mechanism is activated that stores all cookies that the server sends to the HTTPMOD device and puts them back as cookie headers in the following requests.<br />
<br />
For such cases no sidIdRegex and no $sid in a user defined header is necessary.<br />
<br />
== Advanced configuration to define a <code>get</code> and request additional data with its own request from a device ==<br />
<br />
The normal automatic HTTP request that is done repeatedly after the defined interval has elapsed works well in cases where all required readings can be requested in one common HTTP request. If however a device needs individual requests with different URLs or different POST data for each value, then another method is necessary. <br />
For such cases a <code>get</code> option can be defined and the user can either issue FHEM <code>get</code> commands each time he needs the reading or the user can set an attribute to request the reading automatically together with the normal iteration.<br />
For each <code>get</code> option attributes define an individual URL, optional headers, and post data as well as individual regular expressions and formatting options. <br />
<br />
When a get option is defined by attributes, the module allows querying additional values from the device that require individual HTTP-Requests or special parameters to be sent<br />
<br />
Extension to the above example:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr PM get01Name MyGetValue <br><br />
attr PM get01URL http://MyPoolManager/cgi-bin/directory/webgui.fcgi?special=1?sid=$sid <br><br />
attr PM getHeader1 Content-Type: application/json <br><br />
attr PM get01Data {"get" :{"30.1234.value"}} <br><br />
</syntaxhighlight><br />
<br />
This example defines a get option with the name MyGetValue.<br />
By issuing <code>get PM MyGetValue</code> in FHEM, the defined HTTP request is sent to the device.<br />
The HTTP response is then parsed using the same readingXXName and readingXXRegex attributes as above so<br />
additional pairs will probably be needed there for additional values.<br />
<br />
if you prefer to define the parsing and formatting of readings individually per get command, you can use <br />
attributes like get01Regex, get01XPath, get01Format, get01OMap and so on just like for reading01...<br />
<br />
You can also include parameters / values that are passed to the get command in the request just like for set commands.<br />
The placeholder $val will be replaced with the value given to the get command or you can specify your own replacement as described above.<br />
<br />
If the new get parameter should also be queried regularly, you can define the following optional attributes:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr PM get01Poll 1<br />
attr PM get01PollDelay 300<br />
</syntaxhighlight><br />
<br />
The first attribute includes this reading in the automatic update cycle and the second defines an alternative lower update frequency. When the interval defined initially in the define is over and the normal readings are read from the device, the update function will check for additional get parameters that should be included in the update cycle.<br />
<br />
If a PollDelay is specified for a get parameter, the update function also checks if the time passed since it has last read this value is more than the given PollDelay. If not, this reading is skipped and it will be rechecked in the next cycle when interval is over again. So the effective PollDelay will always be a multiple of the interval specified in the initial define.<br />
<br />
Please note that each defined get command that is included in the regular update cycle will create its own HTTP request. So if you want to extract several values from the same request, it is much more efficient to do this by defining readingXXName and readingXXRegex, XPath or JSON attributes and to specify an interval and a URL in the define of the HTTPMOD device. <br />
<br />
Example for a Siemens webserver provided by Lanhydrock:<br />
<syntaxhighlight lang="perl"><br />
define ozw672 HTTPMOD https://192.168.178.8/api/auth/login.json?user=test&pwd=test 300<br />
<br />
attr ozw672 get1Name tempAussen<br />
attr ozw672 get1URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1960<br />
attr ozw672 get1Poll 1<br />
attr ozw672 get1PollDelay 1800<br />
<br />
attr ozw672 get2Name tempAussenGemischt<br />
attr ozw672 get2URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1964<br />
attr ozw672 get2Poll 1<br />
attr ozw672 get2PollDelay 1800<br />
<br />
attr ozw672 get3Name tempTWW<br />
attr ozw672 get3URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1996<br />
attr ozw672 get3Poll 1<br />
<br />
attr ozw672 get4Name tempKesselSoll<br />
attr ozw672 get4URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1910<br />
attr ozw672 get4Poll 1<br />
<br />
attr ozw672 get5Name tempKesselRuecklauf<br />
attr ozw672 get5URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1915<br />
attr ozw672 get5Poll 1<br />
<br />
attr ozw672 get6Name tempKesselRuecklaufSoll<br />
attr ozw672 get6URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1916<br />
attr ozw672 get6Poll 1<br />
<br />
attr ozw672 get7Name anzahlStartsBrenner<br />
attr ozw672 get7URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1927<br />
attr ozw672 get7PollDelay 1800<br />
attr ozw672 get7Poll 1<br />
<br />
attr ozw672 get8Name statusKessel<br />
attr ozw672 get8URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1898<br />
attr ozw672 get8Poll 1<br />
attr ozw672 get8Regex Value": "([a-zA-Zü ]*)"<br />
attr ozw672 get8OMap Aus:0, Nachlauf aktiv:5, Freigegeben für TWW:10, Freigegeben für HK:20, In Teillastbetrieb für TWW:40, In Teillastbetrieb für HK:50, In Betrieb für Trinkwasser:90, In Betrieb für Heizkreis:100<br />
<br />
attr ozw672 getRegex Value": "[ ]*([-.0-9]*)"<br />
<br />
attr ozw672 reAuthRegex .*session not valid.*<br />
attr ozw672 sid1IDRegex .*"(.*-.*-.*-[0-9a-z]*).*<br />
attr ozw672 sid1URL https://192.168.178.8/api/auth/login.json?user=test&pwd=test<br />
</syntaxhighlight><br />
<br />
== All attributes ==<br />
;reading[0-9]+Name<br />
:the name of a reading to extract with the corresponding readingRegex, readingJSON, readingXPath or readingXPath-Strict<br />
:Please note that the old syntax <b>readingsName.*</b> does not work with all features of HTTPMOD and should be avoided. It might go away in a future version of HTTPMOD.<br />
<br />
;(get|set)[0-9]+Name<br />
:Name of a get or set command<br />
:If the HTTP response that is received after the command is parsed with an individual parse option then this name is also used as a reading name. Please note that no individual parsing needs to be defined for a get or set. If no regex, XPath or JSON is specified for the command, then HTTPMOD will try to parse the response using all the defined readingRegex, reading XPath or readingJSON attributes.<br />
<br />
;(get|set|reading)[0-9]+Regex<br />
:If this attribute is specified, the Regex defined here is used to extract the value from the HTTP Response and assign it to a Reading with the name defined in the (get|set|reading)[0-9]+Name attribute.<br />
:If this attribute is not specified for an individual Reading or get or set but without the numbers in the middle, e.g. as getRegex or readingRegex, then it applies to all the other readings / get / set commands where no specific Regex is defined.<br><br />
:The value to extract should be in a capture group / sub expression e.g. ([\d\.]+) in the above example. Multiple capture groups will create multiple readings (see explanation above)<br />
:Using this attribute for a set command (setXXRegex) only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
:Please note that the old syntax <code>readingsRegex.*</code> does not work with all features of HTTPMOD and should be avoided. It might go away in a future version of HTTPMOD.<br />
:If for get or set commands neither a generic Regex attribute without numbers nor a specific (get|set)[0-9]+Regex attribute is specified and also no XPath or JSON parsing specification is given for the get or set command, then HTTPMOD tries to use the parsing definitions for general readings defined in reading[0-9]+Name, reading[0-9]+Regex or XPath or JSON attributes and assigns the Readings that match here.<br />
<br />
;(get|set|reading)[0-9]+RegOpt<br />
:Lets the user specify regular expression modifiers. For example if the same regular expression should be matched as often as possible in the HTTP response, then you can specify RegOpt g which will case the matching to be done as /regex/g<br />
:The results will be trated the same way as multiple capture groups so the reading name will be extended with -number. <br />
:For other possible regular expression modifiers see http://perldoc.perl.org/perlre.html#Modifiers<br />
<br />
;(get|set|reading)[0-9]+XPath<br />
:defines an xpath to one or more values when parsing HTML data (see examples above)<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;get|set|reading[0-9]+XPath-Strict<br />
:defines an xpath to one or more values when parsing XML data (see examples above)<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;(get|set|reading)[0-9]+AutoNumLen<br />
:In cases where a regular expression or an XPath results in multiple results and these results are stored in a common reading name with extension -number, then you can modify the format of this number to have a fixed length with leading zeros. AutoNumLen 3 for example will lead to reading names ending with -001 -002 and so on.<br />
<br />
;(get|set|reading)[0-9]+AlwaysNum<br />
:if set to 1 this attributes forces reading names to end with a -1, -01 (depending on the above described AutoNumLen) even if just one value is parsed.<br />
<br />
;get|set|reading[0-9]+JSON<br />
:defines a path to the JSON object wanted by concatenating the object names. See the above example.<br />
:If you don't know the paths, then start by using extractAllJSON and the use the names of the readings as values for the JSON attribute.<br><br />
:Please don't forget to also specify a name for a reading, get or set. <br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;(get|set|reading)[0-9]*RecombineExpr<br />
:defines an expression that is used in an eval to compute one reading value out of the list of matches.<br />
:This is supposed to be used for regexes or xpath specifications that produce multiple results if only one result that combines them is wanted. The list of matches will be in the variable @matchlist.<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;get[0-9]*CheckAllReadings<br />
:this attribute modifies the behavior of HTTPMOD when the HTTP Response of a get command is parsed. <br><br />
:If this attribute is set to 1, then additionally to the matching of the corresponding get specific regex (get[0-9]*Regex), XPath or JSON attribute also all the reading names and parse definitions defined in Reading[0-9]+Name and Reading[0-9]+Regex, XPath or JSON attributes are checked and if they match, the coresponding Readings are assigned as well.<br />
:Please note that this does not mean that get01CheckAllReadings will cause a get02Regex to be used. Only the corresponding get01Regex will be used but additionally all the readingXYRegex attributes.<br />
:This is automatically done if a get or set command is defined without its own parse attributes.<br />
<br />
;(get|reading)[0-9]*OExpr<br />
:defines an optional expression that is used in an eval to compute / format a readings value after parsing an HTTP response<br />
:The raw value from the parsing will be in the variable $val.<br />
:If specified as readingOExpr then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Expr.<br />
:Please note that the old syntax <b>readingsExpr.*</b> does not work with all features of HTTPMOD and should be avoided. It might go away in a future version of HTTPMOD.<br />
<br />
;(get|reading)[0-9]*Expr<br />
:This is the old syntax for (get|reading)[0-9]*OExpr. It should be replaced by (get|reading)[0-9]*OExpr. The set command upgradeAttributes which becomes visible when the attribute enableControlSet is set to 1, can do this renaming automatically.<br />
<br />
;(get|reading)[0-9]*OMap<br />
:Map that defines a mapping from raw value parsed to visible values like "0:mittig, 1:oberhalb, 2:unterhalb".<br />
:If specified as readingOMap then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Map.<br><br />
:The individual options in a map are separated by a komma and an optional space. Spaces are allowed to appear in a visible value however kommas are not possible.<br />
<br />
;(get|reading)[0-9]*Map<br />
:This is the old syntax for (get|reading)[0-9]*OMap. It should be replaced by (get|reading)[0-9]*OMap. The set command upgradeAttributes which becomes visible when the attribute enableControlSet is set to 1, can do this renaming automatically.<br />
<br />
;(get|set|reading)[0-9]*Format<br />
:Defines a format string that will be used in sprintf to format a reading value.<br />
:If specified without the numbers in the middle e.g. as readingFormat then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Format.<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br><br />
<br />
;(get|set|reading)[0-9]*Decode<br />
:defines an encoding to be used in a call to the perl function decode to convert the raw data string read from the device to a reading. <br />
:This can be used if the device delivers strings in an encoding like cp850 instead of utf8.<br />
:If your reading values contain Umlauts and they are shown as strange looking icons then you probably need to use this feature.<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;(get|set|reading)[0-9]*Encode<br />
:defines an encoding to be used in a call to the perl function encode to convert the raw data string read from the device to a reading. <br />
:This can be used if the device delivers strings in an encoding like cp850 and after decoding it you want to reencode it to e.g. utf8.<br />
:If your reading values contain Umlauts and they are shown as strange looking icons then you probably need to use this feature.<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;(get|set)[0-9]*URL<br />
:URL to be requested for the set or get command. If this option is missing, the URL specified during define will be used.<br />
<br />
;(get|set)[0-9]*Data<br />
:Data to be sent to the device as POST data when the get or set command is executed. if this attribute is not specified, an HTTP GET method will be used instead of an HTTP POST<br />
<br />
;(get|set)[0-9]*NoData<br />
:can be used to override a more generic attribute that specifies POST data for all get or set commands. With NoData no data is sent and therefor the request will be an HTTP GET.<br />
<br />
;(get|set)[0-9]*Header.*<br />
:HTTP Headers to be sent to the device when the set is executed<br />
<br />
;requestHeader.*<br />
:Define an optional additional HTTP Header to set in the HTTP request of the main loop<br />
<br />
;requestData<br />
:optional POST Data to be sent in the request of the main loop. If not defined, it will be an HTTP GET request as defined in HttpUtils which is used by this module<br />
<br />
;get[0-9]+Poll<br />
:if set to 1 the get is executed automatically during the normal update cycle (after the interval provided in the define command has elapsed)<br />
<br />
;get[0-9]+PollDelay<br />
:if the value should not be read in each iteration (after the interval given to the define command), then a minimum delay can be specified with this attribute. This has only an effect if the above Poll attribute has also been set. Every time the update function is called, it checks if since this get has been read the last time, the defined delay has elapsed. If not, then it is skipped this time.<br />
:PollDelay can be specified as seconds or as x[0-9]+ which means a multiple of the interval in the define command.<br />
<br />
;(get|set)[0-9]*TextArg<br />
:For a get command this defines that the command accepts a text value after the option name. By default a get command doesn't accept optional values after the command name. <br />
:If TextArg is specified and a value is passed after the get name then this value can then be used in a request URL, header or data as replacement for $val or in a user defined replacement that uses the internal "value" ($hash->{value}).<br />
:If used for a set command then it defines that the value to be set doesn't require any validation / conversion. <br />
:The raw value is passed on as text to the device. By default a set command expects a numerical value or a text value that is converted to a numeric value using a map.<br />
<br />
;set[0-9]+Min<br />
:Minimum value for input validation. <br />
<br />
;set[0-9]+Max<br />
:Maximum value for input validation. <br />
<br />
;set[0-9]+IExpr<br />
:Perl Expression to compute the raw value to be sent to the device from the input value passed to the set.<br />
<br />
;set[0-9]+Expr<br />
:This is the old syntax for (get|reading)[0-9]*IExpr. It should be replaced by (get|reading)[0-9]*IExpr. The set command upgradeAttributes which becomes visible when the attribute enableControlSet is set to 1, can do this renaming automatically.<br />
<br />
;set[0-9]+IMap<br />
:Map that defines a mapping from raw to input values like "0:mittig, 1:oberhalb, 2:unterhalb". This attribute atomatically creates a hint for FHEMWEB so the user can choose one of the input values.<br />
<br />
;set[0-9]+Map<br />
:This is the old syntax for (get|reading)[0-9]*IMap. It should be replaced by (get|reading)[0-9]*IMap. The set command upgradeAttributes which becomes visible when the attribute enableControlSet is set to 1, can do this renaming automatically.<br />
<br />
;set[0-9]+Hint<br />
:Explicit hint for fhemWEB that will be returned when set ? is seen. Can be used to get a slider or a list of values to choose from.<br />
<br />
;set[0-9]*NoArg<br />
:Defines that this set option doesn't require arguments. It allows sets like "on" or "off" without further values.<br />
<br />
;set[0-9]*ParseResponse<br />
:defines that the HTTP response to the set will be parsed as if it was the response to a get command.<br />
<br />
<br />
;(get|set)[0-9]*URLExpr<br />
:Defines a Perl expression to specify the HTTP Headers for this request. This overwrites any other header specification and should be used carefully only if needed. The original Header is availabe as $old. Typically this feature is not needed and it might go away in future versions of HTTPMOD. Please use the "replacement" attributes if you want to pass additional variable data to a web service. <br />
<br />
;(get|set)[0-9]*DatExpr<br />
:Defines a Perl expression to specify the HTTP Post data for this request. This overwrites any other post data specification and should be used carefully only if needed. The original Data is availabe as $old. Typically this feature is not needed and it might go away in future versions of HTTPMOD. Please use the "replacement" attributes if you want to pass additional variable data to a web service. <br />
<br />
;(get|set)[0-9]*HdrExpr<br />
:Defines a Perl expression to specify the URL for this request. This overwrites any other URL specification and should be used carefully only if needed. The original URL is availabe as $old. Typically this feature is not needed and it might go away in future versions of HTTPMOD. Please use the "replacement" attributes if you want to pass additional variable data to a web service. <br />
<br />
;ReAuthRegex<br />
:regular Expression to match an error page indicating that a session has expired and a new authentication for read access needs to be done. <br />
:This attribute only makes sense if you need a forms based authentication for reading data and if you specify a multi step login procedure based on the sid.. attributes.<br />
:This attribute is used for all requests. For set and get operations you can however specify individual reAuthRegexes with the (get|set)[0-9]*ReAuthRegex attributes.<br />
<br />
;(get|set)[0-9]*ReAuthRegex<br />
:Regex that will detect when a session has expired during a set operation and a new login needs to be performed.<br />
:It works like the global reAuthRegex but is used for set operations.<br />
<br />
;sid[0-9]*URL<br />
:different URLs or one common URL to be used for each step of an optional login procedure. <br />
<br />
;sid[0-9]*IDRegex<br />
:different Regexes per login procedure step or one common Regex for all steps to extract the session ID from the HTTP response<br />
<br />
;sid[0-9]*Data.*<br />
:data part for each step to be sent as POST data to the corresponding URL<br />
<br />
;sid[0-9]*Header.*<br />
:HTTP Headers to be sent to the URL for the corresponding step<br />
<br />
;sid[0-9]*IgnoreRedirects<br />
:Tells the HttpUtils to not follow HTTP Redirects for this Request. Might be needed for some devices that set a session cookie within a 303 Redirect.<br />
<br />
;clearSIdBeforeAuth<br />
:will set the session id to "" before doing the authentication steps<br />
<br />
;authRetries<br />
:number of retries for authentication procedure - defaults to 1<br />
<br />
;replacement[0-9]*Regex<br />
:Defines a replacement to be applied to an HTTP request header, data or URL before it is sent. This allows any part of the request to be modified based on a reading, an internal or an expression.<br />
:The regex defines which part of a header, data or URL should be replaced. The replacement is defined with the following attributes:<br />
<br />
;replacement[0-9]*Mode<br />
:Defines how the replacement should be done and what replacementValue means. Valid options are text, reading, internal and expression.<br />
<br />
;replacement[0-9]*Value<br />
:Defines the replacement. If the corresponding replacementMode is <code>text</code>, then value is a static text that is used as the replacement.<br />
:If replacementMode is <code>reading</code> then Value can be the name of a reading of this device or it can be a reading of a different device referred to by devicename:reading.<br />
:If replacementMode is <code>internal</code> the Value can be the name of an internal of this device or it can be an internal of a different device referred to by devicename:internal.<br />
:If replacementMode is <code>expression</code> the the Value is treated as a Perl expression that computes the replacement value. The expression can use $1, $2 and so on to refer to capture groups of the corresponding regex that is matched against the original URL, header or post data.<br />
:If replacementMode is <code>key</code> then the module will use a value from a key / value pair that is stored in an obfuscated form in the file system with the set storeKeyValue command. This might be useful for storing passwords.<br />
<br />
;[gs]et[0-9]*Replacement[0-9]*Value<br />
:This attribute can be used to override the replacement value for a specific get or set.<br />
<br />
;get|reading[0-9]*MaxAge<br />
:Defines how long a reading is valid before it is automatically overwritten with a replacement when the read function is called the next time.<br />
<br />
;get|reading[0-9]*MaxAgeReplacement<br />
:specifies the replacement for MaxAge - either as a static text or as a perl expression.<br />
<br />
;get|reading[0-9]*MaxAgeReplacementMode<br />
:specifies how the replacement is interpreted: can be text, expression and delete.<br />
<br />
;get|reading[0-9]*DeleteIfUnmatched<br />
:If set to 1 this attribute causes certain readings to be deleted when the parsing of the website does not match the specified reading. Internally HTTPMOD remembers which kind of operation created a reading (update, Get01, Get02 and so on). Specified readings will only be deleted if the same operation does not parse this reading again. This is especially useful for parsing that creates several matches / readings and the number of matches can vary from request to request. For example if reading01Regex creates 4 readings in one update cycle and in the next cycle it only matches two times then the readings containing the remaining values from the last round will be deleted.<br />
:Please note that this mechanism will not work in all cases after a restart. Especially when a get definition does not contain its own parsing definition but ExtractAllJSON or relies on HTTPMOD to use all defined reading.* attributes to parse the responsee to a get command, old readings might not be deleted after a restart of fhem.<br />
;get|reading[0-9]*DeleteOnError<br />
:If set to 1 this attribute causes certain readings to be deleted when the website can not be reached and the HTTP request returns an error. Internally HTTPMOD remembers which kind of operation created a reading (update, Get01, Get02 and so on). Specified readings will only be deleted if the same operation returns an error.<br />
The same restrictions as for DeleteIfUnmatched apply regarding a fhem restart.<br />
<br />
<br />
;httpVersion<br />
:defines the HTTP-Version to be sent to the server. This defaults to 1.0.<br />
<br />
;sslVersion<br />
:defines the SSL Version for the negotiation with the server. The attribute is evaluated by HttpUtils. If it is not specified, HttpUtils assumes SSLv23:!SSLv3:!SSLv2<br />
<br />
;sslArgs<br />
:defines a list that is converted to a key / value hash and gets passed to HttpUtils. To avoid certificate validation for broken servers you can for example specify <br />
:<code>attr myDevice sslArgs SSL_verify_mode,SSL_VERIFY_NONE</code><br />
<br />
;alignTime<br />
:Aligns each periodic read request for the defined interval to this base time. This is typcally something like 00:00 (see the FHEM at command)<br />
<br />
;noShutdown<br />
:pass the noshutdown flag to HTTPUtils for webservers that need it (some embedded webservers only deliver empty pages otherwise)<br />
<br />
;disable<br />
:stop doing automatic HTTP requests while this attribute is set to 1<br />
<br />
;enableControlSet<br />
:enables the built in set commands interval, stop, start, reread, upgradeAttributes, storeKeyValue.<br />
<br />
;enableCookies<br />
:enables the built in cookie handling if set to 1. With cookie handling each HTTPMOD device will remember cookies that the server sets and send them back to the server in the following requests. <br />
:This simplifies session magamenet in cases where the server uses a session ID in a cookie. In such cases enabling cookies should be sufficient and no sidRegex and no manual definition of a cookie header should be necessary.<br />
<br />
;showMatched<br />
:if set to 1 then HTTPMOD will create a reading with the name MATCHED_READINGS that contains the names of all readings that could be matched in the last request as well as UNMATCHED_READINGS and LAST_REQUEST.<br />
<br />
;showError<br />
:if set to 1 then HTTPMOD will create a reading and event with the Name LAST_ERROR that contains the error message of the last error returned from HttpUtils. <br />
<br />
;removeBuf<br />
:if set to 1 then HTTPMOD removes the internal named buf when a HTTP-response has been received. <br />
:$hash->{buf} is used internally be Fhem httpUtils and in some use cases it is desireable to remove this internal after reception <br />
:because it contains a very long response which looks ugly in Fhemweb.<br />
<br />
;timeout<br />
:time in seconds to wait for an answer. Default value is 2<br />
<br />
;queueDelay<br />
:HTTP Requests will be sent from a queue in order to avoid blocking when several Requests have to be sent in sequence. This attribute defines the delay between calls to the function that handles the send queue. It defaults to one second.<br />
<br />
;queueMax<br />
:Defines the maximum size of the send queue. If it is reached then further HTTP Requests will be dropped and not be added to the queue<br />
<br />
;minSendDelay<br />
:Defines the minimum time between two HTTP Requests.<br />
<br />
== Links ==<br />
* Example: [[Wetter_und_Wettervorhersagen#Wetter_von_Weather_Underground|Extract weather information from WeatherUnderground]]<br />
* Example: [[Pollenflug|Pollen count]]<br />
* Example: [[HTTPMOD Beispielkonfiguration zur Anbindung einer Daikin Klimaanlage mit WLAN-Modul|Connect Daikin aircondition to FHEM]]<br />
* Example: [[Go-eCharger|Extract information from go-eCharger]]<br />
* Example: [[Sonnenspeicher|Integration of energy supplies from sonnen (https://sonnenbatterie.de/en/start)]]<br />
* Example: [https://forum.fhem.de/index.php/topic,95989.msg915870.html#msg915870 Miele 3rd party API für Miele Smarthome Geräte]<br />
* Example: [https://forum.fhem.de/index.php/topic,84215.msg918662.html#msg918662 Honeywell Evohome Totalconnect]<br />
* {{Link2Forum|Topic=17804|LinkText=Thread}} in FHEM Forum that discusses the first version of this module <br />
* {{Link2Forum|Topic=29471|LinkText=Thread}} in FHEM Forum that discusses the second major version of this module <br />
* {{Link2Forum|Topic=45176|LinkText=Thread}} in FHEM Forum that discusses the third major version of this module <br />
* [http://perldoc.perl.org/perlretut.html Introduction to regular expressions]<br />
* [http://portswigger.net/burp/ BurpSuite]: Tool (local proxy) to help analyze http traffic<br />
<br />
[[Kategorie:IP Components]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=FHEM_mit_HTTPS_SSL-Zertifikat_und_eine_eigene_Zertifizierungsstelle&diff=29592FHEM mit HTTPS SSL-Zertifikat und eine eigene Zertifizierungsstelle2019-02-19T21:09:06Z<p>Amenomade: /* Bekannte Probleme */</p>
<hr />
<div>== Vorwort ==<br />
=== Dein Anliegen ===<br />
Du möchtest FHEM mit HTTPS betreiben, hasst es aber, ständig von Deinem Browser darauf aufmerksam gemacht zu werden, dass dies "keine sichere Verbindung" ist. <br />
Oder Du möchtest einen weiteren Serverdienst aufsetzen, welcher verschlüsselte SSL oder TLS-Verbindungen anbietet (z.B. HTTPS, POP3S, IMAPS, LDAPS, SMTP mit TLS).<br />
<br />
=== Die Schwierigkeit dabei ===<br />
Um eine mit SSL/TLS abgesicherte Verbindung anzubieten, benötigst Du ein Serverzertifikat. Dieses muss von einer Zertifizierungsstelle (Certification Authority oder kurz CA) signiert sein.<br />
Ein offizielles Serverzertifikat, welches von einer offiziellen Stelle signiert ist, ist leider nicht kostenlos. Meist werden jährliche Gebühren in Höhe von mehreren hundert Euro fällig.<br />
<br />
=== Eine mögliche Lösung ===<br />
Unter Linux kann man mit Bordmitteln eine eigene CA aufsetzen und selbst ein Zertifikate erstellen und signieren. Das ist ein Vorgang von wenigen Minuten. Alle Einzelheiten beschreibt dieser Artikel.<br />
Der einzige Unterschied zu einem von einer anerkannten Stelle signierten Zertifikat ist, dass der Client (Emailprogramm, Browser, etc.) einmalig das root CA importieren muß.<br />
<br />
== Genaues Vorgehen ==<br />
=== OpenSSL installieren ===<br />
Für die Verwaltung der Zertifikate und im übrigen auch für die Verschlüsselung der Verbindungen mit SSL und TLS kommt unter Linux fast immer OpenSSL zum Einsatz. Wahrscheinlich ist das auf Deinem Sytem deshalb bereits installiert, wenn nicht, musst Du das Paket openssl nachinstallieren. Du benötigst aus diesem Paket den Kommandozeilenbefehl openssl.<br />
<br />
=== Erstellen der CA ===<br />
Lege zunächst ein Verzeichnis an, in dem Du das Zertifikat ablegen willst. Wir nehmen in unserem Beispiel /root/ca:<br />
<source lang="bash"><br />
root@linux# mkdir /root/ca<br />
root@linux# cd /root/ca</source><br />
Die Gültigkeit setzen wir mit 10 Jahren bewusst sehr hoch an. Läuft die CA aus, so werden nämlich auch alle damit signierten Serverzertifikate ungültig. Die CA enthält einen geheimen Schlüssel, welcher automatisch erzeugt und in der Datei cakey.pem abgelegt wird. Das CA-Zertifikat wird nach cacert.pem geschrieben. Der folgende Befehl erzeugt das einen Schlüssel für das Zertifikat mit einer Länge von 2048 Bit:<br />
<source lang="bash"><br />
root@linux# openssl req -new -x509 -newkey rsa:2048 -keyout cakey.pem -out cacert.pem -days 3650<br />
Generating a 2048 bit RSA private key<br />
..............................................................<br />
..............................................................<br />
.........................................+++<br />
......................................+++<br />
writing new private key to 'cakey.pem'</source><br />
<br />
Wer den geheimen Schlüssel der CA kennt, kann damit beliebige Serverzertifikate signieren. Deshalb wird diese Schlüsseldatei nicht im Klartext auf der Festplatte abgelegt, sondern mit einer Passphrase verschlüsselt. Diese Passphrase benötigst Du immer dann, wenn Du mit der CA neue Zertifikate ausstellen willst:<br />
<nowiki><br />
Enter PEM pass phrase: sehrlangesgeheimespasswort<br />
Verifying - Enter PEM pass phrase: sehrlangesgeheimespasswort</nowiki><br />
Nun werden wir gebeten, Daten einzugeben, welche die CA identifizieren. Diese werden dem Client angezeigt, wenn er aufgefordert wird, das Zertifikat zu akzeptieren oder abzulehnen. Der Code für Deutschland ist DE. Wenn Du ein Feld leer lassen möchtest, so gib einen Punkt ein. Ansonsten wird der in eckigen Klammern stehende Defaultwert eingetragen:<br />
<nowiki><br />
-----<br />
You are about to be asked to enter information that will be incorporated<br />
into your certificate request.<br />
What you are about to enter is what is called a Distinguished Name or a DN.<br />
There are quite a few fields but you can leave some blank<br />
For some fields there will be a default value,<br />
If you enter '.', the field will be left blank.<br />
-----<br />
Country Name (2 letter code) [AU]: DE<br />
State or Province Name (full name) [Some-State]:Brandenburg<br />
Locality Name (eg, city) []:Potsdam<br />
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Familie AG<br />
Organizational Unit Name (eg, section) []:EDV</nowiki><br />
Das Feld Common Name (CN) ist hier der offizielle Name der Zertifizierungsstelle. Für Dein eigenes CA kannst Du einfach Deinen eigenen Namen eintragen:<br />
<nowiki><br />
Common Name (eg, YOUR name) []: Cool Tux<br />
Email Address []: cooltux@gmail.tada</nowiki><br />
Fertig. Folgende zwei Dateien sind entstanden:<br />
<nowiki><br />
root@linux# ll<br />
insgesamt 9<br />
drwxr-xr-x 2 root root 112 2006-04-30 12:08 .<br />
drwx------ 12 root root 600 2006-04-30 11:54 ..<br />
-rw-r--r-- 1 root root 1212 2006-04-30 12:08 cacert.pem<br />
-rw-r--r-- 1 root root 963 2006-04-30 12:08 cakey.pem</nowiki><br />
Vorsichtshalber solltest Du die Rechte so setzen, dass die Schlüsseldatei nur für root lesbar ist:<br />
<nowiki><br />
root@linux# chmod 600 cakey.pem</nowiki><br />
Du kannst nun ausprobieren, ob Du den Schlüssel mit der Passphrase wieder öffnen kannst:<br />
<nowiki><br />
root@linux# openssl rsa -in cakey.pem -noout -text<br />
Enter pass phrase for cakey.pem: wrzlprmpft<br />
Private-Key: (1024 bit)<br />
modulus:<br />
00:d5:a5:37:51:e9:d9:fa:e3:97:e7:46:b2:88:1a:<br />
b5:46:80:47:76:14:ae:2b:8b:3e:35:5c:ab:15:84:<br />
53:d9:63:2e:7f:08:4b:ec:77:db:02:45:f8:c7:46:<br />
58:cd:2d:f9:29:4d:96:3d:d8:6c:5d:9f:79:8a:04:<br />
cf:b7:3a:89:da:a9:63:9f:44:b3:83:cf:0d:70:7d:</nowiki><br />
usw...<br />
<br />
=== Schlüssel für das Serverzertifikat erzeugen ===<br />
Nachdem wir nun eine eigene CA haben, kann diese nun endlich für unseren Server ein Zertifikat herausgeben. Dazu erzeugen wir zunächst einen 2048 Bit langen RSA Schlüssel, der mit AES 128 verschlüsselt auf der Platte abgelegt wird (ja wirklich, auch hier wieder ein verschlüsselter Schlüssel). Die Passphrase muss diesmal nicht sonderlich geheim sein, da wir sie ohnehin im Anschluss wieder entfernen werden. OpenSSL lässt allerdings keine leere Phrase zu:<br />
<source lang="bash"><br />
root@linux# openssl genrsa -out serverkey.pem -aes128 2048<br />
Generating RSA private key, 2048 bit long modulus<br />
....+++<br />
.......................................+++<br />
e is 65537 (0x10001)<br />
Enter pass phrase for serverkey.pem: test<br />
Verifying - Enter pass phrase for serverkey.pem: test</source><br />
So. Nun entfernen wir die Passphrase wieder. Warum? Der Serverdienst (Apache, Cyrus, etc.) muss schließlich in der Lage sein, den Schlüssel ohne Dein Zutun zu lesen. Oder möchtest Du bei jedem Booten des Servers ein Passwort eingeben müssen?<br />
<source lang="bash"><br />
root@linux# openssl rsa -in serverkey.pem -out serverkey.pem<br />
Enter pass phrase for serverkey.pem: jaja<br />
writing RSA key</source><br />
<br />
=== Certificate Signing Request erzeugen ===<br />
Der nächste Schritt zum eigenen Zertifikat ist ein CSR. Dies muss dann nur noch von der CA signiert werden. Hier sind wieder Angaben analog zum Erstellen der CA nötig, was oft Verwirrung stiftet. Die allgemeinen Daten kann man ggfl. gleich wie oben eingeben:<br />
<source lang="bash"><br />
root@linux# openssl req -new -key serverkey.pem -out req.pem -nodes<br />
You are about to be asked to enter information that will be incorporated<br />
into your certificate request.<br />
What you are about to enter is what is called a Distinguished Name or a DN.<br />
There are quite a few fields but you can leave some blank<br />
For some fields there will be a default value,<br />
If you enter '.', the field will be left blank.<br />
-----<br />
Country Name (2 letter code) [AU]: DE<br />
State or Province Name (full name) [Some-State]:Brandenburg<br />
Locality Name (eg, city) []:Potsdam<br />
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Familie AG<br />
Organizational Unit Name (eg, section) []:EDV</source><br />
ACHTUNG, jetzt kommt das Wichtige: Beim Serverzertifikat ist der Common Name von entscheidender Bedeutung. Hier muss der DNS-Name stehen, unter dem der Client den Server anspricht! Wird das Zertifikat für eine HTTPS-Verbindung zu fhem.local verwendet, so muss der Common Name eben genau fhem.local heißen. Anderfalls wird der Browser das Zertifikat nicht akzeptieren, da er davon ausgehen muss, auf dem falschen Server gelandet zu sein.<br />
<nowiki><br />
Common Name (eg, YOUR name) []: fhem.local<br />
Email Address []: admin.fhem.local</nowiki><br />
Weitere Optionen kann man einfach leer lassen:<br />
<nowiki><br />
A challenge password []:<br />
An optional company name []:</nowiki><br />
Mittlerweile tummeln sich schon vier Dateien in unserem Verzeichnis:<br />
<source lang="bash"><br />
root@linux# ll<br />
insgesamt 17<br />
drwxr-xr-x 2 root root 168 2006-04-30 12:29 .<br />
drwx------ 12 root root 600 2006-04-30 11:54 ..<br />
-rw-r--r-- 1 root root 1212 2006-04-30 12:08 cacert.pem<br />
-rw------- 1 root root 963 2006-04-30 12:08 cakey.pem<br />
-rw-r--r-- 1 root root 1017 2006-04-30 12:29 req.pem<br />
-rw-r--r-- 1 root root 1679 2006-04-30 12:21 serverkey.pem</source><br />
<br />
=== OpenSSL-Konfiguration anpassen ===<br />
Leider kann man bei OpenSSL nicht alle Daten als Kommandozeilenargumente übergeben. Einige Einstellungen muss man lästigerweise in der Datei /etc/ssl/openssl.cnf ändern, bevor man signieren kann. Öffne diese Datei und passe folgende Zeilen in der Sektion [ CA_default ] an:<br />
<source lang="bash"><br />
/etc/ssl/openssl.cnf:<br />
dir = . # Where everything is kept<br />
new_certs_dir = $dir # default place for new certs<br />
private_key = $dir/cakey.pem # The private key<br />
RANDFILE = $dir/.rand # private random number file<br />
default_days = 3650 # how long to certify for</source><br />
Das Feld default_days ist auf 365 Tage voreingestellt und gibt die Gültigkeit des Zertifikates an. Abgelaufene Zertifikate sind im Übrigen ein sehr häufiges Problem. Wenn es soweit ist, kennt sich damit nämlich schon lange keiner mehr aus. Deswegen kannst Du wie im Beispiel angegeben die Lebensdauer z.B. auf 10 Jahre heraufsetzen.<br />
<br />
Nun muss man noch einige Dateien anlegen:<br />
<source lang="bash"><br />
root@linux# echo 01 > serial<br />
root@linux# touch index.txt</source><br />
<br />
=== Serverzertifikat signieren ===<br />
Kommen wir zum feierlichen Abschluss: Unsere CA signiert nun das Zertifikat:<br />
<source lang="bash"><br />
root@linux# openssl ca -in req.pem -notext -out servercert.pem<br />
Enter pass phrase for ./cakey.pem: langesgeheimespasswort<br />
<br />
...<br />
<br />
Certificate is to be certified until Apr 27 10:45:36 2016 GMT (3650 days)<br />
Sign the certificate? [y/n]: y<br />
<br />
<br />
1 out of 1 certificate requests certified, commit? [y/n] y<br />
Write out database with 1 new entries<br />
Data Base Updated</source><br />
<br />
=== Zertifikate installieren ===<br />
Wie Du das Zertifikat in FHEM installierst, findest Du [[Raspberry_Pi_%26_HTTPS|hier]] und wenn Du ein Server Zertifikat für NGINX installieren möchtest, findest Du Infos dazu [[HTTPS-Absicherung_%26_Authentifizierung_via_nginx_Webserver|hier]]<br />
<br />
== Nachwort ==<br />
=== Einbinden der root CA in die Zertifizierungsstelle des Browsers ===<br />
Beim Firefox importieren wir unsere cacert.pem unter Einstellungen -> Erweitert -> Zertifikate -> Zertifikate anzeigen -> Zertifizierungsstellen ein.<br />
Unter Chrome/Chromium finden wir die Zertifikatsverwaltung unter Einstellungen -> Erweitert -> Zertifikate verwalten HTTPS/SSL-Zertifikate und -Einstellungen verwalten -> Zertifizierungsstellen<br />
<br />
=== Bekannte Probleme ===<br />
Für den Chrome/Chromium müssen wir zusätzlich "Subject Alternative Names (SAN)" in unser Zertifikat eintragen. Dies geschieht beim Serverzertifikat signieren. Dazu müssen wir uns eine weitere Datei anlegen:<br />
<source lang="bash"><br />
root@linux# vim oats.extensions.cnf<br />
<br />
basicConstraints=CA:FALSE<br />
subjectAltName=@my_subject_alt_names<br />
subjectKeyIdentifier = hash<br />
<br />
[ my_subject_alt_names ]<br />
DNS.1 = fhem01.tuxnet.local<br />
DNS.2 = fhem02.tuxnet.local<br />
DNS.3 = fhem01-vpn.tuxnet.local</source><br />
<br />
Dabei die DNS.x Namen durch die DNS Namen (bzw. IP Addressen) ersetzen, womit man Fhem aufruft.<br />
<br />
Die Signierung unseres Serverzertifikates erfolgt dann mit folgendem Befehl:<br />
<source lang="bash"><br />
openssl ca -in req.pem -notext -extfile oats.extensions.cnf -out servercert.pem</source><br />
<br />
=== Prüfen von Zertifikaten ===<br />
Zertifikate kann man im übrigen auf dieser [https://www.networking4all.com/en/ssl+certificates/csr+check/| Seite] prüfen lassen.<br />
Dazu kopiert man den Inhalt der servercert.pem in das Eingabefeld der Seite und klickt dann auf Check CSR.<br />
<br />
[[Kategorie:HOWTOS]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=FHEM_mit_HTTPS_SSL-Zertifikat_und_eine_eigene_Zertifizierungsstelle&diff=29591FHEM mit HTTPS SSL-Zertifikat und eine eigene Zertifizierungsstelle2019-02-19T21:08:42Z<p>Amenomade: /* Bekannte Probleme */ Subj alt names Erklärung</p>
<hr />
<div>== Vorwort ==<br />
=== Dein Anliegen ===<br />
Du möchtest FHEM mit HTTPS betreiben, hasst es aber, ständig von Deinem Browser darauf aufmerksam gemacht zu werden, dass dies "keine sichere Verbindung" ist. <br />
Oder Du möchtest einen weiteren Serverdienst aufsetzen, welcher verschlüsselte SSL oder TLS-Verbindungen anbietet (z.B. HTTPS, POP3S, IMAPS, LDAPS, SMTP mit TLS).<br />
<br />
=== Die Schwierigkeit dabei ===<br />
Um eine mit SSL/TLS abgesicherte Verbindung anzubieten, benötigst Du ein Serverzertifikat. Dieses muss von einer Zertifizierungsstelle (Certification Authority oder kurz CA) signiert sein.<br />
Ein offizielles Serverzertifikat, welches von einer offiziellen Stelle signiert ist, ist leider nicht kostenlos. Meist werden jährliche Gebühren in Höhe von mehreren hundert Euro fällig.<br />
<br />
=== Eine mögliche Lösung ===<br />
Unter Linux kann man mit Bordmitteln eine eigene CA aufsetzen und selbst ein Zertifikate erstellen und signieren. Das ist ein Vorgang von wenigen Minuten. Alle Einzelheiten beschreibt dieser Artikel.<br />
Der einzige Unterschied zu einem von einer anerkannten Stelle signierten Zertifikat ist, dass der Client (Emailprogramm, Browser, etc.) einmalig das root CA importieren muß.<br />
<br />
== Genaues Vorgehen ==<br />
=== OpenSSL installieren ===<br />
Für die Verwaltung der Zertifikate und im übrigen auch für die Verschlüsselung der Verbindungen mit SSL und TLS kommt unter Linux fast immer OpenSSL zum Einsatz. Wahrscheinlich ist das auf Deinem Sytem deshalb bereits installiert, wenn nicht, musst Du das Paket openssl nachinstallieren. Du benötigst aus diesem Paket den Kommandozeilenbefehl openssl.<br />
<br />
=== Erstellen der CA ===<br />
Lege zunächst ein Verzeichnis an, in dem Du das Zertifikat ablegen willst. Wir nehmen in unserem Beispiel /root/ca:<br />
<source lang="bash"><br />
root@linux# mkdir /root/ca<br />
root@linux# cd /root/ca</source><br />
Die Gültigkeit setzen wir mit 10 Jahren bewusst sehr hoch an. Läuft die CA aus, so werden nämlich auch alle damit signierten Serverzertifikate ungültig. Die CA enthält einen geheimen Schlüssel, welcher automatisch erzeugt und in der Datei cakey.pem abgelegt wird. Das CA-Zertifikat wird nach cacert.pem geschrieben. Der folgende Befehl erzeugt das einen Schlüssel für das Zertifikat mit einer Länge von 2048 Bit:<br />
<source lang="bash"><br />
root@linux# openssl req -new -x509 -newkey rsa:2048 -keyout cakey.pem -out cacert.pem -days 3650<br />
Generating a 2048 bit RSA private key<br />
..............................................................<br />
..............................................................<br />
.........................................+++<br />
......................................+++<br />
writing new private key to 'cakey.pem'</source><br />
<br />
Wer den geheimen Schlüssel der CA kennt, kann damit beliebige Serverzertifikate signieren. Deshalb wird diese Schlüsseldatei nicht im Klartext auf der Festplatte abgelegt, sondern mit einer Passphrase verschlüsselt. Diese Passphrase benötigst Du immer dann, wenn Du mit der CA neue Zertifikate ausstellen willst:<br />
<nowiki><br />
Enter PEM pass phrase: sehrlangesgeheimespasswort<br />
Verifying - Enter PEM pass phrase: sehrlangesgeheimespasswort</nowiki><br />
Nun werden wir gebeten, Daten einzugeben, welche die CA identifizieren. Diese werden dem Client angezeigt, wenn er aufgefordert wird, das Zertifikat zu akzeptieren oder abzulehnen. Der Code für Deutschland ist DE. Wenn Du ein Feld leer lassen möchtest, so gib einen Punkt ein. Ansonsten wird der in eckigen Klammern stehende Defaultwert eingetragen:<br />
<nowiki><br />
-----<br />
You are about to be asked to enter information that will be incorporated<br />
into your certificate request.<br />
What you are about to enter is what is called a Distinguished Name or a DN.<br />
There are quite a few fields but you can leave some blank<br />
For some fields there will be a default value,<br />
If you enter '.', the field will be left blank.<br />
-----<br />
Country Name (2 letter code) [AU]: DE<br />
State or Province Name (full name) [Some-State]:Brandenburg<br />
Locality Name (eg, city) []:Potsdam<br />
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Familie AG<br />
Organizational Unit Name (eg, section) []:EDV</nowiki><br />
Das Feld Common Name (CN) ist hier der offizielle Name der Zertifizierungsstelle. Für Dein eigenes CA kannst Du einfach Deinen eigenen Namen eintragen:<br />
<nowiki><br />
Common Name (eg, YOUR name) []: Cool Tux<br />
Email Address []: cooltux@gmail.tada</nowiki><br />
Fertig. Folgende zwei Dateien sind entstanden:<br />
<nowiki><br />
root@linux# ll<br />
insgesamt 9<br />
drwxr-xr-x 2 root root 112 2006-04-30 12:08 .<br />
drwx------ 12 root root 600 2006-04-30 11:54 ..<br />
-rw-r--r-- 1 root root 1212 2006-04-30 12:08 cacert.pem<br />
-rw-r--r-- 1 root root 963 2006-04-30 12:08 cakey.pem</nowiki><br />
Vorsichtshalber solltest Du die Rechte so setzen, dass die Schlüsseldatei nur für root lesbar ist:<br />
<nowiki><br />
root@linux# chmod 600 cakey.pem</nowiki><br />
Du kannst nun ausprobieren, ob Du den Schlüssel mit der Passphrase wieder öffnen kannst:<br />
<nowiki><br />
root@linux# openssl rsa -in cakey.pem -noout -text<br />
Enter pass phrase for cakey.pem: wrzlprmpft<br />
Private-Key: (1024 bit)<br />
modulus:<br />
00:d5:a5:37:51:e9:d9:fa:e3:97:e7:46:b2:88:1a:<br />
b5:46:80:47:76:14:ae:2b:8b:3e:35:5c:ab:15:84:<br />
53:d9:63:2e:7f:08:4b:ec:77:db:02:45:f8:c7:46:<br />
58:cd:2d:f9:29:4d:96:3d:d8:6c:5d:9f:79:8a:04:<br />
cf:b7:3a:89:da:a9:63:9f:44:b3:83:cf:0d:70:7d:</nowiki><br />
usw...<br />
<br />
=== Schlüssel für das Serverzertifikat erzeugen ===<br />
Nachdem wir nun eine eigene CA haben, kann diese nun endlich für unseren Server ein Zertifikat herausgeben. Dazu erzeugen wir zunächst einen 2048 Bit langen RSA Schlüssel, der mit AES 128 verschlüsselt auf der Platte abgelegt wird (ja wirklich, auch hier wieder ein verschlüsselter Schlüssel). Die Passphrase muss diesmal nicht sonderlich geheim sein, da wir sie ohnehin im Anschluss wieder entfernen werden. OpenSSL lässt allerdings keine leere Phrase zu:<br />
<source lang="bash"><br />
root@linux# openssl genrsa -out serverkey.pem -aes128 2048<br />
Generating RSA private key, 2048 bit long modulus<br />
....+++<br />
.......................................+++<br />
e is 65537 (0x10001)<br />
Enter pass phrase for serverkey.pem: test<br />
Verifying - Enter pass phrase for serverkey.pem: test</source><br />
So. Nun entfernen wir die Passphrase wieder. Warum? Der Serverdienst (Apache, Cyrus, etc.) muss schließlich in der Lage sein, den Schlüssel ohne Dein Zutun zu lesen. Oder möchtest Du bei jedem Booten des Servers ein Passwort eingeben müssen?<br />
<source lang="bash"><br />
root@linux# openssl rsa -in serverkey.pem -out serverkey.pem<br />
Enter pass phrase for serverkey.pem: jaja<br />
writing RSA key</source><br />
<br />
=== Certificate Signing Request erzeugen ===<br />
Der nächste Schritt zum eigenen Zertifikat ist ein CSR. Dies muss dann nur noch von der CA signiert werden. Hier sind wieder Angaben analog zum Erstellen der CA nötig, was oft Verwirrung stiftet. Die allgemeinen Daten kann man ggfl. gleich wie oben eingeben:<br />
<source lang="bash"><br />
root@linux# openssl req -new -key serverkey.pem -out req.pem -nodes<br />
You are about to be asked to enter information that will be incorporated<br />
into your certificate request.<br />
What you are about to enter is what is called a Distinguished Name or a DN.<br />
There are quite a few fields but you can leave some blank<br />
For some fields there will be a default value,<br />
If you enter '.', the field will be left blank.<br />
-----<br />
Country Name (2 letter code) [AU]: DE<br />
State or Province Name (full name) [Some-State]:Brandenburg<br />
Locality Name (eg, city) []:Potsdam<br />
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Familie AG<br />
Organizational Unit Name (eg, section) []:EDV</source><br />
ACHTUNG, jetzt kommt das Wichtige: Beim Serverzertifikat ist der Common Name von entscheidender Bedeutung. Hier muss der DNS-Name stehen, unter dem der Client den Server anspricht! Wird das Zertifikat für eine HTTPS-Verbindung zu fhem.local verwendet, so muss der Common Name eben genau fhem.local heißen. Anderfalls wird der Browser das Zertifikat nicht akzeptieren, da er davon ausgehen muss, auf dem falschen Server gelandet zu sein.<br />
<nowiki><br />
Common Name (eg, YOUR name) []: fhem.local<br />
Email Address []: admin.fhem.local</nowiki><br />
Weitere Optionen kann man einfach leer lassen:<br />
<nowiki><br />
A challenge password []:<br />
An optional company name []:</nowiki><br />
Mittlerweile tummeln sich schon vier Dateien in unserem Verzeichnis:<br />
<source lang="bash"><br />
root@linux# ll<br />
insgesamt 17<br />
drwxr-xr-x 2 root root 168 2006-04-30 12:29 .<br />
drwx------ 12 root root 600 2006-04-30 11:54 ..<br />
-rw-r--r-- 1 root root 1212 2006-04-30 12:08 cacert.pem<br />
-rw------- 1 root root 963 2006-04-30 12:08 cakey.pem<br />
-rw-r--r-- 1 root root 1017 2006-04-30 12:29 req.pem<br />
-rw-r--r-- 1 root root 1679 2006-04-30 12:21 serverkey.pem</source><br />
<br />
=== OpenSSL-Konfiguration anpassen ===<br />
Leider kann man bei OpenSSL nicht alle Daten als Kommandozeilenargumente übergeben. Einige Einstellungen muss man lästigerweise in der Datei /etc/ssl/openssl.cnf ändern, bevor man signieren kann. Öffne diese Datei und passe folgende Zeilen in der Sektion [ CA_default ] an:<br />
<source lang="bash"><br />
/etc/ssl/openssl.cnf:<br />
dir = . # Where everything is kept<br />
new_certs_dir = $dir # default place for new certs<br />
private_key = $dir/cakey.pem # The private key<br />
RANDFILE = $dir/.rand # private random number file<br />
default_days = 3650 # how long to certify for</source><br />
Das Feld default_days ist auf 365 Tage voreingestellt und gibt die Gültigkeit des Zertifikates an. Abgelaufene Zertifikate sind im Übrigen ein sehr häufiges Problem. Wenn es soweit ist, kennt sich damit nämlich schon lange keiner mehr aus. Deswegen kannst Du wie im Beispiel angegeben die Lebensdauer z.B. auf 10 Jahre heraufsetzen.<br />
<br />
Nun muss man noch einige Dateien anlegen:<br />
<source lang="bash"><br />
root@linux# echo 01 > serial<br />
root@linux# touch index.txt</source><br />
<br />
=== Serverzertifikat signieren ===<br />
Kommen wir zum feierlichen Abschluss: Unsere CA signiert nun das Zertifikat:<br />
<source lang="bash"><br />
root@linux# openssl ca -in req.pem -notext -out servercert.pem<br />
Enter pass phrase for ./cakey.pem: langesgeheimespasswort<br />
<br />
...<br />
<br />
Certificate is to be certified until Apr 27 10:45:36 2016 GMT (3650 days)<br />
Sign the certificate? [y/n]: y<br />
<br />
<br />
1 out of 1 certificate requests certified, commit? [y/n] y<br />
Write out database with 1 new entries<br />
Data Base Updated</source><br />
<br />
=== Zertifikate installieren ===<br />
Wie Du das Zertifikat in FHEM installierst, findest Du [[Raspberry_Pi_%26_HTTPS|hier]] und wenn Du ein Server Zertifikat für NGINX installieren möchtest, findest Du Infos dazu [[HTTPS-Absicherung_%26_Authentifizierung_via_nginx_Webserver|hier]]<br />
<br />
== Nachwort ==<br />
=== Einbinden der root CA in die Zertifizierungsstelle des Browsers ===<br />
Beim Firefox importieren wir unsere cacert.pem unter Einstellungen -> Erweitert -> Zertifikate -> Zertifikate anzeigen -> Zertifizierungsstellen ein.<br />
Unter Chrome/Chromium finden wir die Zertifikatsverwaltung unter Einstellungen -> Erweitert -> Zertifikate verwalten HTTPS/SSL-Zertifikate und -Einstellungen verwalten -> Zertifizierungsstellen<br />
<br />
=== Bekannte Probleme ===<br />
Für den Chrome/Chromium müssen wir zusätzlich "Subject Alternative Names (SAN)" in unser Zertifikat eintragen. Dies geschieht beim Serverzertifikat signieren. Dazu müssen wir uns eine weitere Datei anlegen:<br />
<source lang="bash"><br />
root@linux# vim oats.extensions.cnf<br />
<br />
basicConstraints=CA:FALSE<br />
subjectAltName=@my_subject_alt_names<br />
subjectKeyIdentifier = hash<br />
<br />
[ my_subject_alt_names ]<br />
DNS.1 = fhem01.tuxnet.local<br />
DNS.2 = fhem02.tuxnet.local<br />
DNS.3 = fhem01-vpn.tuxnet.local</source><br />
<br />
Dabei die DNS.x Namen durch die DNS Namen (bzw. IP Addressen) ersetzen, womit man Fhem aufruft.<br />
Die Signierung unseres Serverzertifikates erfolgt dann mit folgendem Befehl:<br />
<source lang="bash"><br />
openssl ca -in req.pem -notext -extfile oats.extensions.cnf -out servercert.pem</source><br />
<br />
=== Prüfen von Zertifikaten ===<br />
Zertifikate kann man im übrigen auf dieser [https://www.networking4all.com/en/ssl+certificates/csr+check/| Seite] prüfen lassen.<br />
Dazu kopiert man den Inhalt der servercert.pem in das Eingabefeld der Seite und klickt dann auf Check CSR.<br />
<br />
[[Kategorie:HOWTOS]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=99_myUtils_anlegen&diff=2918199 myUtils anlegen2019-01-20T22:38:48Z<p>Amenomade: /* Routinen mit mehreren Parametern */ Idem</p>
<hr />
<div>Mit wachsender Anzahl von eigenen Helfer-Programmen wird die Speicherung von Perl-Code in [[Eventhandler|Eventhandlern]], [[Timehandler|Timehandlern]] oder anderen Geräten in denen Perl-Ausdrücke angegeben werden können, unübersichtlich. Es besteht die Möglichkeit, eine eigene Programmdatei zu erzeugen, in der mehrere kleine Programme gesammelt und dann aus entsprechenden Geräten aufgerufen werden.<br />
== Eine neue Programmdatei erzeugen ==<br />
FHEM enthält seit Updatestand 01/2015 eine Vorlage 'myUtilsTemplate.pm', die zur Erzeugung der Programmdatei genutzt werden sollte. <br />
Vorgehensweise:<br />
* FHEM-Menüpunkt {{Taste|Edit files}} anklicken<br />
* Weblink 'myUtilsTemplate.pm' anklicken<br />
* Im Textfeld hinter 'Save as' den Dateinamen '99_myUtils.pm' für die Programmdatei eintragen<br />
: Hinweis: Wenn ein anderer Dateiname angegeben wird, muss der Name Initialize-Routine entsprechend angepasst werden (siehe nachfolgende Erläuterung zur Grundstruktur unter Nr. 3)<br />
* {{Taste|Save as}} anklicken<br />
Nun ist die eigene Programmdatei '99_myUtils.pm' mit der notwendigen Grundstruktur unter dem Menüpunkt 'Edit files' zur Bearbeitung mit dem [[Konfiguration#Integrierter_Editor|Integrierter Editor]] zu finden. Für eine einfache und fehlerminimierende Bearbeitung sollten die [[Konfiguration#Syntaxhervorhebung|Syntaxhervorhebungs-, Befehlsauswahl- und Befehlsvervollständigungsfunktionen]] im Integrierten Editor eingeschaltet sein.<br />
<br />
Für Experten ist auch die Nutzung eines [[Konfiguration#Externer Editor|Externen Editors]] zur Bearbeitung möglich, aber nicht empfohlen.<br />
<br />
Eine ‚leere‘ Programmdatei muss grundsätzlich folgenden Grundstruktur besitzen:<br />
<br />
<source lang="perl"><br />
package main;<br />
use strict;<br />
use warnings;<br />
use POSIX;<br />
sub<br />
myUtils_Initialize($$)<br />
{<br />
my ($hash) = @_;<br />
}<br />
1;<br />
</source><br />
<br />
Folgende Dinge sind für die Programmdatei besonders zu beachten:<br />
<br />
# Der Dateiname muss mit 99_ beginnen. FHEM lädt beim Start alle Programmdateien mit dem prefix 99_. Andere Programmdateien werden erst dann geladen, wenn sie durch eine define-Anweisung in der [[Konfiguration]] angefordert werden. So wird z.B. 10_FS20.pm erst geladen, wenn beim Einlesen der Konfiguration das erste define für ein FS20-device abgearbeitet wird. Da Ihre eigene Programmsammlung wahrscheinlich kein neues Gerät mit einem zugehörigen define-Befehl implementiert, würde sie also nie geladen, wenn ihr Name nicht mit 99_ beginnt.<br />
# Damit die neue Datei bei 'Edit files' angezeigt wird, muss sie mit Utils.pm enden. Also zum Beispiel 99_meineUtils.pm<br />
# Der Name der Programmdatei muss mit dem Namen der Initialize-Routine übereinstimmen. Wenn Sie Ihr Programm also 99_Werkzeugkasten.pm nennen, muss die im code dargestellte initialize-Routine sub Werkzeugkasten_Initialize heißen.<br />
# Die Zeile <code> 1; </code> muss immer die letzte Programmzeile sein. Wenn Sie also eigene Routinen in Ihre Programmsammlung einfügen, tragen Sie diese zwischen dem Ende der Initialize-Routine und der abschließenden Zeile <code> 1; </code> ein.<br />
<br />
== Eigene Routinen einfügen ==<br />
Als Beispiel dient das Umsetzen von FS20 toggle-Events aus dem Artikel "[[FS20 Toggle Events auf On/Off umsetzen]]".<br />
Das gesamte Programm sieht dann folgendermaßen aus:<br />
<br />
<source lang="perl"><br />
package main;<br />
use strict;<br />
use warnings;<br />
use POSIX;<br />
sub<br />
myUtils_Initialize($$)<br />
{<br />
my ($hash) = @_;<br />
}<br />
##########################################################<br />
# Untoggle<br />
# toggle-Vorgänge in den Status on/off umsetzen<br />
sub Untoggle($) {<br />
my ($obj) = @_;<br />
<br />
if( Value($obj) eq "toggle" ){<br />
if( OldValue($obj) eq "off" ) {<br />
fhem( "setstate $obj on" );<br />
}<br />
else {<br />
fhem( "setstate $obj off" );<br />
}<br />
}<br />
else {<br />
fhem( "setstate $obj ".Value($obj) );<br />
} <br />
}<br />
1;</source><br />
Der Aufruf erfolgt dann z.B. so:<br />
<br />
<pre>#fhem.cfg<br />
define lampe_untoggle notify lampe {Untoggle("$NAME")}</pre><br />
Der Aufruf aus einem notify (oder at) erfolgt als Perl-code, muss also in geschweiften Klammern stehen. Der Aufruf erfolgt durch Angabe des Namens der Routine (Untoggle) unter Angabe der zu übergebenden Parameter (hier "$NAME").<br />
Im Programm wurde die Routine Untoggle mit '''einem''' Parameter definiert ( Untoggle($) , die Anzahl der $-Zeichen bestimmt die Anzahl der zu übergebenden Parameter). Der Wert des übergebenen Parameters wird in der ersten Programmzeile in die Variable $obj übernommen (my ($obj) = @_; ). <br />
Der Aufruf erfolgt mit Untoggle(„$NAME“) . Der Platzhalter $NAME in fhem steht für den Namen des Geräts. Im o.g. Beispiel erfolgt der Aufruf also eigentlich mit Untoggle(„lampe“). Natürlich können beim Aufruf auch feste Werte ( „lampe1“ ) oder Variablen ( $hour ) übergeben werden.<br />
<br />
=== Routinen mit mehreren Parametern ===<br />
In der Definition der Routine geben Sie außerdem an, wieviele Parameter übergeben werden sollen, für 2 Parameter z.B. so:<br />
<br />
<source lang="perl">define test at *09:00 { wakeup($we, "Schlafzimmerlampe") }</source><br />
Die Deklaration der Routine in Ihrer Programmdatei muss dann so beginnen:<br />
<br />
<source lang="perl">#Nur am Wochenende eingeschaltet<br />
sub wakeup($$) {<br />
my ($wochenende, $device) = @_;<br />
if ($wochenende) {<br />
fhem( "set $device on" );<br />
}<br />
else {<br />
fhem( "set $device off" );<br />
}<br />
}</source><br />
Durch die Anzahl der $-Zeichen in der Routinen-Deklaration wird also die Anzahl der Parameter festgelegt. In der ersten Programmzeile Ihrer Routine übernehmen Sie dann die übergebenen Parameterwerte in lokale Variablen. Wie beim Routinen-Aufruf muss auch hierbei die Anzahl der Parameter mit der Routinen-Deklaration (also Anzahl der $-Zeichen) übereinstimmen.<br />
<br />
=== Routinen ohne Parameter ===<br />
Auch Routinen ohne Parameter sind natürlich möglich. Definition und Aufruf sehen dann folgendermassen aus:<br />
<br />
<source lang="perl">sub parameterlos() {<br />
...<br />
}</source><br />
{ parameterlos() }<br />
<br />
== Eigene Programmdatei laden ==<br />
Die Programmdatei wird beim FHEM-Start immer automatisch geladen. <br />
<br />
Bei Änderungen an der Programmdatei bei laufendem FHEM ist bezüglich Neuladen ohne FHEM-Neustart zwischen den verschiedenen Bearbeitungsvarianten der Progammdatei zu unterscheiden.<br />
<br />
Bei der Bearbeitung über den '''Integrierten Editor''' wird die Programmdatei beim Abspeichern automatisch mit den Änderungen neu geladen.<br />
<br />
Bei der nicht empfohlenen Bearbeitung der Programmdatei mit einem '''externen Editor''' muss FHEM manuell angewiesen werden, die Programmdatei mit den Änderungen zu laden. Also bearbeiten Sie Ihr Programm, speichern die Programmdatei, und weisen FHEM dann explizit an, die Programmdatei erneut zu laden. Der Befehl dazu, der in das Befehls-Eingabefeld eingegeben wird, lautet: <code>reload 99_myUtils.pm</code><br />
<br />
Treten beim Laden (Syntax)fehler auf, werden diese am Bildschirm wie auch im Log angezeigt. Da der Ladevorgang fehlgeschlagen ist, stehen Ihre eigenen Routinen nun nicht zur Verfügung (bzw. in der zuletzt erfolgreich geladenen Version).<br />
== Eigene Programmdatei dokumentieren ==<br />
In der lokalen Commandref kann man die eigenen Routinen auch dokumentieren.<br />
Dazu muss am Ende der 99_myUtils folgender Codeblock eingefügt werden<br />
<source lang="perl"><br />
=pod<br />
=begin html<br />
<br />
<a name="myUtils"></a><br />
<h3>myUtils</h3><br />
<ul><br />
<b>Name</b><br />
<br><br />
Text<br><br />
Examples:<br />
<ul><br />
<code>Example Code </code><br><br />
</ul><br />
</ul><br />
<br />
=end html<br />
=begin html_DE<br />
<br />
<a name="myUtils"></a><br />
<h3>myUtils</h3><br />
<br />
=end html_DE<br />
=cut<br />
</source><br />
<br />
Der a Tag stellt einen Verweis dar, der h3 Tag kennzeichnet die Überschrift. Beide Tags müssen sein, ansonsten kann FHEM die Doku nicht in die commandref einbinden. Der Abschnitt für die deutsche Doku kann komplett fehlen. Die Beschreibungen der einzelnen Routinen werden mit ul Tags geklammert und eventuell mit ul Tags weiter untergliedert. Dabei entsteht ein eingerückter Text. Beispiele können mit dem code Tag formatiert werden.<br />
<br />
Mit diesem Befehl kann die Erzeugung des Commandrefeintrages initiiert und getestet werden:<br />
<source lang="perl">{system("/usr/bin/perl ./contrib/commandref_join.pl")}</source><br />
<br />
== Links ==<br />
* {{Link2Forum|Topic=34363|Message=266811|LinkText=Zeit- und Datumsvariablen $hour, $wday, $month, ... in 99_myUtils.pm verfügbar machen}}<br />
<br />
[[Kategorie:Code Snippets]]<br />
[[Kategorie:HOWTOS]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=99_myUtils_anlegen&diff=2918099 myUtils anlegen2019-01-20T22:38:14Z<p>Amenomade: Quote problem</p>
<hr />
<div>Mit wachsender Anzahl von eigenen Helfer-Programmen wird die Speicherung von Perl-Code in [[Eventhandler|Eventhandlern]], [[Timehandler|Timehandlern]] oder anderen Geräten in denen Perl-Ausdrücke angegeben werden können, unübersichtlich. Es besteht die Möglichkeit, eine eigene Programmdatei zu erzeugen, in der mehrere kleine Programme gesammelt und dann aus entsprechenden Geräten aufgerufen werden.<br />
== Eine neue Programmdatei erzeugen ==<br />
FHEM enthält seit Updatestand 01/2015 eine Vorlage 'myUtilsTemplate.pm', die zur Erzeugung der Programmdatei genutzt werden sollte. <br />
Vorgehensweise:<br />
* FHEM-Menüpunkt {{Taste|Edit files}} anklicken<br />
* Weblink 'myUtilsTemplate.pm' anklicken<br />
* Im Textfeld hinter 'Save as' den Dateinamen '99_myUtils.pm' für die Programmdatei eintragen<br />
: Hinweis: Wenn ein anderer Dateiname angegeben wird, muss der Name Initialize-Routine entsprechend angepasst werden (siehe nachfolgende Erläuterung zur Grundstruktur unter Nr. 3)<br />
* {{Taste|Save as}} anklicken<br />
Nun ist die eigene Programmdatei '99_myUtils.pm' mit der notwendigen Grundstruktur unter dem Menüpunkt 'Edit files' zur Bearbeitung mit dem [[Konfiguration#Integrierter_Editor|Integrierter Editor]] zu finden. Für eine einfache und fehlerminimierende Bearbeitung sollten die [[Konfiguration#Syntaxhervorhebung|Syntaxhervorhebungs-, Befehlsauswahl- und Befehlsvervollständigungsfunktionen]] im Integrierten Editor eingeschaltet sein.<br />
<br />
Für Experten ist auch die Nutzung eines [[Konfiguration#Externer Editor|Externen Editors]] zur Bearbeitung möglich, aber nicht empfohlen.<br />
<br />
Eine ‚leere‘ Programmdatei muss grundsätzlich folgenden Grundstruktur besitzen:<br />
<br />
<source lang="perl"><br />
package main;<br />
use strict;<br />
use warnings;<br />
use POSIX;<br />
sub<br />
myUtils_Initialize($$)<br />
{<br />
my ($hash) = @_;<br />
}<br />
1;<br />
</source><br />
<br />
Folgende Dinge sind für die Programmdatei besonders zu beachten:<br />
<br />
# Der Dateiname muss mit 99_ beginnen. FHEM lädt beim Start alle Programmdateien mit dem prefix 99_. Andere Programmdateien werden erst dann geladen, wenn sie durch eine define-Anweisung in der [[Konfiguration]] angefordert werden. So wird z.B. 10_FS20.pm erst geladen, wenn beim Einlesen der Konfiguration das erste define für ein FS20-device abgearbeitet wird. Da Ihre eigene Programmsammlung wahrscheinlich kein neues Gerät mit einem zugehörigen define-Befehl implementiert, würde sie also nie geladen, wenn ihr Name nicht mit 99_ beginnt.<br />
# Damit die neue Datei bei 'Edit files' angezeigt wird, muss sie mit Utils.pm enden. Also zum Beispiel 99_meineUtils.pm<br />
# Der Name der Programmdatei muss mit dem Namen der Initialize-Routine übereinstimmen. Wenn Sie Ihr Programm also 99_Werkzeugkasten.pm nennen, muss die im code dargestellte initialize-Routine sub Werkzeugkasten_Initialize heißen.<br />
# Die Zeile <code> 1; </code> muss immer die letzte Programmzeile sein. Wenn Sie also eigene Routinen in Ihre Programmsammlung einfügen, tragen Sie diese zwischen dem Ende der Initialize-Routine und der abschließenden Zeile <code> 1; </code> ein.<br />
<br />
== Eigene Routinen einfügen ==<br />
Als Beispiel dient das Umsetzen von FS20 toggle-Events aus dem Artikel "[[FS20 Toggle Events auf On/Off umsetzen]]".<br />
Das gesamte Programm sieht dann folgendermaßen aus:<br />
<br />
<source lang="perl"><br />
package main;<br />
use strict;<br />
use warnings;<br />
use POSIX;<br />
sub<br />
myUtils_Initialize($$)<br />
{<br />
my ($hash) = @_;<br />
}<br />
##########################################################<br />
# Untoggle<br />
# toggle-Vorgänge in den Status on/off umsetzen<br />
sub Untoggle($) {<br />
my ($obj) = @_;<br />
<br />
if( Value($obj) eq "toggle" ){<br />
if( OldValue($obj) eq "off" ) {<br />
fhem( "setstate $obj on" );<br />
}<br />
else {<br />
fhem( "setstate $obj off" );<br />
}<br />
}<br />
else {<br />
fhem( "setstate $obj ".Value($obj) );<br />
} <br />
}<br />
1;</source><br />
Der Aufruf erfolgt dann z.B. so:<br />
<br />
<pre>#fhem.cfg<br />
define lampe_untoggle notify lampe {Untoggle("$NAME")}</pre><br />
Der Aufruf aus einem notify (oder at) erfolgt als Perl-code, muss also in geschweiften Klammern stehen. Der Aufruf erfolgt durch Angabe des Namens der Routine (Untoggle) unter Angabe der zu übergebenden Parameter (hier "$NAME").<br />
Im Programm wurde die Routine Untoggle mit '''einem''' Parameter definiert ( Untoggle($) , die Anzahl der $-Zeichen bestimmt die Anzahl der zu übergebenden Parameter). Der Wert des übergebenen Parameters wird in der ersten Programmzeile in die Variable $obj übernommen (my ($obj) = @_; ). <br />
Der Aufruf erfolgt mit Untoggle(„$NAME“) . Der Platzhalter $NAME in fhem steht für den Namen des Geräts. Im o.g. Beispiel erfolgt der Aufruf also eigentlich mit Untoggle(„lampe“). Natürlich können beim Aufruf auch feste Werte ( „lampe1“ ) oder Variablen ( $hour ) übergeben werden.<br />
<br />
=== Routinen mit mehreren Parametern ===<br />
In der Definition der Routine geben Sie außerdem an, wieviele Parameter übergeben werden sollen, für 2 Parameter z.B. so:<br />
<br />
<source lang="perl">define test at *09:00 { wakeup($we, „Schlafzimmerlampe“) }</source><br />
Die Deklaration der Routine in Ihrer Programmdatei muss dann so beginnen:<br />
<br />
<source lang="perl">#Nur am Wochenende eingeschaltet<br />
sub wakeup($$) {<br />
my ($wochenende, $device) = @_;<br />
if ($wochenende) {<br />
fhem( "set $device on" );<br />
}<br />
else {<br />
fhem( "set $device off" );<br />
}<br />
}</source><br />
Durch die Anzahl der $-Zeichen in der Routinen-Deklaration wird also die Anzahl der Parameter festgelegt. In der ersten Programmzeile Ihrer Routine übernehmen Sie dann die übergebenen Parameterwerte in lokale Variablen. Wie beim Routinen-Aufruf muss auch hierbei die Anzahl der Parameter mit der Routinen-Deklaration (also Anzahl der $-Zeichen) übereinstimmen.<br />
<br />
=== Routinen ohne Parameter ===<br />
Auch Routinen ohne Parameter sind natürlich möglich. Definition und Aufruf sehen dann folgendermassen aus:<br />
<br />
<source lang="perl">sub parameterlos() {<br />
...<br />
}</source><br />
{ parameterlos() }<br />
<br />
== Eigene Programmdatei laden ==<br />
Die Programmdatei wird beim FHEM-Start immer automatisch geladen. <br />
<br />
Bei Änderungen an der Programmdatei bei laufendem FHEM ist bezüglich Neuladen ohne FHEM-Neustart zwischen den verschiedenen Bearbeitungsvarianten der Progammdatei zu unterscheiden.<br />
<br />
Bei der Bearbeitung über den '''Integrierten Editor''' wird die Programmdatei beim Abspeichern automatisch mit den Änderungen neu geladen.<br />
<br />
Bei der nicht empfohlenen Bearbeitung der Programmdatei mit einem '''externen Editor''' muss FHEM manuell angewiesen werden, die Programmdatei mit den Änderungen zu laden. Also bearbeiten Sie Ihr Programm, speichern die Programmdatei, und weisen FHEM dann explizit an, die Programmdatei erneut zu laden. Der Befehl dazu, der in das Befehls-Eingabefeld eingegeben wird, lautet: <code>reload 99_myUtils.pm</code><br />
<br />
Treten beim Laden (Syntax)fehler auf, werden diese am Bildschirm wie auch im Log angezeigt. Da der Ladevorgang fehlgeschlagen ist, stehen Ihre eigenen Routinen nun nicht zur Verfügung (bzw. in der zuletzt erfolgreich geladenen Version).<br />
== Eigene Programmdatei dokumentieren ==<br />
In der lokalen Commandref kann man die eigenen Routinen auch dokumentieren.<br />
Dazu muss am Ende der 99_myUtils folgender Codeblock eingefügt werden<br />
<source lang="perl"><br />
=pod<br />
=begin html<br />
<br />
<a name="myUtils"></a><br />
<h3>myUtils</h3><br />
<ul><br />
<b>Name</b><br />
<br><br />
Text<br><br />
Examples:<br />
<ul><br />
<code>Example Code </code><br><br />
</ul><br />
</ul><br />
<br />
=end html<br />
=begin html_DE<br />
<br />
<a name="myUtils"></a><br />
<h3>myUtils</h3><br />
<br />
=end html_DE<br />
=cut<br />
</source><br />
<br />
Der a Tag stellt einen Verweis dar, der h3 Tag kennzeichnet die Überschrift. Beide Tags müssen sein, ansonsten kann FHEM die Doku nicht in die commandref einbinden. Der Abschnitt für die deutsche Doku kann komplett fehlen. Die Beschreibungen der einzelnen Routinen werden mit ul Tags geklammert und eventuell mit ul Tags weiter untergliedert. Dabei entsteht ein eingerückter Text. Beispiele können mit dem code Tag formatiert werden.<br />
<br />
Mit diesem Befehl kann die Erzeugung des Commandrefeintrages initiiert und getestet werden:<br />
<source lang="perl">{system("/usr/bin/perl ./contrib/commandref_join.pl")}</source><br />
<br />
== Links ==<br />
* {{Link2Forum|Topic=34363|Message=266811|LinkText=Zeit- und Datumsvariablen $hour, $wday, $month, ... in 99_myUtils.pm verfügbar machen}}<br />
<br />
[[Kategorie:Code Snippets]]<br />
[[Kategorie:HOWTOS]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=FHEM_startet_nicht_-_Tipps_zur_Fehlersuche&diff=26856FHEM startet nicht - Tipps zur Fehlersuche2018-05-25T05:58:57Z<p>Amenomade: /* Und wenn sich gar nichts mehr tut? */ (direkten Link ermöglichen)</p>
<hr />
<div>'''Kein Zugriff auf FHEMWEB/FHEM startet nicht - Was kann ich tun???'''<br />
<br />
Deine [[FHEMWEB]]-Seite ist nicht erreichbar? Ist FHEM tot, oder ist das Netzwerk kaputt? Was kann ich machen, um zu prüfen, woran es genau liegt?<br />
<br />
In diesem Wiki-Artikel soll es darum gehen, wie Du für Dich prüfen kannst, ob ein Fehler bei FHEM, im Netzwerk oder ein anderes Problem vorliegt.<br />
== Prüfen: Läuft überhaupt ein FHEM-Prozess? ==<br />
Man kann sich unter einem Linuxsystem sämtliche laufende Prozesse auflisten lassen<br />
<br />
<code>ps ax</code><br />
<br />
Der Befehl ''ps'' listet je nach Argument alle laufende Prozesse auf. Die Liste kann man nun noch nach einem bestimmten Prozess filtern. Aufruf und Ausgabe einer Prozessliste mit einem Filter nach perl sieht z. B. so aus:<br />
<br />
<code>ps ax | grep perl</code><br />
<br />
<code>cooltux@fhem01-cluster:~> ps ax | grep perl</code><br />
<br />
<code>11320 pts/0 S+ 0:00 grep --color=auto perl</code><br />
<br />
Wie wir sehen, wird hier lediglich der gerade ausgeführte Befehl ''ps'' gefunden (weil das Wort ''perl'' in der Aufrufzeile stand. Es wird hier überhaupt kein Perl-Prozess gelistet. Aktuell läuft also definitiv kein FHEM, das ja ein Perl-Programm/Prozess ist.<br />
<br />
Eine Prozessliste mit einem laufenden FHEM-Prozess könnte so aussehen:<br />
<br />
<code>[11:31 root@fhem01-cluster cooltux] > ps ax | grep perl</code><br />
<br />
<code>15852 ? R 2119:09 /usr/bin/perl fhem.pl configDB</code><br />
<br />
<code>21447 pts/0 S+ 0:00 grep perl</code><br />
<br />
FHEM (''perl fhem.pl ...'') ist in diesem Fall also aktiv.<br />
== Prüfen: Ist der laufende FHEM-Prozess überlastet? ==<br />
Ich sollte mir anschauen, ob der FHEM-Prozess vielleicht zu sehr ausgelastet ist, der Prozess also 100 Prozent CPU Auslastung produziert?<br />
<br />
Ein weiterer Linuxbefehl ''top'' wird uns hierbei behilflich sein:<br />
<pre style="white-space: pre;"><br />
[11:38 root@fhem01-cluster cooltux] > top<br />
top - 11:38:18 up 11 days, 18:58, 1 user, load average: 1,07, 1,03, 1,00<br />
Tasks: 125 total, 2 running, 123 sleeping, 0 stopped, 0 zombie<br />
%Cpu(s): 24,9 us, 0,9 sy, 0,0 ni, 74,1 id, 0,0 wa, 0,0 hi, 0,1 si, 0,0 st<br />
KiB Mem: 945524 total, 833532 used, 111992 free, 41552 buffers<br />
KiB Swap: 102396 total, 46564 used, 55832 free. 496240 cached Mem<br />
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND<br />
15852 fhem 20 0 103652 82160 5068 R 100,0 8,7 2125:41 perl <br />
21683 root 20 0 5740 2560 2092 R 1,0 0,3 0:00.37 top <br />
19129 cooltux 20 0 86204 22348 3668 S 0,3 2,4 64:16.90 insync-portable <br />
21350 cooltux 20 0 11436 2848 2248 S 0,3 0,3 0:00.10 sshd <br />
1 root 20 0 23292 2368 1380 S 0,0 0,3 0:54.23 systemd <br />
2 root 20 0 0 0 0 S 0,0 0,0 0:01.09 kthreadd <br />
3 root 20 0 0 0 0 S 0,0 0,0 3:37.20 ksoftirqd/0 <br />
5 root 0 -20 0 0 0 S 0,0 0,0 0:00.00 kworker/0:0H <br />
7 root 20 0 0 0 0 S 0,0 0,0 8:20.71 rcu_sched <br />
8 root 20 0 0 0 0 S 0,0 0,0 0:00.00 rcu_bh <br />
9 root rt 0 0 0 0 S 0,0 0,0 0:05.45 migration/0<br />
</pre><br />
Hier können wir nun eindeutig erkennen, dass unser FHEM die CPU mit 100 Prozent auslastet. FHEM hat also ein Problem!<br />
<br />
Zum Vergleich ein FHEM/Perl-Prozess ohne Probleme:<br />
<pre style="white-space: pre;"><br />
[11:50 root@fhem01-cluster cooltux] > top<br />
top - 11:50:33 up 11 days, 19:10, 1 user, load average: 0,84, 1,03, 1,00<br />
Tasks: 133 total, 1 running, 132 sleeping, 0 stopped, 0 zombie<br />
%Cpu(s): 0,6 us, 0,8 sy, 0,0 ni, 98,6 id, 0,0 wa, 0,0 hi, 0,0 si, 0,0 st<br />
KiB Mem: 945524 total, 818344 used, 127180 free, 43748 buffers<br />
KiB Swap: 102396 total, 46820 used, 55576 free. 489652 cached Mem<br />
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND<br />
22074 fhem 20 0 86424 68516 7200 S 1,3 7,2 0:47.64 perl<br />
22294 root 20 0 5740 2564 2092 R 1,3 0,3 0:00.19 top<br />
22296 fhem 20 0 86424 63556 2240 S 1,3 6,7 0:00.04 perl<br />
22297 fhem 20 0 2088 408 328 S 0,7 0,0 0:00.02 ping<br />
7 root 20 0 0 0 0 S 0,3 0,0 8:21.23 rcu_sched<br />
1366 mysql 20 0 620608 157132 5736 S 0,3 16,6 70:12.59 mysqld<br />
19481 root 20 0 0 0 0 S 0,3 0,0 0:02.35 kworker/3:0<br />
1 root 20 0 23292 2408 1420 S 0,0 0,3 0:54.27 systemd<br />
2 root 20 0 0 0 0 S 0,0 0,0 0:01.09 kthreadd<br />
3 root 20 0 0 0 0 S 0,0 0,0 3:37.42 ksoftirqd/0<br />
5 root 0 -20 0 0 0 S 0,0 0,0 0:00.00 kworker/0:0H<br />
</pre><br />
== Prüfen: Stimmen die Dateiberechtigungen? ==<br />
Alle Dateien im Verzeichnis /opt/fhem/ und allen Unterverzeichnissen gehören nach der Installation dem Benutzer fhem und der Gruppe dialout. Man kann es leicht prüfen:<br />
<code>ls -la /opt/fhem/</code><br />
<br />
Häufig wird der Eigentümer durch Manipulation der Dateien falsch gesetzt, mit diesem Befehl kann man alle Dateien auf den Eigentümer fhem und dessen primäre Gruppe setzen.<br />
<br />
<code>sudo chown -R fhem: /opt/fhem/</code><br />
<br />
Die Setup Routine setzt den Besitz auf fhem:dialout<br />
<code>sudo chown -R fhem:dialout /opt/fhem/</code><br />
<br />
== Und wenn sich gar nichts mehr tut? ==<br />
=== Fehlernachrichten von FHEM bei dessen Start analysieren ===<br />
In der Regel werden die Ausgaben von FHEM, auch die beim Start, gemeinsam mit vielen anderen Nachrichten in ein Logfile geschrieben. Dort kann natürlich nach Ursachen geforscht werden.<br />
<br />
Eine einfachere Auswertung wird möglich, wenn man diese Meldungen zeitweilig in einem Terminalfenster (das Ding, um Kommandozeilenbefehle einzugeben) angezeigt bekommt. Das erreicht man z.B. auf folgendem Weg:<br />
<br />
# Starte ein Terminalfenster bzw. einen Terminalemulator<br />
# Wechsle in das FHEM-Installationsverzeichnis (meist: ''/opt/fhem'')<br />
#: <code>cd /opt/fhem</code><br />
# Erstelle eine Kopie Deiner fhem.cfg, z.B. fhem.cfg.debug<br />
#: <code>cp fhem.cfg fhem.cfg.debug</code><br />
# Bearbeite diese Kopie fhem.cfg.debug nun, um die Meldungen in das Terminalfenster zu leiten, in dem der FHEM-Start versucht wird:<br />
#: <code>nano ./fhem.cfg.debug</code><br />
#:<br />
#: In der Zeile mit "attr global logfile" ist der Dateiname durch ein - (Minuszeichen) zu ersetzen. Dadurch werden die FHEM-Ausgaben auf STDOUT (in das Terminalfenster) geschrieben, und FHEM geht nicht in den Hintergrund.<br />
<br />
# Starte FHEM im Terminalfenster '''mit der angepassten Konfigurationsdatei''':<br />
#: <code>perl fhem.pl fhem.cfg.debug</code><br />
#: Das Terminalfenster nun nicht schliessen, die Meldungen tauchen hier auf.<br />
#: ... Die Fehlermeldungen sind nun zu interpretieren. Gegebenenfalls kann man sie kopieren und als wichtige Information bei einer Hilfeanfrage (z.B. im Forum) verwenden.<br />
# Wenn man genug analysiert hat, FHEM mit Ctrl-C/Strg-C stoppen<br />
<br />
<br />
===Neue Möglichkeit des Debuggen===<br />
<br />
Seit dem 01.08.2017 gibt es die Möglichkeit beim manuellen Starten von FHEM im Terminal den Schalter -d zu verwenden ({{Link2Forum|Topic=74774|Message=666766}}). Dieser startet FHEM mit den beiden gesetzten Attributen <code>attr global logfile -</code> und <code>attr global verbose 5</code> und gibt somit alle Meldungen im Terminalfenster aus. Zuerst mit ins FHEM Verzeichnis wechseln. Root oder sudo ist nicht erforderlich!<br />
<br />
<code>cd /opt/fhem</code><br />
<br />
fhem.cfg - Nutzer:<br />
<code>perl fhem.pl -d fhem.cfg</code><br />
<br />
configDB - Nutzer:<br />
<code>perl fhem.pl -d configDB</code><br />
<br />
[[Kategorie:HOWTOS]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=Alexa-Fhem&diff=26710Alexa-Fhem2018-05-15T18:11:49Z<p>Amenomade: /* node.js installieren */ node.js updaten</p>
<hr />
<div>'''Alexa-Fhem''' ist eine in JavaScript geschriebene und auf NodeJS basierende Software, welche es ermöglicht, der digitalen Amazon Assistentin Alexa zusätzliche Skills für die Heimautomatisierung via FHEM beizubringen. Eine erste funktionierende Version wurde von [https://forum.fhem.de/index.php?action=profile;u=430 justme1968] im {{Link2Forum|Topic=60244|LinkText=Forum}} veröffentlicht.<br />
Das ist eine erste Version der Dokumentation zur Installation und Einrichtung, eine Erweiterung wird sicherlich in nächster Zeit noch folgen.<br />
{{Infobox Modul<br />
|ModPurpose=Anbindung von FHEM an Amazon Assistent Alexa<br />
|ModType=x<br />
|ModTechName=<br />
|ModForumArea=Frontends/Sprachsteuerung<br />
|ModOwner=justme1968<br />
}} <br />
<br />
<br />
==Einführung==<br />
===Glossar===<br />
*Echo bzw. Echo Dot (im Folgenden maskulin bezeichnet) sind die derzeit verfügbaren Geräte des Alexa-Systems '''BILDER EINSTELLEN - Achtung Urheberrecht'''<br />
*AVS ist der Amazon Voice Service, d.h. die Spracherkennungskomponente des Systems.{{Randnotiz|RNTyp=r|RNText=Für die Nutzung der Amazon AWS-Dienste müssen zwingend die Daten einer Kreditkarte angegeben werden. Nach gegenwärtigem Kenntnisstand sollen jedoch keine Kosten für die Nutzung der im Rahmen dieses How To beschriebenen Dienste anfallen, sofern diese in einem Rahmen genutzt werden, der selbst eine intensive private Nutzung nicht überschreitet. Der Benutzer sei an dieser Stelle auf die von Amazon veröffentlichten Preislisten verwiesen. Die Autoren dieser Anleitung und der darin beschriebenen Module übernehmen keine Haftung für eventuelle Kosten, die aus der Nutzung der AWS entstehen. }}<br />
*AWS sind die Amazon Web Services, also per URL erreichbare Dienste zur Ausführung von Berechnungen etc. Im Rahmen von Alexa-Fhem wird bei AWS eine eigene JavaScript-Funktion hinterlegt, die zur Kommunikation mit dem FHEM-Server dient. Im Jargon von Amazon ist dies eine so genannte Lambda-Funktion '''WARUM ? Nachlesen bei Amazon'''.<br />
*Card bezeichnet einen Eintrag in der Alexa-App, der die erkannte Sprachnachricht sowie weiter gehenden Informationen über die Reaktion von Alexa enzthält und Rückmeldung an Amazon erlaubt.<br />
*Skill (engl. für Fähigkeit) ist die Bezeichnung für eine per Spracherkennung bediente Funktionalität des Alexa-Systems, z.B. zur Nachrichtenansage, zur Wettervorhersage oder zur Steuerung von FHEM<br />
<br />
===Arbeitsweise und Datenfluss===<br />
[[Datei:2gpXyLN.jpg|200px|thumb|right|Grafische Darstellung der beteiligten Komponenten]]<br />
Echo -> AVS -> AWS Lambda -> alexa-fhem -> AWS Lambda -> AVS -> Echo<br />
<br />
*Der Echo (oder ein anderes Alexa/AVS fähiges Gerät) nimmt Audiodaten auf und schickt diese an AVS (Amazon Voice Service) zur Erkennung<br />
*AVS führt die Spracherkennung durch und erzeugt ein Event mit Informationen zu den erkannten Daten<br />
:*Beim Alexa SmartHome Skill sind die möglichen Sätze für die Spracherkennung relativ fest vorgegeben <br />
:*Beim Alexa Custom Skill kommen die dazu nötigen Informationen aus dem ''Interaction Model'' der Alexa Skills Configuration<br />
*Das Event wird an den unter ''Configuration'' in der Alexa Skills Configuration hinterlegten Endpoint geschickt<br />
:*Beim Alexa SmartHome Skill ist das zwingend eine AWS Lambda Routine<br />
:*Beim Alexa Custom Skill kann das im Prinzip auch ein eigener Web Service sein<br />
*Das Event wird vom <code>lambda.js</code> code an alexa-fhem weitergeleitet<br />
*alexa-fhem steuert FHEM und sendet ein Antwort-Event zurück<br />
*<code>lambda.js</code> nimmt diese Antwort entgegen und gibt sie an AVS zurück<br />
*AVS sogt dafür das der Echo 'antwortet' und dass die Card in der Alexa App erscheint<br />
<br />
===Anmerkungen===<br />
*Ein Skill hat keinen Zugriff auf die Audiodaten<br />
*Mit dem Skill API kann ein Skill zu zu keiner Zeit von sich aus aktiv werden und 'einfach' Daten an den Echo schicken oder ihn dazu bringen irgendetwas zu tun.<br />
*Wenn man berücksichtigt welchen Weg die Daten insgesamt gehen, ist es erstaunlich, wie schnell die Reaktion auf einen gesprochenen Satz erfolgt.<br />
<br />
=== Abgrenzung des '''Alexa Smart Home Skills''' und des '''Alexa Custom Skills''' ===<br />
<br />
Der [[Alexa-Fhem#Smart_Home|Alexa Smart Home Skill]] ist ein Amazon-Alexa-Standard-Skill, der wesentliche Basisfunktionalitäten bereitstellt. Zu diesen gehört im Wesentlichen die Funktionalität, durch Alexa-FHEM bereitgestellte Devices im Alexa-Account des Benutzers anzulegen. Der Alexa Smart Home Skill reagiert auf gesprochene Interaktion in einem beschränkten Umfang. Beispielsweise genügt ein "Alexa, schalte die Wohnzimmerlampe an" um eine Interaktion zwischen Alexa Smart Home Skill und FHEM-Alexa auszulösen. Nach erfolgreicher Einrichtung wird dieser Skill in der Alexa-App bzw. im Web in der Rubrik "Smart Home" als Skill angezeigt.<br />
<br />
Der [[Alexa-Fhem#Custom|Alexa Custom Skill]] ist kein Standard-Smart-Home-Skill, sondern ein individuell entwickelter Skill, so wie alle anderen Skills auch. Er wird daher auch nicht in der Alexa-App unter der Rubrik "Smart Home" angezeigt. Gesprochene Interaktion mit diesem Skill erfolgt dadurch, dass entweder der Skill explizit gestartet wird (z.B. "Alexa, starte [Name des Skills]") oder direkt angesprochen wird (z.B. "Alexa, frage [Name des Skills] wie ist der Status von [Device] "). Der Alexa Custom Skill befindet sich in Entwicklung und wird hinsichtlich seiner Funktionalitäten laufend weiterentwickelt. Die Einrichtung dieses Skills ist grundsätzlich optional, jedoch werden anspruchsvollere Steuerungsmöglichkeiten nur mit diesem realisiert werden können.<br />
<br />
==Installation==<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Da die einzelnen Schritte der Anleitung an verschiedenen Stellen unterbrochen und später fortgesetzt werden müssen, empfiehlt es sich, die Anleitung einmal vollständig gelesen zu haben. Während der Konfiguration sollten alle nachfolgenden Abschnitte parallel in gleichzeitig geöffneten Browserfenstern durchgeführt werden, die jeweils bis zum Abschluss geöffnet bleiben müssen. }}<br />
Grundvoraussetzung für alle folgenden Schritte ist das Vorhandensein eines Amazon-Accounts. Es wird davon ausgegangen, dass die Konten für alle im Folgenden genutzten Amazon-Dienste eingerichtet wurden.<br />
<br />
===node.js installieren===<br />
Zunächst wird das Betriebssystem (in diesem Falle Debian oder Ubuntu) auf den aktuellen Stand gebracht:<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
sudo apt-get update<br />
sudo apt-get upgrade<br />
sudo apt-get install build-essential libssl-dev</syntaxhighlight><br />
<br />
Nun muss NodeJS installiert werden. Leider ist die Version im Debian Repository deutlich zu alt, daher wird mit den folgenden Befehlen das Node Repository hinzugefügt und NodeJS (in der LTS Version) entsprechend installiert:<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -<br />
sudo apt-get install -y nodejs<br />
</syntaxhighlight><br />
<br />
===node.js updaten===<br />
Um node.js aus einer vorherige Installation zu updaten (Version 4 ist deprecated und in AWS Amazon nicht mehr unterstützt):<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
# Zuerst alexa-fhem stoppen, dann<br />
sudo apt-get remove nodejs<br />
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -<br />
sudo apt-get install -y nodejs<br />
npm install npm@latest -g<br />
<br />
#--> in Amazon Konsole NodeJs auf 8.1 umstellen (Funktion in AWS Konsole editieren, im Pulldown-Menü "Runtime" eine neuere Version auswählen, und speichern)<br />
#--> Raspi Reboot (vielleicht nicht nötig)<br />
</syntaxhighlight><br />
<br />
=== Alexa-Fhem installieren ===<br />
'''Aus gegebenem Anlass: Dies ist weder eine Einführung in Linux, noch eine Anfängerdokumentation für FHEM.''' Also erst die Grundlagen lernen, und dann mit Alexa beginnen !<br />
<br />
Die aktuelle Version ist jeweils {{Link2Forum|Topic=81324|Message=733986|LinkText=hier}} zu finden.<br />
Wer bisher noch keinen Alexa-FHEM Skill angelegt hat, bitte {{Link2Forum|Topic=81324|Message=733986|LinkText=diesen Forumsbeitrag}} beachten!<br />
<br />
====Erstinstallation====<br />
Hier wird die Erstinstallation von Alexa-Fhem beschrieben.<br />
===== Linux =====<br />
# Die tgz-Datei unter Linux im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) entpacken (''nicht'' unter Windows, das zerstört die Rechteeinstellungen).<syntaxhighlight lang="bash" style="width:50%;">tar -xvzf dateiname.tgz</syntaxhighlight><br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen <syntaxhighlight lang="bash" style="width:50%;">mv package alexa-fhem</syntaxhighlight><br />
# Durch <syntaxhighlight lang="bash" style="width:50%;">cd alexa-fhem</syntaxhighlight> in das Verzeichnis wechseln<br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren (kein sudo!).<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=createKey.sh erzeugt ein Zertifikat, das 365 Tage gültig ist. Dies muss deswegen jedes Jahr erneuert werden }}<br />
# SSL Zertifikat erzeugen durch Aufruf von <syntaxhighlight lang="bash" style="width:50%;">./createKey.sh</syntaxhighlight> (kein sudo!). Hierbei beachten, dass ein Kennwort vergeben werden muss, das mindestens aus 4 Zeichen besteht, dieses Kennwort bitte merken.<br />
# Das Verzeichnis ''.alexa'' anlegen, ''und zwar im Home-Verzeichnis desjenigen Benutzers, unter dem Alexa-Fhem laufen soll.'' Insbesondere ist zu beachten, dass dieser Nutzer u.U. im Startskript explizit gesetzt wird. Mit dem untenstehenden Skript ist das ''nicht'' der User fhem, sondern der User ''pi''. Das Symbol ''~/'' verweist auf das Home-Verzeichnis des Benutzers, der gerade die Installation vornimmt.<br />
# Die Datei ''config-sample.json'' nach ''.alexa/config.json'' kopieren. Achtung: Installiert man alexa-fhem als root-user, zeigt das Symbol ''~/'' auf ''/root'' - und die Konfigurationsdatei wird ggf. bei einem manuellen Start von Alexa-Fhem nicht gefunden.<br />
# Achtung: Ggf. müssen auch die Dateien key.pem und cert.pem ins entsprechende Verzeichnis kopiert werden.<br />
===== Windows =====<br />
''Vor'' der Installation von Alexa-Fhem muss man folgende Anwendungen installieren:<br />
* Node.js (die aktuelle Version findet man unter https://nodejs.org/en/download/)<br />
* OpenSSL (http://slproweb.com/products/Win32OpenSSL.html oder https://www.heise.de/download/product/win32-openssl-47316/download)<br />
Erst dann fängt man mit Alexa-Fhem an.<br />
<br />
<br />
# Die tgz-Datei im Hauptverzeichnis von FHEM (z.B. <code>С:\Program Files (x86)\fhem</code>) entpacken.<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen<br />
# Windows-Shell (Kommandozeile, Eingabeaufforderung usw.) öffnen. "Start" -> "Ausführen" (oder [Windows-Taste]+[R]) -> cmd -> Ok. Durch <syntaxhighlight lang="bash" style="width:50%;">cd "<FHEM-Hauptverzeichis>\alexa-fhem"</syntaxhighlight> in das Verzeichnis wechseln. <br/>Dabei ist natürlich das <FHEM-Hauptverzeichis> durch den entsprechenden Pfad aus dem Schritt 1 zu ersetzen. Im o.g. Beispiel wäre es <code>cd "С:\Program Files (x86)\fhem\alexa-fhem"</code><br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren.<br/> Bei der Fehlermeldung wie "Der Befehl "npm" ist entweder falsch geschrieben oder konnte nicht gefunden werden." ist die Installation von Node.js zu überprüfen.<br />
# SSL Zertifikat erzeugen. Dafür muss man alle Befehle aus dem Skript ''createKey.sh'' nacheinander manuell ausführen. Hierbei beachten, dass ein Kennwort vergeben werden muss, das mindestens aus 4 Zeichen besteht, dieses Kennwort bitte merken. Der Windows-Welt unbekannter Befehl <code>mv</code> ist durch <code>move /y</code> zu ersetzen:<syntaxhighlight lang="bash" style="width:50%;">openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;">openssl rsa -in key.pem -out newkey.pem</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;">move /y newkey.pem key.pem</syntaxhighlight> Eventuelle Fehlermeldung "can't open config file: /usr/local/ssl/openssl.cnf" o.Ä. lässt sich durch Befehl <code>set OPENSSL_CONF=<OpenSSL-Verzeichnis>\bin\openssl.cfg</code> beheben, wobei <OpenSSL-Verzeichnis> durch den entsprechenden Installationspfad (typischerweise <code>c:\OpenSSL-Win32</code>) zu ersetzen ist.<br />
# Das Verzeichnis ''.alexa'' anlegen, ''und zwar im Benutzerverzeichnis desjenigen Benutzers, unter dem Alexa-Fhem laufen soll.'' In aktuellen Versionen von Windows (ab Windows 7 bzw. ab Windows Server 2008 R2) liegt das Verzeichnis unter <code>C:\Users\<Benutzername></code>, also z.B. für Benutzer "Administrator" - unter <code>C:\Users\Administrator</code>.<br/>Falls Windows sich weigert das Verzichniss mit dem Punkt am Anfang zu erstellen, kann man das aus der Kommandozeile machen:<syntaxhighlight lang="bash" style="width:50%;">cd "C:\Users\<Benutzername>"</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;"><br />
mkdir ".alexa"</syntaxhighlight><br />
# Die Datei ''config-sample.json'' nach ''C:\Users\<Benutzername>\.alexa\config.json'' kopieren.<br />
# Achtung: Ggf. müssen auch die Dateien key.pem und cert.pem ins entsprechende Verzeichnis (<code>"<FHEM-Hauptverzeichis>\alexa-fhem\bin</code>) kopiert werden.<br />
<br />
====Update====<br />
Hier wir das Update auf eine neue Version von Alexa-Fhem beschrieben<br />
===== Linux =====<br />
# Das Verzeichnis ''alexa-fhem'' im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) umbenennen in ''alexa-fhem.old''.<br />
# Die tgz-Datei der neuen Alexa-Fhem-Version unter Linux im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) entpacken (''nicht'' unter Windows, das zerstört die Rechteeinstellungen).<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen, in das Verzeichnis wechseln<br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren (kein sudo!).<br />
# Die Zertifikatsdateien key.pem und cert.pem aus dem alten Verzeichnis ''alexa-fhem.old'' ins neue Verzeichnis ''alexa-fhem'' kopieren.<br />
Natürlich dann den Dienst neu starten, auch müssen selbstredend irgendwelche Modifikationen an der Datei server.js in der neuen Version nachgezogen werden. Wenn alles läuft, kann das alte Verzeichnis ''alexa-fhem.old'' gelöscht werden.<br />
===== Windows =====<br />
# Das Verzeichnis ''alexa-fhem'' im Hauptverzeichnis von FHEM (z.B. <code>С:\Program Files (x86)\fhem</code>) umbenennen in ''alexa-fhem.old''.<br />
# Die tgz-Datei der neuen Alexa-Fhem-Version im Hauptverzeichnis von FHEM entpacken.<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen<br />
# Windows-Shell (Kommandozeile, Eingabeaufforderung usw.) öffnen. "Start" -> "Ausführen" (oder [Windows-Taste]+[R]) -> cmd -> Ok. Durch <syntaxhighlight lang="bash" style="width:50%;">cd "<FHEM-Hauptverzeichis>\alexa-fhem"</syntaxhighlight> in das Verzeichnis wechseln. <br/>Dabei ist natürlich das <FHEM-Hauptverzeichis> durch den entsprechenden Pfad aus dem Schritt 1 zu ersetzen. Im o.g. Beispiel wäre es <code>cd "С:\Program Files (x86)\fhem\alexa-fhem"</code><br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren.<br />
# Die Zertifikatsdateien key.pem und cert.pem aus dem alten Verzeichnis ''alexa-fhem.old'' ins neue Verzeichnis ''alexa-fhem'' kopieren.<br />
Natürlich dann den Dienst neu starten, auch müssen selbstredend irgendwelche Modifikationen an der Datei server.js in der neuen Version nachgezogen werden. Wenn alles läuft, kann das alte Verzeichnis ''alexa-fhem.old'' gelöscht werden.<br />
<br />
==== Alexa-Fhem konfigurieren ====<br />
Der Inhalt der Datei ''~/.alexa/config.json'' muss an die eigene Umgebung angepasst werden. <br />
# ''nat-pmp'' -> wenn nat-pmp verwendet werden soll: die ip des eigenen routers,<br />
# ''nat-upnp'' -> wenn nat-upnp verwendet werden soll: ''true'',<br />
# ''applicationId'' <br />
#:* Wenn man nur den SmartHome-Skill verwenden möchte, kann dieser Eintrag leer bleiben.<br />
#:* Ansonsten ist er mit der SkillID des Alexa Custom Skills zu belegen, siehe Abschnitt [[#Skill_Id_bestimmen | Skill Id bestimmen]]<br />
# ''oauthClientID'' -> ''Client ID'' dem Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
# ''server'' -> IP-Adresse des eigenen FHEM-Servers<br />
# ''port'' -> Portnummer des eigenen FHEM-Servers<br />
Beispiel:<br />
{<br />
"alexa": {<br />
"name": "Alexa TEST",<br />
"keyFile": "./key.pem",<br />
"certFile": "./cert.pem",<br />
"applicationId": "amzn1.ask.skill.xxxxxxxxxxxxxxxxxxxxxxxxxxxx",<br />
"oauthClientID": "amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"<br />
},<br />
"connections": [<br />
{<br />
"name": "FHEM",<br />
"server": "192.168.0.xxx.xxx",<br />
"port": "8083",<br />
"filter": "room=AlexaRoom"<br />
}<br />
]<br />
}<br />
<br />
Mehrere Custom Skills lassen sich mit der folgenden Syntax eintragen<br />
"applicationId": [ "amzn1.ask.skill.1" , "amzn1.ask.skill.2" ],<br />
"oauthClientID": [ "amzn1.application-oa2-client.1" , "amzn1.application-oa2-client.1" ]<br />
<br />
Danach durch Aufruf von <syntaxhighlight lang="bash" style="width:50%;">./bin/alexa</syntaxhighlight> den Dienst starten (kein sudo!)<br />
<br />
<br />
Unter Windows startet man den Alexa-Dienst durch <syntaxhighlight lang="bash" style="width:50%;">node alexa</syntaxhighlight> aus der <code>alex-fhem/bin</code> (also erst z.B. durch <code>cd "<FHEM-Hauptverzeichis>\alexa-fhem\bin"</code> ins richtige Verzeichnis kommen)<br />
<br />
Der Start des Alexa-Dienstes auf der Console ist immer dann zu empfehlen, wenn man auf die Ausgaben des Dienstes angewiesen ist und beispielsweise sehen möchte, welche Devices durch den Dienst bereitgestellt werden oder ob Fehler auftreten. Beendet man die Console-Session wird auch der Dienst wieder beendet. Insofern ist die vorgenannte Vorgehensweise nur für ein Debugging zu empfehlen und nicht im Regelbetrieb. Nachfolgend ist beschrieben, wie man den Alexa-Dienst aus FHEM heraus starten / stoppen und neu starten kann.<br />
<br />
==== Alexa-Fhem aus FHEM heraus starten ====<br />
Zunächst das Start-up-Skript aus diesem Post herunterladen {{Link2Forum|Topic=60244|Message=517271|LinkText=https://forum.fhem.de/index.php/topic,60244.msg517271.html#msg517271}} und unter /etc/init.d/alexa speichern.<br />
<br />
Das Script geht davon aus, das der alexa-fhem script unter /opt/fhem/alexa-fhem liegt, und die logfiles später unter /opt/fhem/log. Sollte das nicht der Fall sein, muss das Skript angepasst werden.<br />
<br />
Nun folgende Kommandos ausführen:<br />
<syntaxhighlight lang="bash" style="width:50%;">sudo chmod 755 /etc/init.d/alexa<br />
sudo update-rc.d alexa defaults</syntaxhighlight><br />
<br />
In der Datei <code>/etc/sudoers</code> den User fhem für die Nutzung von sudo zulassen (<code>sudo nano /etc/sudoers</code>), z.B. durch Anfügen der nachfolgenden Zeile:<br />
<code>fhem ALL=(ALL) NOPASSWD: ALL</code><br />
<br />
Nun folgende Devices anlegen (ggf. einem Raum zuordnen, z.B. AlexaControl):<br />
<syntaxhighlight lang="bash" style="width:75%;">define FHEM.Alexa.Status dummy<br />
<br />
define FHEM.Alexa dummy<br />
attr FHEM.Alexa event-on-change-reading state<br />
attr FHEM.Alexa webCmd status:start:stop:restart<br />
<br />
define FHEM.Alexa.DOIF DOIF ([FHEM.Alexa] eq "start") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa start > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "stop")<br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa stop > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "restart") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa restart > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "status") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa status > /dev/null 2>&1 &")})</syntaxhighlight><br />
<br />
==== Alexa-Fhem als Service (systemd) installieren ====<br />
Auf neueren Installationen (z.B. RPi Jessie) wird init.d durch systemd ersetzt. Folgend die Anleitung um alexa-fhem als Service zu installieren auf einem Raspberry Pi mit Jessie.<br />
<br />
Zunächst einen neuen Benutzer anlegen unter dem alexa-fhem laufen soll, falls man nicht möchtet dass alexa-fhem z.B. mit dem fhem User ausgeführt wird:<br />
<br />
<code lang="bash" style="width:75%;"><br />
sudo useradd -M --system alexa<br />
</code><br />
<br />
Eigentlich braucht der Benutzer keine Gruppen, aber man kann den Benutzer auch der Gruppe <code>dialout</code> hinzufügen (<code>sudo usermod -a -G dialout alexa</code>)<br />
<br />
Datei "alexa.service" unter <code>/etc/systemd/system</code> anlegen:<br />
<br />
[Unit]<br />
Description=Node.js Alexa Server <br />
After=syslog.target network-online.target<br />
<br />
[Service]<br />
Type=simple<br />
User=alexa <br />
WorkingDirectory=/opt/fhem/alexa-fhem<br />
ExecStart=/opt/fhem/alexa-fhem/bin/alexa -U /home/alexa/.alexa<br />
Restart=on-failure<br />
RestartSec=10<br />
KillMode=process<br />
<br />
[Install]<br />
WantedBy=multi-user.target <br />
<br />
Den Pfad <code>/home/alexa/.alexa</code> an die Systemgegebenheiten anpassen. Letztendlich kann die config.json irgendwo liegen, hauptsache alexa-fhem weiß wo. <br />
<br />
Im WorkingDirectory wird der alexa Dienst die Zertifikate suchen.<br />
<br />
Achtung: Natürlich muss der Benutzer auch Zugriff sowohl auf das Verzeichnis mit der config als auch das alexa-fhem Verzeichnis und das WorkingDirectory haben.<br />
<br />
Um den Service zu aktiveren und zu starten helfen folgende Befehle:<br />
sudo systemctl daemon-reload<br />
sudo systemctl enable alexa<br />
sudo systemctl start alexa<br />
<br />
Status abfragen mit<br />
sudo systemctl status alexa<br />
<br />
Log einsehen?<br />
sudo journalctl -u alexa<br />
<br />
(mit <code>-f</code> kann man den follow Modus aktivieren, wie <code>tail -f</code>).<br />
Bei einen reboot startet alexa-fhem jetzt automatisch.<br />
<br />
==== Alexa-Fhem testen ====<br />
Node.Js stellt einen Web-Server am Port 3000 bereit, das oben erzeugte Zertifikat sichert diesen Zugang per SSL ab. Durch Aufruf der Adresse<br />
<code>https://<IP-Adresse des Servers>:3000</code> kann man testen, ob der Alexa-Fhem Service läuft - der Seitenaufruf liefert eine Zeile JSON-Code, beginnend mit<br />
<code>{"header":{"name":"UnsupportedOperationError"...</code><br />
<br />
=== Alexa Device anlegen ===<br />
Das Modul 39_alexa.pm stellt innerhalb von FHEM verschiedene Attribute z.B. alexaName oder alexaRoom zur Verfügung. Manche dieser Attribute (wie z.b. alexaName) werden in beiden Skills verwendet, andere werden ausschließlich bei einer Nutzung des Alexa Custom Skill verwendet.<br />
<br />
Die Einrichtung des Alexa Device geschieht durch die nachfolgende Definition:<br />
<syntaxhighlight lang="bash" style="width:70%;">define MyAlexa alexa</syntaxhighlight><br />
<br />
<hr><br />
<br />
=== Alexa Skills ===<br />
Für folgende Schritte muss man unter der Adresse http://developer.amazon.com angemeldet sein<br />
# Anmeldung auswählen<br />[[Datei:Developer.amazon.com-01-login2.png|200px]]<br />
# Anmeldedaten eingeben<br />[[Datei:Developer.amazon.com-02-userpass2.png|200px]]<br />
<br />
==== Security Profile anlegen ====<br />
Die Erzeugung eines Sicherheitsprofils muss nur einmal erfolgen, es wird dann für alle weiteren Skills verwendet.<br />
# Nach der Anmeldung Auswahl von ''APPS & SERVICES''<br />[[Datei:Developer.amazon.com-03-apps_and_services.png|200px]]<br />
# Anschließend auswählen ''Security Profiles''<br />[[Datei:Developer.amazon.com-05-apps_and_services_-_security_profiles.png|200px]]<br />
# Auswählen ''Create a New Security Profile'' aus<br />[[Datei:Developer.amazon.com-06-apps_and_services_-_create_a_new_security_profile.png|200px]]<br />
# Dann einen Namen und eine Beschreibung für das Profil eingeben und mit ''Save'' bestätigen<br />[[Datei:Developer.amazon.com-07-apps_and_services_-_security_profile_management.png|200px]]<br />
<br />
===== Login with Amazon =====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Hier wird beschrieben, wo ''Client Id'' und ''Client Secret'' zu finden sind}}<br />
# Oben rechts auf ''Login with Amazon'' klicken (https://developer.amazon.com/lwa/sp/overview.html).<br/>[[Datei:Developer.amazon.com-08-login_with_amazon.png|200px]]<br />
# Auf der neu geladenen Seite auswählen ''Sign up''<br/>[[Datei:Developer.amazon.com-09-login_with_amazon_-_sign_up.png|200px]]<br />
# Anschließend im Dropdown Menü das vorher angelegte Profil auswählen und mit ''Confirm'' bestätigen<br/>[[Datei:Developer.amazon.com-10-login_with_amazon_-_create_new_profile.png|200px]] [[Datei:Developer.amazon.com-11-login_with_amazon_-_create_new_profile2.png|200px]]<br />
# Im folgenden Fenster die Adresse [https://www.amazon.com/gp/help/customer/display.html?nodeId=468496 https://www.amazon.com/gp/help/customer/display.html?nodeId=468496] eingeben und mit ''Save'' bestätigen. '''Todo Erklärungsbedarf: WARUM diese Adresse'''<br/>[[Datei:Developer.amazon.com-12-login_with_amazon_-_enter_consent_screen_information.png|200px]]<br />
# Anschließend bei dem neu angelegten Eintrag auf der rechten Seite auf das Zahnrad klicken und ''Web Settings'' auswählen<br/>[[Datei:Developer.amazon.com-13-login_with_amazon_-_web_settings.png|200px]]<br />
# Im neu geladenen Fenster anklicken von ''Edit''<br/>[[Datei:Developer.amazon.com-14-login_with_amazon_-_edit.png|200px]]<br />
# Anschließend bei ''Allowed Return URLs'' die folgenden drei Adressen eingeben. ''xxx'' muss hierbei durch den Wert ersetzt werden, der in den beiden Abschnitten [[#SmartHome_Skill_anlegen | SmartHome Skill anlegen]] bzw. [[#Custom_Skill_anlegen | Custom Skill anlegen]] jeweils unter Punkt 4 (Seite ''Configuration'') bei ''Redirect Urls'' am Ende der URLs angezeigt wird<br />
## [https://layla.amazon.co.uk/api/skill/link/xxx https://layla.amazon.co.uk/api/skill/link/xxx]<br />
## [https://pitangui.amazon.com/api/skill/link/xxx https://pitangui.amazon.com/api/skill/link/xxx]<br />
## [https://layla.amazon.com/api/skill/link/xxx https://layla.amazon.com/api/skill/link/xxx]<br />
.<br/>[[Datei:Developer.amazon.com-15-login_with_amazon_-_allowed_return_urls.png|200px]]<br />
<br />
==== Skills bearbeiten ====<br />
# Im Menü den Punkt ''ALEXA'' auswählen<br />[[Datei:Developer.amazon.com-03-apps_and_services.png|200px]]<br />
# Anschließend im Feld ''Alexa Skills Kit'' auf ''Get started'' klicken<br />[[Datei:Developer.amazon.com-17-alexa_-_alex_skills_kit_-_get_started.png|200px]]<br />
<br />
===== SmartHome Skill anlegen ====={{Randnotiz|RNTyp=r|RNText=aktuell lässt sich nur noch das v3 api auswählen. eine test version hierfür gibt es im {{Link2Forum|Topic=81324|LinkText=Forum}}. bitte die hinweise dort lesen und beachten.}}<br />
# Oben rechts ''Add a New Skill'' auswählen<br />[[Datei:Developer.amazon.com-18-alexa_-_alex_skills_kit_-_add_a_new_skill.png|200px]]<br />
# Auf der folgenden Seite eingeben und dann mit ''Next'' bestätigen:<br />
#:* ''Skill Type'' -> ''SmartHome Skill API'' <br />
#:* ''Language'' -> ''German''<br />
#:* ''Name'' -> beliebiger Name, z.B. "MySmartHome Basic")<br />
#:* ''Payload Version'' -> ''v2 (other devices)'' <br/>[[Datei:Developer.amazon.com-19-alexa_-_alex_skills_kit_-_skill_information.png|200px]] <br />
# Die folgende Seite einfach mit ''Next'' überspringen<br />[[Datei:Developer.amazon.com-20-alexa_-_alex_skills_kit_-_interaction_model.png|200px]]<br />
# Auf der Seite ''Configuration'' Folgendes eingeben:<br />
#:* ''Service Endpoint Type'' -> ''AWS Lambda'' ist vorausgewählt und kann nicht geändert werden.<br />
#:* ''Geographical Region'' -> ''Europe'' auswählen und im Textfeld die ARN aus Abschnitt [[#ARN_der_AWS_Lambda_Funktion_bestimmen | AWS Lambda Funktion]] eintragen. <br />
#:* ''Authorization URL'' -> <code>https://www.amazon.com/ap/oa</code><br />
#:* ''Client ID'' -> ''Client ID'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
#:* ''Scope'' -> <code>profile:user_id</code> (wörtlich 1:1 eintragen)<br />
#:* ''Redirect URLs'' - sollten vorbelegt sein<br />
#:* ''Authorization Grant Type'' -> ''Auth Code Grant'' auswählen<br />
#:* ''Access Token URI'' -> <code>https://api.amazon.com/auth/o2/token</code><br />
#:* ''Client Secret'' -> ''Client Secret'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
#:* ''Client Authentication Scheme'' -> ''HTTP Basic''<br />
#:* ''Privacy Policy URL'' -> <code>https://www.amazon.com/gp/help/customer/display.html?nodeId=468496</code><br /><br /><br />
<br />[[Datei:Developer.amazon.com-21-alexa_-_alex_skills_kit_-_configuration.png|200px]] [[Datei:Developer.amazon.com-22-alexa_-_alex_skills_kit_-_test.png|200px]]<br />
<br />
===== Custom Skill anlegen =====<br />
<ol><br />
<li> Oben rechts ''Add a New Skill'' auswählen<br />[[Datei:Developer.amazon.com-18-alexa_-_alex_skills_kit_-_add_a_new_skill.png|200px]]</li><br />
<li> Auf der folgenden Seite (''Skill Information'') die nachstehenden Daten eingeben und dann mit ''Next'' bestätigen:<br />
<ul><br />
<li> ''Skill Type'' -> ''Custom Interaction Model'' </li><br />
<li> ''Language'' -> ''German''</li><br />
<li> ''Name'' -> beliebiger Name, z.B. "MySmartHome Advanced". Dieser wird in der Alexa App unter "Meine Skills" angezeigt.</li><br />
<li> ''Invocation Name'' -> Aufruf des Skills, unter dem dieser später gestartet wird. Z.B. "Alexa, starte James"<br />[[Datei:CustomSkill_2.PNG|400px]]</li><br />
</ul></li><br />
<li>Auf der Seite ''Interaction Model'' folgende Eingaben tätigen und mit ''Next'' abschließen<br />
<ul><br />
<li>In einem separaten Browserfenster FHEM aufrufen, und für das bereits definierte Alexa-Gerät das Kommando <code>get MyAlexa interactionModel</code> aufrufen. Es erscheint ein Popup-Fenster mit ziemlich vielen Zeilen.<br />
<li>In die Box ''Intent Schema'' kopiert man den ersten Teil dieser FHEM-Ausgabe hinein, also:<br/><blockquote><br />
{ <br />
"intents" : [ <br />
<hier ziemlich viele Zeilen> <br />
]<br />
}<br />
</blockquote></li><br />
<li>Nun die ''Custom Slot Types'' einrichten. Dazu muss aus dem zweiten Teil der FHEM-Ausgabe jeweils der Slot-Type (z.B. <code>FHEM_article</code>) in das Feld ''TYPE'' eingetragen werden, das nach dem Anklicken von ''Add Slot Type'' erscheint. In das darunter liegende größere Textfeld kommen die möglichen Werte für diesen Slot, so wie sie aus der FHEM-Ausgabe abzulesen sind. Dann mit ''Save'' sichern. Als Custom Slot Type erscheint dann für diesen Beispiel-Slot<br />
FHEM_article der | die | das | den<br />
d.h., die Zeilenumbrüche bei den möglichen Werten werden als "|" dargestellt.</li><br />
<li>Hier muss nun ein Bruch im Arbeitsfluss durchgeführt werden, denn bei der Erstellung des Custom Skills kommt es auf die Reihenfolge der Einträge an. Deshalb zunächst diese FHEM-Ausgabe schließen, und für dasselbe FHEM-Device <code>get MyAlexa customSlotTypes</code> ausführen. Auch diese Ausgabe wird, wie oben beschriebeen, in Custom Slot Types eingetragen (erst der TYPE, dann die möglichen Werte)<br />
<li>Anschließend erneut die FHEM-Ausgabe schließen und erneut für das bereits definierte Alexa-Gerät das Kommando <code>get MyAlexa interactionModel</code> aufrufen.<br />
<li>Unter ''Sample Utterances'' nun den Text aus dem dritten Teil dieser FHEM-Ausgabe hineinkopieren<br />[[Datei:CustomSkill_5.PNG|400px]]</li><br />
</ul></li><br />
<li>Auf der Seite ''Configuration'' Folgendes eingeben und mit ''Next'' bestätigen:<br />
<ul><br />
<li>''Service Endpoint Type'' -> ''AWS Lambda'' auswählen</li><br />
<li>''Geographical Region'' -> ''Europe'' auswählen und im Textfeld den Wert aus Abschnitt [[#AWS_Lambda_Funktion_anlegen | AWS Lambda Funktion anlegen]] (Punkt 12) eintragen. </li><br />
<li>''Do you allow users to create an account or link to an existing account with you?'' -> ''Yes''</li><br />
<li>''Authorization URL'' -> <code>https://www.amazon.com/ap/oa</code></li><br />
<li>''Client ID'' -> ''Client ID'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1</li><br />
<li>''Scope'' -> <code>profile:user_id</code> (wörtlich 1:1 eintragen)</li><br />
<li>''Redirect URLs'' - sollten vorbelegt sein</li><br />
<li>''Authorization Grant Type'' -> ''Auth Code Grant'' auswählen</li><br />
<li>''Access Token URI'' -> <code>https://api.amazon.com/auth/o2/token</code></li><br />
<li>''Client Secret'' -> ''Client Secret'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1</li><br />
<li>''Client Authentication Scheme'' -> ''HTTP Basic''</li><br />
<li>''Privacy Policy URL'' -> <code>https://www.amazon.com/gp/help/customer/display.html?nodeId=468496</code></li><br />
</ul><br />
Beim Sichern dieser Seite mit ''Next'' kann es zu einer Fehlermeldung kommen, wenn man seine Skill-Definitionen mit dem einfachen SmartHome-Skill begonnen hat. Deshalb muss noch der entsprechende Trigger für die [[#AWS_Lambda-Funktion | AWS Lambda Funktion]] nachgetragen werden, dies wird in Abschnitt [[#Trigger_f.C3.BCr_Custom_Skill_hinzuf.C3.BCgen | Trigger für Custom Skill hinzufügen]] beschrieben.<br />
<br />[[Datei:CustomSkill_6.PNG|400px]] [[Datei:CustomSkill_7.PNG|400px]]</li><br />
<br />
==== Testen ====<br />
Hat man den Custom Skill angelegt, bietet dieser auch eine komfortable Testmöglichkeit. Dazu wählt man in der Übersichtsseite ''All Skills'' den Button ''Edit'' des Alexa Custom Skill aus. Auf der nachfolgenden Seite dann links ''Test''. <br />
Die Testseite enthält <br />
* ein Feld ''Voice Simulator'', mit dem man die Sprachsausgabe testen kann, <br />
* ein Feld ''Service Simulator'', mit dem die Verarbeitung von Alexa-Kommandois getestet werden kann. Hier kann man z.B. eintragen<br />
"Alexa, sage <Custom Skill Invocation Name>: Stelle Weckzeit auf Neunzehn Siebenundzwanzig Uhr"<br />
"Alexa, frage <Custom Skill Invocation Name> nach dem Status von Weckzeit"<br />
Dabei ist natürlich der ''Custom Skill Invocation Name'' durch den Wert zu ersetzen, den man im Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]] unter Punkt 2 eingetragen hat.<br />
<br />
==== Skill Id bestimmen ====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Hier wird beschrieben, wo die ''Alexa Skill Id'' zu finden ist}}<br />
Für das [[#AWS_Lamba_Funktion_anlegen | Anlegen einer ''AWS Lambda Funktion'']] bzw für die [[#Alexa-Fhem_konfigurieren | Konfiguration von Alexa-Fhem]] wird die ''Alexa Skill Id'' benötigt. An diese kommt man wie folgt:<br />
# Anmelden wie unter [[#Alexa_Skills | Alexa Skills]] beschrieben.<br />
# Menüpunkt ''ALEXA'' auswählen, wie [[#Skills_bearbeiten | Skills bearbeiten]] erklärt.<br />
# Beim gewünschten Eintrag auf ''Edit'' klicken<br />[[Datei:Developer.amazon.com-23-alexa_-_alex_skills_kit_-_overview.png|200px]]<br />
# Die Id, die nun oben angezeigt wird, ist die gesuchte. Sie hat typischerweise das Format <code>amzn1.ask.skill.[Zahlen und Bindestriche]</code><br />[[Datei:Aws.amazon.com-06-configure_triggers2.png|200px]]<br />
<br />
<hr><br />
<br />
=== AWS Lambda Funktion ===<br />
Für folgende Schritte muss man unter der Adresse http://aws.amazon.com angemeldet sein<br />
# Anmeldung auswählen<br />[[Datei:Aws.amazon.com-01-site.png|200px]]<br />
# Anmeldedaten eingeben<br />[[Datei:Aws.amazon.com-02-login.png|200px]]<br />
# Den Punkt ''Lambda'' links auf der Startseite auswählen, bzw. im Menü ''Services'' unter ''Compute'' den Menüpunkt ''Lambda'' auswählen<br />[[Datei:Aws.amazon.com-03-lambda.png|200px]]<br />
<br />
==== AWS Lambda Funktion anlegen ===={{Randnotiz|RNTyp=r|RNText=Die AWS Seiten sehen inzwischen etwas anders aus. Eine angepasste Beschreibung findet sich im {{Link2Forum|Topic=81790|Message=739211|LinkText=Forum}}. Bitte auch die Hinweise dort lesen.}}<br />
# Für eine erste Lambda-Funktion den Punkt ''Get Started Now'' auswählen<br />[[Datei:Aws.amazon.com-04-get_started_now.png|200px]]<br />
# Den Blueprint ''Blank function'' auswählen<br />[[Datei:Aws.amazon.com-05-select_blueprint.png|200px]]<br />
# Im neuen Fenster dann auf den gestrichelten Kasten klicken und ''Alexa Smart Home'' auswählen und mit ''Next'' bestätigen<br />[[Datei:Aws.amazon.com-06-configure_triggers1.png|200px]]<br />
## Achtung, es ist möglich, dass dabei ''Alexa Smart Home'' überhaupt nicht angeboten wird. Dann bitte ganz rechts oben in der Ecke nachsehen, welche Region bzw. welches Land ausgewählt ist. Empfohlen wird, ''Ireland'' auszuwählen. Dann erscheint bei den Funktionen auch ''Alexa Smart Home''.<br />
# Bei ''Application Id'' den Wert eintragen, dessen Ermittlung im Abschnitt [[#Skill_Id_bestimmen | Skill Id bestimmen]] beschrieben wird, den Haken bei ''Enable trigger'' setzen und mit ''Next'' bestätigen <br />[[Datei:Aws.amazon.com-06-configure_triggers3.png|200px]]<br />
# Auf der Konfigurationsseite eingeben:<br />
## ''Name'' -> ''FHEM''<br />
## ''Runtime'' -> Node.js 6.10 (oder 8.10). <br />
## ''Role'' -> ''Choose an existing role'' <br />
### Achtung: wenn es noch keine existing role gibt, zuerst ''Create a custom role'' -> in dem Popup dann ''lambda_basic_execution'' auswählen und auf ''Allow'' klicken sowie bei ''Existing role'' dann ''x'' wählen.<br />
# Auf der Code-Seite ist im großen Textfeld dann der Code aus der Datei ''lambda.js'' im Paket [[#Alexa-Fhem_installieren | Alexa-Fhem]] vollständig einzufügen. Dabei muss der vorhandene Code im Texteil komplett gelöscht, der Teil aus der ''lamda.js'' eingefügt und noch der Hostname im Quellcode an den eigenen Hostnamen angepasst werden. <br />
# Anschließend alles mit ''Next'' bestätigen.<br />[[Datei:Aws.amazon.com-07-configure_function.png|200px]]<br />
# Auf der Übersichtsseite dann ''Create function'' anklicken<br />[[Datei:Aws.amazon.com-08-review.png|200px]]<br />
<br />
==== Trigger für Custom Skill hinzufügen ====<br />
Editiert man eine Lambda-Funktion, werden auf der Seite ''Triggers'' diejenigen Dienste angezeigt, die diese Funktion aufrufen.<br />
* Hier taucht der Trigger ''Alexa Smart Home'' zusammen mit der ''Application Id'' auf, der bei der Einrichtung des SmartHome-Skills eingetragen wurde.<br />
* Zur Verbindung mit dem Custom Skill ist es nötig, einen zweiten Trigger hinzuzufügen. Durch Anklicken von ''Add Trigger'' wird eine Auswahlseite eingeblendet. Im neuen Fenster dann auf den gestrichelten Kasten klicken und ''Alexa Skills Kit' auswählen und mit ''Next'' bestätigen<br />
<br />
==== ARN der AWS Lambda Funktion bestimmen ====<br />
# Auf der Übersichtsseite oben links den Menüpunkt ''Functions'' aúswählen<br />[[Datei:Aws.amazon.com-09-go_overview.png|200px]]<br />
# Anschließend den Radiobutton der angelegten Funktion ''FHEM'' markieren und im Menü ''Action'' den Punkt ''Show ARN'' auswählen<br />[[Datei:Aws.amazon.com-10-1-show_arn.png|200px]]<br />
# Es wird nun eine ARN Adresse angezeigt, die für den Abschnitt [[#SmartHome_Skill_anlegen| SmartHome Skill anlegen]] benötigt wird<br />[[Datei:Aws.amazon.com-10-2-arn.png|200px]]<br />
<br />
=== Absichern des Zugriffs ===<br />
Natürlich muss der Zugriff auf den von Alexa-Fhem verwendeten Port (default: 3000, Bestandteil des Codes in der AWS Lambda-Funktion) durch die Firewall freigeschaltet werden (auf einer FritzBox unter "Portfreigaben").<br />
<br />
==== Absicherung direkt in Alexa-FHEM ====<br />
Die Kommunikation zwischen Amazon AWS und Alexa-FHEM ist auf die folgenden Arten gesichert:<br />
* Die Verbindung erfolgt per HTTPS<br />
* Es werden nur Verbindung angenommen auf denen ein gültiges Alexa-Event gesendet wird. <br />
* Es werden nur Verbindungen angenommen die ein gültiges und noch nicht abgelaufenes OAuth-Token enthalten. Jedes neue Token wird live bei Amazon auf Gültigkeit geprüft. <br />
* Es werden nur Verbindungen mit lokal konfigurierter Skill-ID angenommen.<br />
* Es ist nicht möglich von außen beliebige FHEM Kommandos zu senden. Die FHEM Kommandos werden nur lokal erzeugt.<br />
<br />
Wer möchte kann Alexa-FHEM natürlich noch weiter absichern. Es gilt aber, dass nicht jedes zusätzliche Glied in der Kette die Sicherheit sondern unter Umständen nur die Angriffsfläche erhöht. Ein falsch konfigurierter und nach aussen offener Apache (oder anderer ReverseProxy) ist unter Umständen ein größeres Risiko als Alexa-FHEM alleine.<br />
<br />
==== Absicherung per ReverseProxy ====<br />
<s>Die Kommunikation zwischen Amazon und FHEM ist wegen der Verwendung von SSL schon verschlüsselt - prinzipiell kann aber jeder von außen mit Alexa-Fhem kommunizieren. Man sollte sich deshalb im Klaren darüber sein, dass dies eine Sicherheitslücke darstellt:</s> Jeder offene Port verleitet zu Angriffen, und mit zunehmender Verbreitung von Alexa steigt auch das Risiko. Es wird deshalb empfohlen, vor den eigentlichen Alexa-Server zur Absicherung einen Apache-Webserver als ReverseProxy zu setzen. Nicht nur ist der Apache eine hervorragend stabile und seit Jahrzehnten getestete Software, sondern die Konfiguration als ReverseProxy erlaubt auch, den Zugriff auf den Alexa-Fhem-Rechner auf die Amazon-Maschinen zu beschränken.<br />
<br />
'''Achtung: Dies ist keine allgemeine Anleitung in Sachen Computersicherheit.''' Im Folgenden gehen wir davon aus, dass <br />
* Grundbegriffe wie Firewall, IP-Ports, SSL und Dynamic DNS vertraut sind<br />
* Ein Apache Webserver (idealerweise auf einer zweiten Maschine) bereits installiert ist und die Konfiguration verstanden wurde (wenn nicht: Es gibt im Netz ''tausende'' von Anleitungen dafür...)<br />
* Ein Servername von einem DynDNS-Anbieter - sagen wir ''myhome.is-my-castle.com'' - bereits von ''außen'' auf unser SmartHome zeigt.<br />
* Alexa-Fhem in einer der oben beschriebenen Basiskonfigurationen läuft, d.h. der Zugriff auf <code>https://myhome.is-my-castle.com:3000</code> ergibt, wie im Punkt [[#Alexa-Fhem_testen|Alexa-Fhem testen]] beschrieben, eine Antwort des Node.js Servers.<br />
<br />
Als erster Schritt zur Absicherung muss das ReverseProxy Modul für den Apache installiert und mit <code>a2enmod</code> aktiviert werden, hierzu sei auf [https://www.digitalocean.com/community/tutorials/how-to-use-apache-http-server-as-reverse-proxy-using-mod_proxy-extension diese Anleitung] verwiesen. Der zweite Schritt besteht darin, den SSL-Zugriff durch ein Passwort abzusichern. Dazu wird auf dem Apache-Rechner das Programm <br />
htpasswd <passwdfile> <username><br />
ausgeführt, das Programm fragt dann nach dem gewünschten Passwort. Wir nehmen im Folgenden an, dass das Passwortfile ''/etc/apache2/htpasswd'' ist, der gesetzte Username ''alexa'' lautet und das Passwort ''my_smarthome'' ist.<br />
<br />
Im dritten Schritt wird nun in das Apache-Konfigurationsfile die Weiterleitung auf den eigentlichen Alexa-Fhem-Rechner eingetragen. Dazu wählen wir, dass von außen der Standard-SSL-Port 443 benutzt werden soll, sowie als Verzeichnisname ''/alexa''. '''Achtung:''' Dieser Code soll '''nicht''' in die Default-Konfiguration des Apache-Webservers. Sondern in eine separate Datei (Dateiname z.B. "fhem"), die ins Unterverzeichnis /etc/apache2/conf.d gestellt wird.<br />
<br />
<VirtualHost *:443><br />
ServerName myhome.is-my-castle.com<br />
SSLEngine on<br />
SSLProxyEngine on<br />
SSLProxyCheckPeerCN off<br />
SSLProxyCheckPeerName off<br />
SSLCertificateKeyFile /etc/apache2/mycert/server.key<br />
SSLCertificateFile /etc/apache2/mycert/server.crt<br />
<Location /alexa><br />
AuthType Basic<br />
AuthName "Authentication Required"<br />
AuthUserFile "/etc/apache2/htpasswd"<br />
Require valid-user<br />
ProxyPass https://<hier IP-Adresse des Alexa-Fhem-Rechners>:3000/<br />
ProxyPassReverse https://<hier IP-Adresse des Alexa-Fhem-Rechners>:3000/<br />
Order deny,allow<br />
Allow from All<br />
</Location><br />
(... Hier eventuell weitere Umleitungen)<br />
</VirtualHost><br />
Nach einem Neustart des Apache-Servers, dem Schließen des Ports 3000 in der Firewall sowie dem Öffnen des Ports 443 ist der Alexa-Fhem-Rechner von außen nur noch erreichbar durch den Aufruf von <code>https://myhome.is-my-castle.com/alexa</code> und verlangt unmittelbar die Eingabe von Username und Passwort.<br />
<br />
Der vierte Schritt ist nun, den Code der AWS Lambda-Funktion an fünf Stellen zu verändern<br />
'''const PORT=443;'''<br />
const HOST='myhome.is-my-castle.com';<br />
'''const PATH='/alexa';'''<br />
'''const AUTH='alexa:my_smarthome';'''<br />
// entry<br />
exports.handler = function(event, context, callback) {<br />
console.log(`EVENT: ${event}`);<br />
console.log(`CONTEXT: ${context}`); <br />
var post_data = JSON.stringify(event);<br />
var options = {<br />
hostname: HOST,<br />
port: PORT,<br />
//family: 6,<br />
'''path: PATH,'''<br />
method: 'POST',<br />
'''auth: AUTH,'''<br />
rejectUnauthorized: false, // accept self-signed<br />
(etc., Rest des Codes wie gehabt)<br />
Natürlich muss der Zugriff getestet werden. Bei Beachtung aller dieser Schritte werden alle un-autorisierten Zugriffe von außen abgewehrt. Eine noch weiter gehende Sicherung ist möglich, dazu kann in der Serverkonfiguration der Zugriff auf die Amazon-Domains beschränkt werden. Das ganze Alexa-System ist aber noch in konstanter Weiterentwicklung, diese Domain-Namen können sich also noch ändern.<br />
<br />
== Einrichtung in der Alexa App==<br />
Nachdem die Alexa Skills angelegt wurden, müssen diese noch in der Alexa App eingerichtet werden.<br />
Dafür jeweils per Desktop-Browser auf [http://alexa.amazon.de alexa.amazon.de] anmelden, nicht die App unter iOS oder Android verwenden. Diese hat Probleme mit der OAuth Verknüpfung.<br />
<br />
=== Alexa Skill ===<br />
# Auf ''Skills'' klicken<br />[[Datei:Alexa.amazon.de-01-startseite.png|200px]]<br />
# Oben rechts ''Meine Skills'' bzw. ''Ihre Skills'' auswählen<br />[[Datei:Alexa.amazon.de-03-meine_skills.png|200px]]<br />
# In der Liste der Skills sollte das angelegte FHEM Skill angezeigt werden. Dieses anklicken<br />[[Datei:Alexa.amazon.de-02-liste_skills.png|200px]]<br />
# Oben Rechts in den Details des Skills auf ''Skill aktivieren'' klicken<br />[[Datei:Alexa.amazon.de-04-skill_details.png|200px]]<br />
# In dem neu geöffneten Fenster die Autorisierung bestätigen<br />[[Datei:Alexa.amazon.de-05-amazon_auth.png|200px]]<br />
# Anschließend sollte die Verbindung erfolgreich aufgebaut worden sein <br />[[Datei:Alexa.amazon.de-06-success.png|200px]]<br />
<br />
=== Geräte ===<br />
# Auf http://alexa.amazon.de anmelden<br />
# Auf ''Smart Home'' klicken<br />[[Datei:Alexa.amazon.de-01-startseite.png|200px]]<br />
# Anschließend den Punkt ''Geräte suchen'' anklicken<br />[[Datei:Alexa.amazon.de-07-Gerätesuche.png|200px]]<br />
# Wurde soweit alles korrekt eingerichtet, werden nun die gefundenen Geräte angezeigt.<br />
<br />
Tip: Es macht Sinn, unter ''Meine Gruppen'' Gruppen benannt nach den Räumen einzurichten. Hierdurch kann Alexa die Geräte besser auseinander halten, vor allem wenn die den gleichen Alias (z.B. "Licht") haben.<br />
<br />
== Einrichtung unter FHEM ==<br />
Im Folgenden werden exemplarisch ein paar Geräte beschrieben, die man nutzbringend mit FHEM einsetzen kann.<br />
<br />
Bei Verwendung des Custom Skills übersetzt die Kombination der Attribute ''alexaMapping'' und ''homebridgeMapping'' Sprachbefehle ("Intents") in gerätespezifische Kommandos. <br />
* Das Attribut alexaMapping wird am Alexa-Device gesetzt und dient dazu, erkannte Sprachkommandos in abstrakte Characteristiken zu überführen. Für den einfacheren SmartHome Skill hat darum das Attribut ''alexaMapping'' keine Bedeutung, sondern nur der ''genericDeviceType'' des zu steuernden Gerätes.<br />
* Das Attribut homebridgeMapping wird für beide Skills am zu steuernden Gerät gesetzt und übersetzt diese Charakteristiken in die konkreten Befehle, die das Gerät versteht. Der inhalt des Attributs wird von links nach rechts ausgewertet und ist wie folgt aufgebaut:<br />
** Das Attribut enthält eine durch Leerzeichen getrennte Liste aus Konfigurationen für jeweils eine Characteristik<br />
** Jede einzelne der Characteristik-Konfigurationen besteht aus dem Namen der Characteristik, gefolgt von "=" und einer kommaseparierten Liste von Parametern.<br />
attr <device> homebridgeMapping <Characteristic1>=<param1.1>,<param1.2>,... <Characteristic2>=<param2.1>,<param2.2>,...<br />
** Jeder Parameter besteht entweder aus<br />
*** <code><cmd>:<device>:<reading></code>, hier können nicht verwendete Elemente von links nach rechts weg gelassen werden.<br />
*** <code><name>=<value></code>, hier kann <code><value></code> entweder ein Wert oder semikolonseparierte Liste sein.<br />
*** Oder dem schlüsselwort <code>clear</code>, welches alle vorhandenen (default) Parameter dieser Characteristik löscht. <code>clear</code> kann auch an Stelle einer ganzen Characteristik-Konfiguration stehen<br />
Weiter führende Dokumentation zum homebridgeMapping findet sich unter https://forum.fhem.de/index.php/topic,48558.0.html<br />
<br />
=== Einfacher Schalter ===<br />
* Ein einfacher Schalter, der die set-Kommandos ''on'' und ''off'' kennt, kann direkt mit Alexa-Fhem gekoppelt werden <br />
* Für kompliziertere Aktionen, etwa das Übermitteln eines spezifischen Schaltbefehls an FHEM, ist die Einrichtung eines Dummies zu empfehlen. <br />
Ob Dummy oder nicht, wichtig sind die drei fett gedruckten Zeilen<br />
define Alexa.Party dummy<br />
'''attr Alexa.Party alexaName party'''<br />
'''attr Alexa.Party alexaRoom alexaroom'''<br />
'''attr Alexa.Party genericDeviceType switch'''<br />
attr Alexa.Party group AlexaGeräte<br />
attr Alexa.Party room AlexaRoom<br />
attr Alexa.Party setList on off<br />
Selbstverständlich kann man diesen Dummy mit einem notify oder DOIF abfangen, um die gewünschte Schaltaktion auszuführen. <br />
<br />
Ein Alternative zum Dummy ist das Anlegen eines readingsProxy, dem die entsprechenden Attribute gegeben werden.<br />
<br />
Weil es sich hierbei um eines der einfachen Geräte handelt, die Alexa selbst im SmartHome Skill bearbeiten kann, ist auch der zweite Schritt bei der Einrichtung in der Alexa App sinnvoll: Der Schalter wird dann im Bereich Smart Home der Alexa App erkannt. Wer ihn auch mit dem Custon Skill bedienen möchte, muss natürlich Sorge tragen, dass der Alexa-Name ''party'' bei den FHEM_Devices auftaucht und die entsprechenden weiteren Slot Types und Example Utterances in der Konfiguration des Custom Skills vorhanden sind (siehe Abschnitt [[##Custom_Skill_anlegen | Custom Skill Anlegen]]).<br />
<br />
=== Wecker ===<br />
Dieses Gerät kann man nur mit dem Custom Skill bedienen, es wird also '''nicht''' im Bereich Smart Home der Alexa App auftauchen. Wir richten einen Dummy ein, wichtig sind wieder die fett gedruckten Zeilen:<br />
define Alexa.Weckzeit dummy<br />
'''attr Alexa.Weckzeit alexaName weckzeit'''<br />
'''attr Alexa.Weckzeit alexaRoom alexaroom'''<br />
attr Alexa.Weckzeit genericDeviceType clock<br />
attr Alexa.Weckzeit group AlexaGeräte<br />
'''attr Alexa.Weckzeit homebridgeMapping Weckzeit=state,cmd=+'''<br />
attr Alexa.Weckzeit room AlexaRoom<br />
'''attr Alexa.Weckzeit setList Weckzeit:time'''<br />
Das Attribut ''genericDeviceTye'' ist nicht wichtig, weil es ein generisches Device dieser Art gar nicht gibt. Wichtig hingegen ist das Attribut ''homebridgeMapping'' <br />
<br />
Für das Gerät ''MyAlexa'', das in Abschnitt definiert wurde, muss im Attribut ''alexaMapping'' auftauchen<br />
Weckzeit=verb=stelle,valuePrefix=für;auf,values=AMAZON.TIME,valueSuffix=uhr<br />
Darüber hinaus muss der Alexa-Name ''weckzeit'' bei den FHEM_Devices auftauchen und die entsprechenden weiteren Slot Types und Example Utterances in der Konfiguration des Custom Skills vorhanden sein (siehe Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]]).<br />
<br />
Der Aufruf dieses Gerätes mit Alexa erfolgt dann z.B. mit den Sätzen<br />
<pre style="width:50%;"><br />
"Alexa, sage <Custom Skill Invocation Name>: Stelle Weckzeit auf Neunzehn Uhr Siebenundzwanzig"<br />
"Alexa, frage <Custom Skill Invocation Name> nach dem Status von Weckzeit"<br />
</pre><br />
Dabei ist natürlich der ''Custom Skill Invocation Name'' durch den Wert zu ersetzen, den man im Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]] unter Punkt 2 eingetragen hat.<br />
<br />
Zur weiteren Bearbeitung kann man jetzt mit einem DOIF Statusänderungen des Dummies abfangen und durch eine kleine Helperfunktion ins "echte" FHEM weiterleiten.<br />
define Alexa.Weckzeit.N DOIF (["Alexa.Weckzeit:.*"])({AlexaHelper("Alexa.Weckzeit","$EVENT")}) <br />
Die Helperfunktion (z.B. in 99_myUtils.pm) stellt aus der übergebenen Zeit (immer im Format dd:mm) eine sprachkompatible Nachricht $nc und einen mit den FHEM-Zeitangaben kompatiblen String $nt zusammen und reicht beide an eine Routine ''changeWakeTime'' weiter (dokumentiert in den [https://www.dpunkt.de/buecher/12387/9783960090120-smarthome-hacks.html Smart Home Hacks]).<br />
sub AlexaHelper($$){<br />
my ($name,$event)=@_;<br />
if( $name eq "Alexa.Weckzeit" ){ <br />
my ($nc,$nt);<br />
#-- volle Stunde----------------------------------------<br />
if( $event =~ /(\d+):00/ ){<br />
$nc=sprintf("%d Uhr",$1);<br />
$nt=sprintf("%02d:00:00",$1);<br />
#-- nicht volle Stunde---------------------------------<br />
}elsif( $event =~ /(\d+):(\d+)/ ){<br />
$nc=sprintf("%d Uhr %d",$1,$2);<br />
$nt=sprintf("%02d:%02d:00",$1,$2);<br />
}<br />
changeWakeTime(\'GalaxyTab.EG\',\'$nc\',\'$nt\');<br />
}<br />
}<br />
<br />
<hr><br />
<br />
=== Lichtszene ===<br />
Eine Lichtszene wird mit dem Modul LightScene angelegt. Wir gehen davon aus, dass in der Lichtszene die beiden Szenen Alle_An und Alle_Aus, sowie mindestens eine weitere Szene (hier: Sitzgruppe) definiert wurde.<br />
* Nachfolgend wird ein Beispiel beschrieben, wie man eine Lichtszene mit dem einfachen SmartHome Skill steuern kann. Die verwendeten Kommandos sind dann<br />
<pre><br />
"Alexa, schalte (die) Beleuchtung an" -> LightScene Alle_An wird ausgewählt<br />
"Alexa, schalte (die) Beleuchtungsitzgruppe an" -> LightScene Sitzgruppe wird ausgewählt<br />
...<br />
"Alexa, schalte (die) Beleuchtung aus" -> LightScene Alle_Aus wird ausgewählt<br />
</pre><br />
* Künftig wird man LightScene mit dem Custom Skill eventuell direkt steuern können - allerdings hat das einen geringeren WAF, als die Steuerung über den SmartHome Skill: Der Einschaltsatz muss dann mindestens lauten<br />
<pre><br />
"Alexa, sage <Custom Skill Invocation Name>: schalte (die) Beleuchtung an" -> LightScene Alle_An wird ausgewählt<br />
</pre><br />
Dafür wird es aber auch möglich sein direkt die SzenenNamen im gesprochenen Kommando zu verwenden und so auf die Umwege über dummys und ähnliches zu verzichten.<br />
<br />
<br />
Im ersten Schritt wird ein Dummy für die Gesamtbeleuchtung eingerichtet:<br />
define Alexa.Beleuchtung dummy <br />
attr Beleuchtung setList on off<br />
'''attr Alexa.Beleuchtung alexaName beleuchtung'''<br />
'''attr Alexa.Beleuchtung alexaRoom alexaroom'''<br />
'''attr Alexa.Beleuchtung genericDeviceType switch'''<br />
Anschließend wird für jede vorhandene Lichtszene (außer Alle_An und Alle_Aus) ein weiterer Dummy angelegt:<br />
define Alexa.Beleuchtung.Sitzgruppe dummy <br />
attr Beleuchtung setList on off<br />
'''attr Alexa.Beleuchtung.Sitzgruppe alexaName beleuchtungsitzgruppe'''<br />
'''attr Alexa.Beleuchtung.Sitzgruppe alexaRoom alexaroom'''<br />
'''attr Alexa.Beleuchtung.Sitzgruppe genericDeviceType switch''' <br />
Die eigentliche Steuerung übernimmt dann ein DOIF<br />
define Alexa.Beleuchtung.N DOIF<br />
(["Alexa.Beleuchtung.Sitzgruppe:on"])<br />
(set <devicename der Lichtszene> scene Sitzgruppe,<br />
set Alexa.Beleuchtung off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
DOELSIF<br />
... <weitere on-Events der anderen Szenen werden abgefangen><br />
DOELSEIF<br />
(["Alexa.Beleuchtung:on"])<br />
(set <devicename der Lichtszene> scene Alle_An,<br />
set Alexa.Beleuchtung.Sitzgruppe off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
DOELSEIF<br />
(["Alexa.Beleuchtung:off"])<br />
(set <devicename der Lichtszene> scene Alle_Aus,<br />
set Alexa.Beleuchtung.Sitzgruppe off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
Mit diesem DOIF wird ein Radiobutton simuliert, d.h. wie bei den Stationstasten vor Uralt-Radios sorgt die Auswahl einer Szene immer dafür, dass alle anderen Dummies ausgeschaltet werden.<br />
Natürlich kann man das auch mit einem kleinen Perl-Programm erreichen.<br />
<br />
<br />
Zwei andere Ansätze Lichtszenen zu schalten die ohne DOIF auskommen sind im Folgenden beschrieben:<br />
<br />
* Wenn es von Interesse ist die Steuerung mit einer Darstellung in FTUI zu verbinden: Statt der oben beschriebenen dummy Devices kann man readingsProxy Devices mit passenden setFn und valueFn analog zum [[Harmony#Button_f.C3.BCr_eine_bestimmte_Activity_im_Frontend_und_Homekit_.C3.BCber_readingsProxy|diesem Beispiel für harmony aktivitäten]] verwenden.<br />
<br />
* Für jede zu schaltende Szene wird ein dummy angelegt dessen homebridgeMapping direkt auf das LightScene Device zeigt:<br />
<br />
define <dummy> dummy<br />
attr <dummy> setList on off<br />
attr <dummy> genericDeviceType switch<br />
attr <dummy> homebridgeMapping On=<light scene>::state,valueOn=<szene>,cmdOn=scene+<szene>,cmdOff=scene+<szene aus><br />
<br />
Bei der zweiten Variante wird davon ausgegangen das der aktuelle status nicht abgefragt oder angezeigt werden soll. Deshalb gibt es keine direkte RadioButton Funktionalität.<br />
<br />
=== Harmony Hub ===<br />
Ein [https://forum.fhem.de/index.php/topic,60244.msg550298.html#msg550298 HowTo-Beitrag im Forum] beschreibt die Ansteuerung von Harmony-Aktionen über den Custom Skill, beispielsweise für eine Aktion ''ARD'': „Alexa, sage FHEM stelle Anlage auf ARD“.<br />
<br />
== Nutzung ==<br />
Um den Namen zu bestimmen, unter dem ein Gerät mit Alexa angesprochen wird, verwendet Alexa-Fhem mit absteigender Priorität:<br />
* das alexaName Attribut<br />
* das alias Attribut<br />
* das NAME Internal<br />
Damit Alexa ein Gerät eindeutig identifizieren kann, sollten eindeutige Gerätenamen verwendet werden, bestehed möglichst aus einem Wort und ohne Ziffern. Wenn Alexa einen Namen nicht versteht, kann man unter [http://alexa.amazon.de/spa/index.html] nachsehen was tatsächlich verstanden wurde und den Gerätenamen ggf. anpassen.<br />
<br />
=== SmartHome Skill ===<br />
Gruppen (Räume) müssen in der Alexa App konfiguriert werden. Über das API lassen sich nur der Name und die Schalteigenschaften übergeben.<br />
<br />
Nach erfolgreicher Einrichtung des SmartHome Skills sollte Alexa mit den folgenden Befehlen nutzbar sein:<br />
<pre style="width:50%;"><br />
“alexa, schalte <gerät/gruppe> ein”<br />
“alexa, schalte <gerät/gruppe> aus”<br />
“alexa, stelle <gerät/gruppe> auf <wert> prozent”<br />
“alexa, stelle <gerät/gruppe> auf <anzahl> grad”<br />
“alexa, erhöhe <gerät/gruppe> um <anzahl> prozent”<br />
“alexa, reduziere <gerät/gruppe> um <anzahl> prozent”<br />
“alexa, erhöhe <gerät/gruppe> um <anzahl> grad”<br />
“alexa, reduziere <gerät/gruppe> um <anzahl> grad”<br />
</pre><br />
<br />
=== Custom Skill ===<br />
Der Custom Skill erlaubt im Gegensatz zum SmartHome Skill eine weitreichende Konfiguration der möglichen Kommandos. Die Dokumentation ist aktuell noch über diverse Artikel im Wiki verstreut:<br />
<br />
*Das Prinzip der Kommandokonfiguration ist {{Link2Forum|Topic=60244|Message=532513|LinkText=hier}} beschrieben.<br />
*Die erste Umsetzung ist {{Link2Forum|Topic=60244|Message=540117|LinkText=hier}} beschrieben.<br />
*Mehr zu FHEM-Intents und deren Möglichkeiten gibt es {{Link2Forum|Topic=67490|Message=589378|LinkText=hier}}.<br />
*Wie man die Alexa TTS-Engine bei den Antworten auf FHEM-Intents beeinflussen kann {{Link2Forum|Topic=77421|Message=693631|LinkText=hier}}.<br />
<br />
<br />
<br />
TODO: Abfragen, Attribute (alexaMapping, alexaTypes, fhemIntents, articles, prepositions), alles hier sammeln.<br />
<br />
== Troubleshooting ==<br />
<br />
====Allgemeiner Hinweis====<br />
Besonders wichtig ist, dass man sich sehr genau an diese Anleitung hält. Ein häufiger Fehler ist, dass die einfachen Anführungszeichen in der Anleitung unter '''AWS Lambda Funktion anlegen''' Punkt 8 einfach weggelassen werden. Diese sind zwingend notwendig. Es darf auch nur der reine Hostname eingetragen werden. Also kein ''http://'' davor. Entweder eine feste IP Adresse oder den Hostnamen, um den Rechner zu erreichen, den ihr über den Port 3000 freigegeben habt. Das sollte dann so aussehen:<br />
<pre style="width:50%;"><br />
const PORT=3000;<br />
const HOST='mein.host.name';<br />
</pre><br />
<br />
====Freigabe von Port 3000====<br />
{{Randnotiz|RNTyp=Fehl|RNText=Derzeit müsst ihr über einen echten IPv4 Anschluss verfügen, damit der Amazon Lambda-Server euch erreichen kann. DS-Lite Anschlüsse wie die von <b>UnityMedia</b> z.B. funktionieren derzeit leider nicht. Eine möglicher "Workaround" wird hier beschrieben: https://forum.fhem.de/index.php/topic,60244.msg518276.html#msg518276}}<br />
<br />
Auf dem Router muss der Port 3000 Protokoll TCP freigegeben werden. D.h. von außen muss man wenn man den Port 3000 aufruft, auf dem intern laufenden node.js Alexa-Dienst zugreifen können.<br />
Je nach Router gestaltet sich das Portforwarding bzw. die Portumleitung etwas schwieriger.<br />
<br />
Bei einem Speedport Router der Telekom beispielsweise, muss der Router komplett neu gestartet werden, wenn die Portfreigabe eingerichtet wurde. <br />
<br />
Bei der Fritz!Box ist das nicht nötig, bei dieser finden die Freigabe unter ''Internet -> Freigaben -> Portfreigaben'' statt. Dort wählt man dann den Rechner aus und richtet eine neue Freigabe ein. Wichtig hierbei ist, dass man Portfreigabe auswählt und nicht MyFRITZ!-Freigabe. Bei Port von bis trägt man 3000 ein, bei Port extern ebenfalls.<br />
<br />
Um die Portweiterleitung zu testen, solltet ihr euch auch nicht im gleichen Netz befinden. Viele Router blockieren den Netzaufruf aus dem gleichen Netz. Am besten testet ihr es, wenn ihr an eurem Mobiltelefon W-LAN deaktiviert und im Browser folgende Seite aufruft: ''https://mein.hostname:3000''. Wenn ihr im Browser dann einen Quellcode von Alexa seht, funktioniert die Portumleitung.<br />
<br />
Wenn bis hier alles funktioniert und es läuft dennoch nicht rund, liegt das Problem woanders. Kommt z.B. bei der Gerätesuche kein Request rein (sichtbar auf dem Bildschirm, wenn bin/alexa gestartet wurden), kann evtl. der Lambda-Dienst falsch konfiguriert sein.<br />
<br />
====Probleme mit node.js - npm install====<br />
<br />
Falls eine Fehlermeldung auftritt, dass "npm" nicht gefunden werden kann, bitte NodeJS entsprechend der Anleitung im Homebridge-Artikel vorgehen: [[Homebridge_einrichten#NodeJS_installieren|NodeJS installieren]] sowie [[Homebridge_einrichten#Python.2C_g.2B.2B.2C_MDNS_installieren|Python, g++, MDNS installieren]], siehe auch folgenden Abschnitt.<br />
<br />
====Es kommen diverse Fehlermeldungen beim Starten von alexa-fhem und es beendet sich====<br />
Wenn man auf der Konsole angemeldet ist, den Befehl<syntaxhighlight lang="bash" style="width:50%;">node -v</syntaxhighlight>eingeben. Ist die Version niedriger als die geforderte 0.12, muss eine neuere installiert werden. Hier darf man dann im Wiki unter [[Homebridge_einrichten#NodeJS_installieren]] nachschauen. NodeJS V4 sollte hierbei schon ausreichen. Solange die node.js Version nicht passt, gar nicht groß rum experimentieren! Bitte beachtet, dass alle Voraussetzungen unter [[Alexa-Fhem#Voraussetzungen]] erfüllt sind! Keine Experimente mit Versionen die darunter liegen.<br />
<br />
====Fehlermeldung ''NAT-PMP failed: Error: timeout'' Fehler angezeigt beim Start von alexa-fhem====<br />
Wenn ihr dann alexa-fhem über die Konsole startet und bekommt folgenden Fehler: ''NAT-PMP failed: Error: timeout'', lasst euch davon nicht irritieren. Das bedeutet lediglich, dass der Port nicht automatich freigegeben wurde über uPNP. Alternativ prüft, ob die Funktion der Portfreigabe via uPNP auf eurem Router aktiviert ist.<br />
<br />
====Nach Start auf der Console beendet sich Alexa-FHEM sofort wieder====<br />
Unmittelbar nach dem Start von Alexa-FHEM werden ein paar UPNP Fehlermeldungen ausgegeben. Unmittelbar danach beendet sich Alexa-FHEM wieder. <br />
<br />
Viele scheinen ein Problem mit UPNP auf dem Raspberry Pi zu haben. Wenn dieses Problem auftritt einfach in der <code>~/.alexa/config.json</code> die folgenden Zeilen rauslöschen:<br />
<br />
<pre><br />
"nat-pmp": "10.0.1.1",<br />
"nat-upnp": true,<br />
</pre><br />
<br />
Jetzt erneut Alexa-FHEM starten. Sollte nun laufen.<br />
<br />
====Was ist zu tun, wenn alexa-fhem keine Geräte findet?====<br />
Zunächst müssen die Geräte, die angesprochen werden wollen, unter FHEM ein neues Attribut zugewiesen bekommen. Dazu das Gerät in FHEM öffnen und das Attribut ''genericDeviceType switch'' hinzufügen, wenn es ein Schalter mit der Funktiona AN/AUS sein soll. Wenn man will, kann man dem Gerät jetzt noch über das Attribut ''alias'' eine besseren Namen geben, mit dem Alexa das Gerät dann auch finden kann.<br />
Anschließend muss alexa-fhem neu gestartet werden und die definierten Geräte sollten nun gefunden werden.<br />
<br />
====Was ist zu tun, wenn Alexa zwar Geräte findet, diese aber nicht angesprochen werden können?====<br />
Zuerst die Informationen zum Datenfluss ganz oben ansehen. Dann am besten von hinten nach vorne vorgehen:<br />
* wenn nichts bei alexa-fhem ankommt: port forwarding prüfen<br />
* wenn lambda.js nichts los wird: im cloudwatch log nachsehen<br />
* wenn bei lambda.js nichts ankommt: den trigger prüfen<br />
<br />
<br />
Zunächst sollte man sich unter ''http://aws.amazon.com'' das Logfile seiner erstellten Funktion anschauen. Ist überhaupt ein Logfile vorhanden? Falls nicht, liegt es vermutlich am Trigger.<br />
Den solltet ihr überprüfen. Scheinbar kommt es hin und wieder vor, dass dieser nicht gesetzt ist. Dazu einfach auf ''Triggers'' klicken und mit ''Add trigger'' erneut einen anlegen. Hier muss, wie in der Anleitung unter '''AWS Lambda Funktion anlegen''' Punkt 7, die ''Application Id'' stehen und der Haken bei ''Enable trigger'' gesetzt sein. Dann alexa-fhem neu starten.<br />
Wenn ihr Änderungen gemacht habt und den alexa-fhem Dienst noch nicht neu gestartet habt, wäre jetzt der richtige Zeitpunkt. Fürs Debugging empfiehlt es sich, alexa-fhem in einer Konsole laufen zu lassen, um eingehende Anfragen mitverfolgen zu können.<br />
<br />
<br />
Es kann sein, dass immer noch keine Log im Cloudwatch ([http://docs.aws.amazon.com/de_de/lambda/latest/dg/monitoring-functions-logs.html]) zu sehen ist. In dem Fall hilft es, eine neue Role Policy anzulegen. <br />
* in der AWS Console [https://console.aws.amazon.com] oben links auf Services klicken, und in der Gruppe "Security, Identity & Compliance" auf IAM klicken<br />
* links auf Roles klicken<br />
* Auf dem Knopf "Create Role" klicken<br />
* AWS Services > Lambda auswählen, unten auf Next:Permissions klicken<br />
* im Filter / Policy Type, "log" eintragen (ohne quotes)<br />
* CloudWatchLogsFullAccess hacken, auf Next:Review unten klicken<br />
* Name vergeben und mit "Create role" bestätigen<br />
* Oben links auf Services klicken, und in der Gruppe "Compute", auf Lambda klicken<br />
* auf den Name der Funktion klicken<br />
* Reiter Configuration auswählen<br />
* in Existing Role, den neukreierten Role auswählen<br />
* oben auf Save (und Testen wenn gewünscht) klicken.<br />
Schon sollte eine neue Gruppe im Cloudwatch sichtbar sein. Die Suche von den Devices in Alexa wiederholen, und die Logs analysieren<br />
<br />
====Was ist zu tun, wenn sich der Alexa-Service nicht starten lässt?====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Der User in der User= Directive von alexa.service muss Ausführungsrecht auf dem alexa binary haben (x), so wie auch mind. Lesezugriff auf dem Verzeichnis nach -U Option in der ExecStart= Directive und auch auf dem WorkingDirectory }}<br />
Schaut bitte in das Unterverzeichnis [alexa-fhem (also dort, wo Ihr Alexa-FHEM instelliert habt]/bin. Die dort befindliche Datei ''alexa'' muss ausführbar sein. Also z.B. so:<br />
<syntaxhighlight lang="bash" style="width:70%;">2755327 4 -rwxr-xr-x 1 pi pi 339 Nov 26 23:20 alexa</syntaxhighlight><br />
Sollte dies nicht der Fall sein bitte mit:<br />
<syntaxhighlight lang="bash" style="width:70%;">chmod +x alexa</syntaxhighlight><br />
die Datei ausführbar machen. Sofern der User "pi" Eigentümer ist, ist kein sudo erforderlich.<br />
<br />
Eine lauffähige Konfiguration ist {{Link2Forum|Topic=71612|Message=668383|LinkText=hier}} zu sehen.<br />
<br />
Ein Fehler in der Rechtekonfiguration führt in der Regel zu folgendem Ergebnis nach <code>sudo systemctl status alexa</code>:<br />
<br />
<syntaxhighlight lang="bash"> Loaded: loaded (/etc/systemd/system/alexa.service; enabled)<br />
Active: activating (auto-restart) (Result: exit-code) since mer. 2017-09-06 02:33:23 CEST; 3s ago<br />
Process: 18332 ExecStart=/opt/fhem/alexa-fhem/bin/alexa -U /home/alexa/.alexa (code=exited, status=217/USER)<br />
Main PID: 18332 (code=exited, status=217/USER)</syntaxhighlight><br />
<br />
====Wie kann ich via Alexa-FHEM auf FHEM zugreifen, wenn der Port mit Benutzername/Kennwort geschützt ist?====<br />
<br />
Hierzu muss die Datei <code>~/.alexa/config.json</code> geöffnet werden und der Abschnitt "connections" um folgende Zeile ergänzt werden:<pre><br />
"auth": {"user": "fhem", "pass": "fhempassword"},</pre><br />
Bei Verwendung von SSL bei FHEM muss auch noch <pre><br />
"ssl": true,</pre> hinzugefügt werden<br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Sprachsteuerung]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=Alexa-Fhem&diff=26582Alexa-Fhem2018-05-06T16:56:21Z<p>Amenomade: Installation: Ablauf des Zertifikats (Randnotiz)</p>
<hr />
<div>'''Alexa-Fhem''' ist eine in JavaScript geschriebene und auf NodeJS basierende Software, welche es ermöglicht, der digitalen Amazon Assistentin Alexa zusätzliche Skills für die Heimautomatisierung via FHEM beizubringen. Eine erste funktionierende Version wurde von [https://forum.fhem.de/index.php?action=profile;u=430 justme1968] im {{Link2Forum|Topic=60244|LinkText=Forum}} veröffentlicht.<br />
Das ist eine erste Version der Dokumentation zur Installation und Einrichtung, eine Erweiterung wird sicherlich in nächster Zeit noch folgen.<br />
{{Infobox Modul<br />
|ModPurpose=Anbindung von FHEM an Amazon Assistent Alexa<br />
|ModType=x<br />
|ModTechName=<br />
|ModForumArea=Frontends/Sprachsteuerung<br />
|ModOwner=justme1968<br />
}} <br />
<br />
<br />
==Einführung==<br />
===Glossar===<br />
*Echo bzw. Echo Dot (im Folgenden maskulin bezeichnet) sind die derzeit verfügbaren Geräte des Alexa-Systems '''BILDER EINSTELLEN - Achtung Urheberrecht'''<br />
*AVS ist der Amazon Voice Service, d.h. die Spracherkennungskomponente des Systems.{{Randnotiz|RNTyp=r|RNText=Für die Nutzung der Amazon AWS-Dienste müssen zwingend die Daten einer Kreditkarte angegeben werden. Nach gegenwärtigem Kenntnisstand sollen jedoch keine Kosten für die Nutzung der im Rahmen dieses How To beschriebenen Dienste anfallen, sofern diese in einem Rahmen genutzt werden, der selbst eine intensive private Nutzung nicht überschreitet. Der Benutzer sei an dieser Stelle auf die von Amazon veröffentlichten Preislisten verwiesen. Die Autoren dieser Anleitung und der darin beschriebenen Module übernehmen keine Haftung für eventuelle Kosten, die aus der Nutzung der AWS entstehen. }}<br />
*AWS sind die Amazon Web Services, also per URL erreichbare Dienste zur Ausführung von Berechnungen etc. Im Rahmen von Alexa-Fhem wird bei AWS eine eigene JavaScript-Funktion hinterlegt, die zur Kommunikation mit dem FHEM-Server dient. Im Jargon von Amazon ist dies eine so genannte Lambda-Funktion '''WARUM ? Nachlesen bei Amazon'''.<br />
*Card bezeichnet einen Eintrag in der Alexa-App, der die erkannte Sprachnachricht sowie weiter gehenden Informationen über die Reaktion von Alexa enzthält und Rückmeldung an Amazon erlaubt.<br />
*Skill (engl. für Fähigkeit) ist die Bezeichnung für eine per Spracherkennung bediente Funktionalität des Alexa-Systems, z.B. zur Nachrichtenansage, zur Wettervorhersage oder zur Steuerung von FHEM<br />
<br />
===Arbeitsweise und Datenfluss===<br />
[[Datei:2gpXyLN.jpg|200px|thumb|right|Grafische Darstellung der beteiligten Komponenten]]<br />
Echo -> AVS -> AWS Lambda -> alexa-fhem -> AWS Lambda -> AVS -> Echo<br />
<br />
*Der Echo (oder ein anderes Alexa/AVS fähiges Gerät) nimmt Audiodaten auf und schickt diese an AVS (Amazon Voice Service) zur Erkennung<br />
*AVS führt die Spracherkennung durch und erzeugt ein Event mit Informationen zu den erkannten Daten<br />
:*Beim Alexa SmartHome Skill sind die möglichen Sätze für die Spracherkennung relativ fest vorgegeben <br />
:*Beim Alexa Custom Skill kommen die dazu nötigen Informationen aus dem ''Interaction Model'' der Alexa Skills Configuration<br />
*Das Event wird an den unter ''Configuration'' in der Alexa Skills Configuration hinterlegten Endpoint geschickt<br />
:*Beim Alexa SmartHome Skill ist das zwingend eine AWS Lambda Routine<br />
:*Beim Alexa Custom Skill kann das im Prinzip auch ein eigener Web Service sein<br />
*Das Event wird vom <code>lambda.js</code> code an alexa-fhem weitergeleitet<br />
*alexa-fhem steuert FHEM und sendet ein Antwort-Event zurück<br />
*<code>lambda.js</code> nimmt diese Antwort entgegen und gibt sie an AVS zurück<br />
*AVS sogt dafür das der Echo 'antwortet' und dass die Card in der Alexa App erscheint<br />
<br />
===Anmerkungen===<br />
*Ein Skill hat keinen Zugriff auf die Audiodaten<br />
*Mit dem Skill API kann ein Skill zu zu keiner Zeit von sich aus aktiv werden und 'einfach' Daten an den Echo schicken oder ihn dazu bringen irgendetwas zu tun.<br />
*Wenn man berücksichtigt welchen Weg die Daten insgesamt gehen, ist es erstaunlich, wie schnell die Reaktion auf einen gesprochenen Satz erfolgt.<br />
<br />
=== Abgrenzung des '''Alexa Smart Home Skills''' und des '''Alexa Custom Skills''' ===<br />
<br />
Der [[Alexa-Fhem#Smart_Home|Alexa Smart Home Skill]] ist ein Amazon-Alexa-Standard-Skill, der wesentliche Basisfunktionalitäten bereitstellt. Zu diesen gehört im Wesentlichen die Funktionalität, durch Alexa-FHEM bereitgestellte Devices im Alexa-Account des Benutzers anzulegen. Der Alexa Smart Home Skill reagiert auf gesprochene Interaktion in einem beschränkten Umfang. Beispielsweise genügt ein "Alexa, schalte die Wohnzimmerlampe an" um eine Interaktion zwischen Alexa Smart Home Skill und FHEM-Alexa auszulösen. Nach erfolgreicher Einrichtung wird dieser Skill in der Alexa-App bzw. im Web in der Rubrik "Smart Home" als Skill angezeigt.<br />
<br />
Der [[Alexa-Fhem#Custom|Alexa Custom Skill]] ist kein Standard-Smart-Home-Skill, sondern ein individuell entwickelter Skill, so wie alle anderen Skills auch. Er wird daher auch nicht in der Alexa-App unter der Rubrik "Smart Home" angezeigt. Gesprochene Interaktion mit diesem Skill erfolgt dadurch, dass entweder der Skill explizit gestartet wird (z.B. "Alexa, starte [Name des Skills]") oder direkt angesprochen wird (z.B. "Alexa, frage [Name des Skills] wie ist der Status von [Device] "). Der Alexa Custom Skill befindet sich in Entwicklung und wird hinsichtlich seiner Funktionalitäten laufend weiterentwickelt. Die Einrichtung dieses Skills ist grundsätzlich optional, jedoch werden anspruchsvollere Steuerungsmöglichkeiten nur mit diesem realisiert werden können.<br />
<br />
==Installation==<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Da die einzelnen Schritte der Anleitung an verschiedenen Stellen unterbrochen und später fortgesetzt werden müssen, empfiehlt es sich, die Anleitung einmal vollständig gelesen zu haben. Während der Konfiguration sollten alle nachfolgenden Abschnitte parallel in gleichzeitig geöffneten Browserfenstern durchgeführt werden, die jeweils bis zum Abschluss geöffnet bleiben müssen. }}<br />
Grundvoraussetzung für alle folgenden Schritte ist das Vorhandensein eines Amazon-Accounts. Es wird davon ausgegangen, dass die Konten für alle im Folgenden genutzten Amazon-Dienste eingerichtet wurden.<br />
<br />
===node.js installieren===<br />
Zunächst wird das Betriebssystem (in diesem Falle Debian oder Ubuntu) auf den aktuellen Stand gebracht:<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
sudo apt-get update<br />
sudo apt-get upgrade<br />
sudo apt-get install build-essential libssl-dev</syntaxhighlight><br />
<br />
Nun muss NodeJS installiert werden. Leider ist die Version im Debian Repository deutlich zu alt, daher wird mit den folgenden Befehlen das Node Repository hinzugefügt und NodeJS (in der LTS Version) entsprechend installiert:<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -<br />
sudo apt-get install -y nodejs<br />
</syntaxhighlight><br />
<br />
=== Alexa-Fhem installieren ===<br />
'''Aus gegebenem Anlass: Dies ist weder eine Einführung in Linux, noch eine Anfängerdokumentation für FHEM.''' Also erst die Grundlagen lernen, und dann mit Alexa beginnen !<br />
<br />
Die aktuelle Version ist jeweils {{Link2Forum|Topic=81324|Message=733986|LinkText=hier}} zu finden.<br />
Wer bisher noch keinen Alexa-FHEM Skill angelegt hat, bitte {{Link2Forum|Topic=81324|Message=733986|LinkText=diesen Forumsbeitrag}} beachten!<br />
<br />
====Erstinstallation====<br />
Hier wird die Erstinstallation von Alexa-Fhem beschrieben.<br />
===== Linux =====<br />
# Die tgz-Datei unter Linux im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) entpacken (''nicht'' unter Windows, das zerstört die Rechteeinstellungen).<syntaxhighlight lang="bash" style="width:50%;">tar -xvzf dateiname.tgz</syntaxhighlight><br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen <syntaxhighlight lang="bash" style="width:50%;">mv package alexa-fhem</syntaxhighlight><br />
# Durch <syntaxhighlight lang="bash" style="width:50%;">cd alexa-fhem</syntaxhighlight> in das Verzeichnis wechseln<br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren (kein sudo!).<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=createKey.sh erzeugt ein Zertifikat, das 365 Tage gültig ist. Dies muss deswegen jedes Jahr erneuert werden }}<br />
# SSL Zertifikat erzeugen durch Aufruf von <syntaxhighlight lang="bash" style="width:50%;">./createKey.sh</syntaxhighlight> (kein sudo!). Hierbei beachten, dass ein Kennwort vergeben werden muss, das mindestens aus 4 Zeichen besteht, dieses Kennwort bitte merken.<br />
# Das Verzeichnis ''.alexa'' anlegen, ''und zwar im Home-Verzeichnis desjenigen Benutzers, unter dem Alexa-Fhem laufen soll.'' Insbesondere ist zu beachten, dass dieser Nutzer u.U. im Startskript explizit gesetzt wird. Mit dem untenstehenden Skript ist das ''nicht'' der User fhem, sondern der User ''pi''. Das Symbol ''~/'' verweist auf das Home-Verzeichnis des Benutzers, der gerade die Installation vornimmt.<br />
# Die Datei ''config-sample.json'' nach ''.alexa/config.json'' kopieren. Achtung: Installiert man alexa-fhem als root-user, zeigt das Symbol ''~/'' auf ''/root'' - und die Konfigurationsdatei wird ggf. bei einem manuellen Start von Alexa-Fhem nicht gefunden.<br />
# Achtung: Ggf. müssen auch die Dateien key.pem und cert.pem ins entsprechende Verzeichnis kopiert werden.<br />
===== Windows =====<br />
''Vor'' der Installation von Alexa-Fhem muss man folgende Anwendungen installieren:<br />
* Node.js (die aktuelle Version findet man unter https://nodejs.org/en/download/)<br />
* OpenSSL (http://slproweb.com/products/Win32OpenSSL.html oder https://www.heise.de/download/product/win32-openssl-47316/download)<br />
Erst dann fängt man mit Alexa-Fhem an.<br />
<br />
<br />
# Die tgz-Datei im Hauptverzeichnis von FHEM (z.B. <code>С:\Program Files (x86)\fhem</code>) entpacken.<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen<br />
# Windows-Shell (Kommandozeile, Eingabeaufforderung usw.) öffnen. "Start" -> "Ausführen" (oder [Windows-Taste]+[R]) -> cmd -> Ok. Durch <syntaxhighlight lang="bash" style="width:50%;">cd "<FHEM-Hauptverzeichis>\alexa-fhem"</syntaxhighlight> in das Verzeichnis wechseln. <br/>Dabei ist natürlich das <FHEM-Hauptverzeichis> durch den entsprechenden Pfad aus dem Schritt 1 zu ersetzen. Im o.g. Beispiel wäre es <code>cd "С:\Program Files (x86)\fhem\alexa-fhem"</code><br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren.<br/> Bei der Fehlermeldung wie "Der Befehl "npm" ist entweder falsch geschrieben oder konnte nicht gefunden werden." ist die Installation von Node.js zu überprüfen.<br />
# SSL Zertifikat erzeugen. Dafür muss man alle Befehle aus dem Skript ''createKey.sh'' nacheinander manuell ausführen. Hierbei beachten, dass ein Kennwort vergeben werden muss, das mindestens aus 4 Zeichen besteht, dieses Kennwort bitte merken. Der Windows-Welt unbekannter Befehl <code>mv</code> ist durch <code>move /y</code> zu ersetzen:<syntaxhighlight lang="bash" style="width:50%;">openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;">openssl rsa -in key.pem -out newkey.pem</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;">move /y newkey.pem key.pem</syntaxhighlight> Eventuelle Fehlermeldung "can't open config file: /usr/local/ssl/openssl.cnf" o.Ä. lässt sich durch Befehl <code>set OPENSSL_CONF=<OpenSSL-Verzeichnis>\bin\openssl.cfg</code> beheben, wobei <OpenSSL-Verzeichnis> durch den entsprechenden Installationspfad (typischerweise <code>c:\OpenSSL-Win32</code>) zu ersetzen ist.<br />
# Das Verzeichnis ''.alexa'' anlegen, ''und zwar im Benutzerverzeichnis desjenigen Benutzers, unter dem Alexa-Fhem laufen soll.'' In aktuellen Versionen von Windows (ab Windows 7 bzw. ab Windows Server 2008 R2) liegt das Verzeichnis unter <code>C:\Users\<Benutzername></code>, also z.B. für Benutzer "Administrator" - unter <code>C:\Users\Administrator</code>.<br/>Falls Windows sich weigert das Verzichniss mit dem Punkt am Anfang zu erstellen, kann man das aus der Kommandozeile machen:<syntaxhighlight lang="bash" style="width:50%;">cd "C:\Users\<Benutzername>"</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;"><br />
mkdir ".alexa"</syntaxhighlight><br />
# Die Datei ''config-sample.json'' nach ''C:\Users\<Benutzername>\.alexa\config.json'' kopieren.<br />
# Achtung: Ggf. müssen auch die Dateien key.pem und cert.pem ins entsprechende Verzeichnis (<code>"<FHEM-Hauptverzeichis>\alexa-fhem\bin</code>) kopiert werden.<br />
<br />
====Update====<br />
Hier wir das Update auf eine neue Version von Alexa-Fhem beschrieben<br />
===== Linux =====<br />
# Das Verzeichnis ''alexa-fhem'' im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) umbenennen in ''alexa-fhem.old''.<br />
# Die tgz-Datei der neuen Alexa-Fhem-Version unter Linux im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) entpacken (''nicht'' unter Windows, das zerstört die Rechteeinstellungen).<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen, in das Verzeichnis wechseln<br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren (kein sudo!).<br />
# Die Zertifikatsdateien key.pem und cert.pem aus dem alten Verzeichnis ''alexa-fhem.old'' ins neue Verzeichnis ''alexa-fhem'' kopieren.<br />
Natürlich dann den Dienst neu starten, auch müssen selbstredend irgendwelche Modifikationen an der Datei server.js in der neuen Version nachgezogen werden. Wenn alles läuft, kann das alte Verzeichnis ''alexa-fhem.old'' gelöscht werden.<br />
===== Windows =====<br />
# Das Verzeichnis ''alexa-fhem'' im Hauptverzeichnis von FHEM (z.B. <code>С:\Program Files (x86)\fhem</code>) umbenennen in ''alexa-fhem.old''.<br />
# Die tgz-Datei der neuen Alexa-Fhem-Version im Hauptverzeichnis von FHEM entpacken.<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen<br />
# Windows-Shell (Kommandozeile, Eingabeaufforderung usw.) öffnen. "Start" -> "Ausführen" (oder [Windows-Taste]+[R]) -> cmd -> Ok. Durch <syntaxhighlight lang="bash" style="width:50%;">cd "<FHEM-Hauptverzeichis>\alexa-fhem"</syntaxhighlight> in das Verzeichnis wechseln. <br/>Dabei ist natürlich das <FHEM-Hauptverzeichis> durch den entsprechenden Pfad aus dem Schritt 1 zu ersetzen. Im o.g. Beispiel wäre es <code>cd "С:\Program Files (x86)\fhem\alexa-fhem"</code><br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren.<br />
# Die Zertifikatsdateien key.pem und cert.pem aus dem alten Verzeichnis ''alexa-fhem.old'' ins neue Verzeichnis ''alexa-fhem'' kopieren.<br />
Natürlich dann den Dienst neu starten, auch müssen selbstredend irgendwelche Modifikationen an der Datei server.js in der neuen Version nachgezogen werden. Wenn alles läuft, kann das alte Verzeichnis ''alexa-fhem.old'' gelöscht werden.<br />
<br />
==== Alexa-Fhem konfigurieren ====<br />
Der Inhalt der Datei ''~/.alexa/config.json'' muss an die eigene Umgebung angepasst werden. <br />
# ''nat-pmp'' -> wenn nat-pmp verwendet werden soll: die ip des eigenen routers,<br />
# ''nat-upnp'' -> wenn nat-upnp verwendet werden soll: ''true'',<br />
# ''applicationId'' <br />
#:* Wenn man nur den SmartHome-Skill verwenden möchte, kann dieser Eintrag leer bleiben.<br />
#:* Ansonsten ist er mit der SkillID des Alexa Custom Skills zu belegen, siehe Abschnitt [[#Skill_Id_bestimmen | Skill Id bestimmen]]<br />
# ''oauthClientID'' -> ''Client ID'' dem Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
# ''server'' -> IP-Adresse des eigenen FHEM-Servers<br />
# ''port'' -> Portnummer des eigenen FHEM-Servers<br />
Beispiel:<br />
{<br />
"alexa": {<br />
"name": "Alexa TEST",<br />
"keyFile": "./key.pem",<br />
"certFile": "./cert.pem",<br />
"applicationId": "amzn1.ask.skill.xxxxxxxxxxxxxxxxxxxxxxxxxxxx",<br />
"oauthClientID": "amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"<br />
},<br />
"connections": [<br />
{<br />
"name": "FHEM",<br />
"server": "192.168.0.xxx.xxx",<br />
"port": "8083",<br />
"filter": "room=AlexaRoom"<br />
}<br />
]<br />
}<br />
<br />
Mehrere Custom Skills lassen sich mit der folgenden Syntax eintragen<br />
"applicationId": [ "amzn1.ask.skill.1" , "amzn1.ask.skill.2" ],<br />
"oauthClientID": [ "amzn1.application-oa2-client.1" , "amzn1.application-oa2-client.1" ]<br />
<br />
Danach durch Aufruf von <syntaxhighlight lang="bash" style="width:50%;">./bin/alexa</syntaxhighlight> den Dienst starten (kein sudo!)<br />
<br />
<br />
Unter Windows startet man den Alexa-Dienst durch <syntaxhighlight lang="bash" style="width:50%;">node alexa</syntaxhighlight> aus der <code>alex-fhem/bin</code> (also erst z.B. durch <code>cd "<FHEM-Hauptverzeichis>\alexa-fhem\bin"</code> ins richtige Verzeichnis kommen)<br />
<br />
Der Start des Alexa-Dienstes auf der Console ist immer dann zu empfehlen, wenn man auf die Ausgaben des Dienstes angewiesen ist und beispielsweise sehen möchte, welche Devices durch den Dienst bereitgestellt werden oder ob Fehler auftreten. Beendet man die Console-Session wird auch der Dienst wieder beendet. Insofern ist die vorgenannte Vorgehensweise nur für ein Debugging zu empfehlen und nicht im Regelbetrieb. Nachfolgend ist beschrieben, wie man den Alexa-Dienst aus FHEM heraus starten / stoppen und neu starten kann.<br />
<br />
==== Alexa-Fhem aus FHEM heraus starten ====<br />
Zunächst das Start-up-Skript aus diesem Post herunterladen {{Link2Forum|Topic=60244|Message=517271|LinkText=https://forum.fhem.de/index.php/topic,60244.msg517271.html#msg517271}} und unter /etc/init.d/alexa speichern.<br />
<br />
Das Script geht davon aus, das der alexa-fhem script unter /opt/fhem/alexa-fhem liegt, und die logfiles später unter /opt/fhem/log. Sollte das nicht der Fall sein, muss das Skript angepasst werden.<br />
<br />
Nun folgende Kommandos ausführen:<br />
<syntaxhighlight lang="bash" style="width:50%;">sudo chmod 755 /etc/init.d/alexa<br />
sudo update-rc.d alexa defaults</syntaxhighlight><br />
<br />
In der Datei <code>/etc/sudoers</code> den User fhem für die Nutzung von sudo zulassen (<code>sudo nano /etc/sudoers</code>), z.B. durch Anfügen der nachfolgenden Zeile:<br />
<code>fhem ALL=(ALL) NOPASSWD: ALL</code><br />
<br />
Nun folgende Devices anlegen (ggf. einem Raum zuordnen, z.B. AlexaControl):<br />
<syntaxhighlight lang="bash" style="width:75%;">define FHEM.Alexa.Status dummy<br />
<br />
define FHEM.Alexa dummy<br />
attr FHEM.Alexa event-on-change-reading state<br />
attr FHEM.Alexa webCmd status:start:stop:restart<br />
<br />
define FHEM.Alexa.DOIF DOIF ([FHEM.Alexa] eq "start") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa start > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "stop")<br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa stop > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "restart") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa restart > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "status") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa status > /dev/null 2>&1 &")})</syntaxhighlight><br />
<br />
==== Alexa-Fhem als Service (systemd) installieren ====<br />
Auf neueren Installationen (z.B. RPi Jessie) wird init.d durch systemd ersetzt. Folgend die Anleitung um alexa-fhem als Service zu installieren auf einem Raspberry Pi mit Jessie.<br />
<br />
Zunächst einen neuen Benutzer anlegen unter dem alexa-fhem laufen soll, falls man nicht möchtet dass alexa-fhem z.B. mit dem fhem User ausgeführt wird:<br />
<br />
<code lang="bash" style="width:75%;"><br />
sudo useradd -M --system alexa<br />
</code><br />
<br />
Eigentlich braucht der Benutzer keine Gruppen, aber man kann den Benutzer auch der Gruppe <code>dialout</code> hinzufügen (<code>sudo usermod -a -G dialout alexa</code>)<br />
<br />
Datei "alexa.service" unter <code>/etc/systemd/system</code> anlegen:<br />
<br />
[Unit]<br />
Description=Node.js Alexa Server <br />
After=syslog.target network-online.target<br />
<br />
[Service]<br />
Type=simple<br />
User=alexa <br />
WorkingDirectory=/opt/fhem/alexa-fhem<br />
ExecStart=/opt/fhem/alexa-fhem/bin/alexa -U /home/alexa/.alexa<br />
Restart=on-failure<br />
RestartSec=10<br />
KillMode=process<br />
<br />
[Install]<br />
WantedBy=multi-user.target <br />
<br />
Den Pfad <code>/home/alexa/.alexa</code> an die Systemgegebenheiten anpassen. Letztendlich kann die config.json irgendwo liegen, hauptsache alexa-fhem weiß wo. <br />
<br />
Im WorkingDirectory wird der alexa Dienst die Zertifikate suchen.<br />
<br />
Achtung: Natürlich muss der Benutzer auch Zugriff sowohl auf das Verzeichnis mit der config als auch das alexa-fhem Verzeichnis und das WorkingDirectory haben.<br />
<br />
Um den Service zu aktiveren und zu starten helfen folgende Befehle:<br />
sudo systemctl daemon-reload<br />
sudo systemctl enable alexa<br />
sudo systemctl start alexa<br />
<br />
Status abfragen mit<br />
sudo systemctl status alexa<br />
<br />
Log einsehen?<br />
sudo journalctl -u alexa<br />
<br />
(mit <code>-f</code> kann man den follow Modus aktivieren, wie <code>tail -f</code>).<br />
Bei einen reboot startet alexa-fhem jetzt automatisch.<br />
<br />
==== Alexa-Fhem testen ====<br />
Node.Js stellt einen Web-Server am Port 3000 bereit, das oben erzeugte Zertifikat sichert diesen Zugang per SSL ab. Durch Aufruf der Adresse<br />
<code>https://<IP-Adresse des Servers>:3000</code> kann man testen, ob der Alexa-Fhem Service läuft - der Seitenaufruf liefert eine Zeile JSON-Code, beginnend mit<br />
<code>{"header":{"name":"UnsupportedOperationError"...</code><br />
<br />
=== Alexa Device anlegen ===<br />
Das Modul 39_alexa.pm stellt innerhalb von FHEM verschiedene Attribute z.B. alexaName oder alexaRoom zur Verfügung. Manche dieser Attribute (wie z.b. alexaName) werden in beiden Skills verwendet, andere werden ausschließlich bei einer Nutzung des Alexa Custom Skill verwendet.<br />
<br />
Die Einrichtung des Alexa Device geschieht durch die nachfolgende Definition:<br />
<syntaxhighlight lang="bash" style="width:70%;">define MyAlexa alexa</syntaxhighlight><br />
<br />
<hr><br />
<br />
=== Alexa Skills ===<br />
Für folgende Schritte muss man unter der Adresse http://developer.amazon.com angemeldet sein<br />
# Anmeldung auswählen<br />[[Datei:Developer.amazon.com-01-login2.png|200px]]<br />
# Anmeldedaten eingeben<br />[[Datei:Developer.amazon.com-02-userpass2.png|200px]]<br />
<br />
==== Security Profile anlegen ====<br />
Die Erzeugung eines Sicherheitsprofils muss nur einmal erfolgen, es wird dann für alle weiteren Skills verwendet.<br />
# Nach der Anmeldung Auswahl von ''APPS & SERVICES''<br />[[Datei:Developer.amazon.com-03-apps_and_services.png|200px]]<br />
# Anschließend auswählen ''Security Profiles''<br />[[Datei:Developer.amazon.com-05-apps_and_services_-_security_profiles.png|200px]]<br />
# Auswählen ''Create a New Security Profile'' aus<br />[[Datei:Developer.amazon.com-06-apps_and_services_-_create_a_new_security_profile.png|200px]]<br />
# Dann einen Namen und eine Beschreibung für das Profil eingeben und mit ''Save'' bestätigen<br />[[Datei:Developer.amazon.com-07-apps_and_services_-_security_profile_management.png|200px]]<br />
<br />
===== Login with Amazon =====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Hier wird beschrieben, wo ''Client Id'' und ''Client Secret'' zu finden sind}}<br />
# Oben rechts auf ''Login with Amazon'' klicken (https://developer.amazon.com/lwa/sp/overview.html).<br/>[[Datei:Developer.amazon.com-08-login_with_amazon.png|200px]]<br />
# Auf der neu geladenen Seite auswählen ''Sign up''<br/>[[Datei:Developer.amazon.com-09-login_with_amazon_-_sign_up.png|200px]]<br />
# Anschließend im Dropdown Menü das vorher angelegte Profil auswählen und mit ''Confirm'' bestätigen<br/>[[Datei:Developer.amazon.com-10-login_with_amazon_-_create_new_profile.png|200px]] [[Datei:Developer.amazon.com-11-login_with_amazon_-_create_new_profile2.png|200px]]<br />
# Im folgenden Fenster die Adresse [https://www.amazon.com/gp/help/customer/display.html?nodeId=468496 https://www.amazon.com/gp/help/customer/display.html?nodeId=468496] eingeben und mit ''Save'' bestätigen. '''Todo Erklärungsbedarf: WARUM diese Adresse'''<br/>[[Datei:Developer.amazon.com-12-login_with_amazon_-_enter_consent_screen_information.png|200px]]<br />
# Anschließend bei dem neu angelegten Eintrag auf der rechten Seite auf das Zahnrad klicken und ''Web Settings'' auswählen<br/>[[Datei:Developer.amazon.com-13-login_with_amazon_-_web_settings.png|200px]]<br />
# Im neu geladenen Fenster anklicken von ''Edit''<br/>[[Datei:Developer.amazon.com-14-login_with_amazon_-_edit.png|200px]]<br />
# Anschließend bei ''Allowed Return URLs'' die folgenden drei Adressen eingeben. ''xxx'' muss hierbei durch den Wert ersetzt werden, der in den beiden Abschnitten [[#SmartHome_Skill_anlegen | SmartHome Skill anlegen]] bzw. [[#Custom_Skill_anlegen | Custom Skill anlegen]] jeweils unter Punkt 4 (Seite ''Configuration'') bei ''Redirect Urls'' am Ende der URLs angezeigt wird<br />
## [https://layla.amazon.co.uk/api/skill/link/xxx https://layla.amazon.co.uk/api/skill/link/xxx]<br />
## [https://pitangui.amazon.com/api/skill/link/xxx https://pitangui.amazon.com/api/skill/link/xxx]<br />
## [https://layla.amazon.com/api/skill/link/xxx https://layla.amazon.com/api/skill/link/xxx]<br />
.<br/>[[Datei:Developer.amazon.com-15-login_with_amazon_-_allowed_return_urls.png|200px]]<br />
<br />
==== Skills bearbeiten ====<br />
# Im Menü den Punkt ''ALEXA'' auswählen<br />[[Datei:Developer.amazon.com-03-apps_and_services.png|200px]]<br />
# Anschließend im Feld ''Alexa Skills Kit'' auf ''Get started'' klicken<br />[[Datei:Developer.amazon.com-17-alexa_-_alex_skills_kit_-_get_started.png|200px]]<br />
<br />
===== SmartHome Skill anlegen ====={{Randnotiz|RNTyp=r|RNText=aktuell lässt sich nur noch das v3 api auswählen. eine test version hierfür gibt es im {{Link2Forum|Topic=81324|LinkText=Forum}}. bitte die hinweise dort lesen und beachten.}}<br />
# Oben rechts ''Add a New Skill'' auswählen<br />[[Datei:Developer.amazon.com-18-alexa_-_alex_skills_kit_-_add_a_new_skill.png|200px]]<br />
# Auf der folgenden Seite eingeben und dann mit ''Next'' bestätigen:<br />
#:* ''Skill Type'' -> ''SmartHome Skill API'' <br />
#:* ''Language'' -> ''German''<br />
#:* ''Name'' -> beliebiger Name, z.B. "MySmartHome Basic")<br />
#:* ''Payload Version'' -> ''v2 (other devices)'' <br/>[[Datei:Developer.amazon.com-19-alexa_-_alex_skills_kit_-_skill_information.png|200px]] <br />
# Die folgende Seite einfach mit ''Next'' überspringen<br />[[Datei:Developer.amazon.com-20-alexa_-_alex_skills_kit_-_interaction_model.png|200px]]<br />
# Auf der Seite ''Configuration'' Folgendes eingeben:<br />
#:* ''Service Endpoint Type'' -> ''AWS Lambda'' ist vorausgewählt und kann nicht geändert werden.<br />
#:* ''Geographical Region'' -> ''Europe'' auswählen und im Textfeld die ARN aus Abschnitt [[#ARN_der_AWS_Lambda_Funktion_bestimmen | AWS Lambda Funktion]] eintragen. <br />
#:* ''Authorization URL'' -> <code>https://www.amazon.com/ap/oa</code><br />
#:* ''Client ID'' -> ''Client ID'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
#:* ''Scope'' -> <code>profile:user_id</code> (wörtlich 1:1 eintragen)<br />
#:* ''Redirect URLs'' - sollten vorbelegt sein<br />
#:* ''Authorization Grant Type'' -> ''Auth Code Grant'' auswählen<br />
#:* ''Access Token URI'' -> <code>https://api.amazon.com/auth/o2/token</code><br />
#:* ''Client Secret'' -> ''Client Secret'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
#:* ''Client Authentication Scheme'' -> ''HTTP Basic''<br />
#:* ''Privacy Policy URL'' -> <code>https://www.amazon.com/gp/help/customer/display.html?nodeId=468496</code><br /><br /><br />
<br />[[Datei:Developer.amazon.com-21-alexa_-_alex_skills_kit_-_configuration.png|200px]] [[Datei:Developer.amazon.com-22-alexa_-_alex_skills_kit_-_test.png|200px]]<br />
<br />
===== Custom Skill anlegen =====<br />
<ol><br />
<li> Oben rechts ''Add a New Skill'' auswählen<br />[[Datei:Developer.amazon.com-18-alexa_-_alex_skills_kit_-_add_a_new_skill.png|200px]]</li><br />
<li> Auf der folgenden Seite (''Skill Information'') die nachstehenden Daten eingeben und dann mit ''Next'' bestätigen:<br />
<ul><br />
<li> ''Skill Type'' -> ''Custom Interaction Model'' </li><br />
<li> ''Language'' -> ''German''</li><br />
<li> ''Name'' -> beliebiger Name, z.B. "MySmartHome Advanced". Dieser wird in der Alexa App unter "Meine Skills" angezeigt.</li><br />
<li> ''Invocation Name'' -> Aufruf des Skills, unter dem dieser später gestartet wird. Z.B. "Alexa, starte James"<br />[[Datei:CustomSkill_2.PNG|400px]]</li><br />
</ul></li><br />
<li>Auf der Seite ''Interaction Model'' folgende Eingaben tätigen und mit ''Next'' abschließen<br />
<ul><br />
<li>In einem separaten Browserfenster FHEM aufrufen, und für das bereits definierte Alexa-Gerät das Kommando <code>get MyAlexa interactionModel</code> aufrufen. Es erscheint ein Popup-Fenster mit ziemlich vielen Zeilen.<br />
<li>In die Box ''Intent Schema'' kopiert man den ersten Teil dieser FHEM-Ausgabe hinein, also:<br/><blockquote><br />
{ <br />
"intents" : [ <br />
<hier ziemlich viele Zeilen> <br />
]<br />
}<br />
</blockquote></li><br />
<li>Nun die ''Custom Slot Types'' einrichten. Dazu muss aus dem zweiten Teil der FHEM-Ausgabe jeweils der Slot-Type (z.B. <code>FHEM_article</code>) in das Feld ''TYPE'' eingetragen werden, das nach dem Anklicken von ''Add Slot Type'' erscheint. In das darunter liegende größere Textfeld kommen die möglichen Werte für diesen Slot, so wie sie aus der FHEM-Ausgabe abzulesen sind. Dann mit ''Save'' sichern. Als Custom Slot Type erscheint dann für diesen Beispiel-Slot<br />
FHEM_article der | die | das | den<br />
d.h., die Zeilenumbrüche bei den möglichen Werten werden als "|" dargestellt.</li><br />
<li>Hier muss nun ein Bruch im Arbeitsfluss durchgeführt werden, denn bei der Erstellung des Custom Skills kommt es auf die Reihenfolge der Einträge an. Deshalb zunächst diese FHEM-Ausgabe schließen, und für dasselbe FHEM-Device <code>get MyAlexa customSlotTypes</code> ausführen. Auch diese Ausgabe wird, wie oben beschriebeen, in Custom Slot Types eingetragen (erst der TYPE, dann die möglichen Werte)<br />
<li>Anschließend erneut die FHEM-Ausgabe schließen und erneut für das bereits definierte Alexa-Gerät das Kommando <code>get MyAlexa interactionModel</code> aufrufen.<br />
<li>Unter ''Sample Utterances'' nun den Text aus dem dritten Teil dieser FHEM-Ausgabe hineinkopieren<br />[[Datei:CustomSkill_5.PNG|400px]]</li><br />
</ul></li><br />
<li>Auf der Seite ''Configuration'' Folgendes eingeben und mit ''Next'' bestätigen:<br />
<ul><br />
<li>''Service Endpoint Type'' -> ''AWS Lambda'' auswählen</li><br />
<li>''Geographical Region'' -> ''Europe'' auswählen und im Textfeld den Wert aus Abschnitt [[#AWS_Lambda_Funktion_anlegen | AWS Lambda Funktion anlegen]] (Punkt 12) eintragen. </li><br />
<li>''Do you allow users to create an account or link to an existing account with you?'' -> ''Yes''</li><br />
<li>''Authorization URL'' -> <code>https://www.amazon.com/ap/oa</code></li><br />
<li>''Client ID'' -> ''Client ID'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1</li><br />
<li>''Scope'' -> <code>profile:user_id</code> (wörtlich 1:1 eintragen)</li><br />
<li>''Redirect URLs'' - sollten vorbelegt sein</li><br />
<li>''Authorization Grant Type'' -> ''Auth Code Grant'' auswählen</li><br />
<li>''Access Token URI'' -> <code>https://api.amazon.com/auth/o2/token</code></li><br />
<li>''Client Secret'' -> ''Client Secret'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1</li><br />
<li>''Client Authentication Scheme'' -> ''HTTP Basic''</li><br />
<li>''Privacy Policy URL'' -> <code>https://www.amazon.com/gp/help/customer/display.html?nodeId=468496</code></li><br />
</ul><br />
Beim Sichern dieser Seite mit ''Next'' kann es zu einer Fehlermeldung kommen, wenn man seine Skill-Definitionen mit dem einfachen SmartHome-Skill begonnen hat. Deshalb muss noch der entsprechende Trigger für die [[#AWS_Lambda-Funktion | AWS Lambda Funktion]] nachgetragen werden, dies wird in Abschnitt [[#Trigger_f.C3.BCr_Custom_Skill_hinzuf.C3.BCgen | Trigger für Custom Skill hinzufügen]] beschrieben.<br />
<br />[[Datei:CustomSkill_6.PNG|400px]] [[Datei:CustomSkill_7.PNG|400px]]</li><br />
<br />
==== Testen ====<br />
Hat man den Custom Skill angelegt, bietet dieser auch eine komfortable Testmöglichkeit. Dazu wählt man in der Übersichtsseite ''All Skills'' den Button ''Edit'' des Alexa Custom Skill aus. Auf der nachfolgenden Seite dann links ''Test''. <br />
Die Testseite enthält <br />
* ein Feld ''Voice Simulator'', mit dem man die Sprachsausgabe testen kann, <br />
* ein Feld ''Service Simulator'', mit dem die Verarbeitung von Alexa-Kommandois getestet werden kann. Hier kann man z.B. eintragen<br />
"Alexa, sage <Custom Skill Invocation Name>: Stelle Weckzeit auf Neunzehn Siebenundzwanzig Uhr"<br />
"Alexa, frage <Custom Skill Invocation Name> nach dem Status von Weckzeit"<br />
Dabei ist natürlich der ''Custom Skill Invocation Name'' durch den Wert zu ersetzen, den man im Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]] unter Punkt 2 eingetragen hat.<br />
<br />
==== Skill Id bestimmen ====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Hier wird beschrieben, wo die ''Alexa Skill Id'' zu finden ist}}<br />
Für das [[#AWS_Lamba_Funktion_anlegen | Anlegen einer ''AWS Lambda Funktion'']] bzw für die [[#Alexa-Fhem_konfigurieren | Konfiguration von Alexa-Fhem]] wird die ''Alexa Skill Id'' benötigt. An diese kommt man wie folgt:<br />
# Anmelden wie unter [[#Alexa_Skills | Alexa Skills]] beschrieben.<br />
# Menüpunkt ''ALEXA'' auswählen, wie [[#Skills_bearbeiten | Skills bearbeiten]] erklärt.<br />
# Beim gewünschten Eintrag auf ''Edit'' klicken<br />[[Datei:Developer.amazon.com-23-alexa_-_alex_skills_kit_-_overview.png|200px]]<br />
# Die Id, die nun oben angezeigt wird, ist die gesuchte. Sie hat typischerweise das Format <code>amzn1.ask.skill.[Zahlen und Bindestriche]</code><br />[[Datei:Aws.amazon.com-06-configure_triggers2.png|200px]]<br />
<br />
<hr><br />
<br />
=== AWS Lambda Funktion ===<br />
Für folgende Schritte muss man unter der Adresse http://aws.amazon.com angemeldet sein<br />
# Anmeldung auswählen<br />[[Datei:Aws.amazon.com-01-site.png|200px]]<br />
# Anmeldedaten eingeben<br />[[Datei:Aws.amazon.com-02-login.png|200px]]<br />
# Den Punkt ''Lambda'' links auf der Startseite auswählen, bzw. im Menü ''Services'' unter ''Compute'' den Menüpunkt ''Lambda'' auswählen<br />[[Datei:Aws.amazon.com-03-lambda.png|200px]]<br />
<br />
==== AWS Lambda Funktion anlegen ===={{Randnotiz|RNTyp=r|RNText=Die AWS Seiten sehen inzwischen etwas anders aus. Eine angepasste Beschreibung findet sich im {{Link2Forum|Topic=81790|Message=739211|LinkText=Forum}}. Bitte auch die Hinweise dort lesen.}}<br />
# Für eine erste Lambda-Funktion den Punkt ''Get Started Now'' auswählen<br />[[Datei:Aws.amazon.com-04-get_started_now.png|200px]]<br />
# Den Blueprint ''Blank function'' auswählen<br />[[Datei:Aws.amazon.com-05-select_blueprint.png|200px]]<br />
# Im neuen Fenster dann auf den gestrichelten Kasten klicken und ''Alexa Smart Home'' auswählen und mit ''Next'' bestätigen<br />[[Datei:Aws.amazon.com-06-configure_triggers1.png|200px]]<br />
## Achtung, es ist möglich, dass dabei ''Alexa Smart Home'' überhaupt nicht angeboten wird. Dann bitte ganz rechts oben in der Ecke nachsehen, welche Region bzw. welches Land ausgewählt ist. Empfohlen wird, ''Ireland'' auszuwählen. Dann erscheint bei den Funktionen auch ''Alexa Smart Home''.<br />
# Bei ''Application Id'' den Wert eintragen, dessen Ermittlung im Abschnitt [[#Skill_Id_bestimmen | Skill Id bestimmen]] beschrieben wird, den Haken bei ''Enable trigger'' setzen und mit ''Next'' bestätigen <br />[[Datei:Aws.amazon.com-06-configure_triggers3.png|200px]]<br />
# Auf der Konfigurationsseite eingeben:<br />
## ''Name'' -> ''FHEM''<br />
## ''Runtime'' -> Node.js 4.3. <br />
## ''Role'' -> ''Choose an existing role'' <br />
### Achtung: wenn es noch keine existing role gibt, zuerst ''Create a custom role'' -> in dem Popup dann ''lambda_basic_execution'' auswählen und auf ''Allow'' klicken sowie bei ''Existing role'' dann ''x'' wählen.<br />
# Auf der Code-Seite ist im großen Textfeld dann der Code aus der Datei ''lambda.js'' im Paket [[#Alexa-Fhem_installieren | Alexa-Fhem]] vollständig einzufügen. Dabei muss der vorhandene Code im Texteil komplett gelöscht, der Teil aus der ''lamda.js'' eingefügt und noch der Hostname im Quellcode an den eigenen Hostnamen angepasst werden. <br />
# Anschließend alles mit ''Next'' bestätigen.<br />[[Datei:Aws.amazon.com-07-configure_function.png|200px]]<br />
# Auf der Übersichtsseite dann ''Create function'' anklicken<br />[[Datei:Aws.amazon.com-08-review.png|200px]]<br />
<br />
==== Trigger für Custom Skill hinzufügen ====<br />
Editiert man eine Lambda-Funktion, werden auf der Seite ''Triggers'' diejenigen Dienste angezeigt, die diese Funktion aufrufen.<br />
* Hier taucht der Trigger ''Alexa Smart Home'' zusammen mit der ''Application Id'' auf, der bei der Einrichtung des SmartHome-Skills eingetragen wurde.<br />
* Zur Verbindung mit dem Custom Skill ist es nötig, einen zweiten Trigger hinzuzufügen. Durch Anklicken von ''Add Trigger'' wird eine Auswahlseite eingeblendet. Im neuen Fenster dann auf den gestrichelten Kasten klicken und ''Alexa Skills Kit' auswählen und mit ''Next'' bestätigen<br />
<br />
==== ARN der AWS Lambda Funktion bestimmen ====<br />
# Auf der Übersichtsseite oben links den Menüpunkt ''Functions'' aúswählen<br />[[Datei:Aws.amazon.com-09-go_overview.png|200px]]<br />
# Anschließend den Radiobutton der angelegten Funktion ''FHEM'' markieren und im Menü ''Action'' den Punkt ''Show ARN'' auswählen<br />[[Datei:Aws.amazon.com-10-1-show_arn.png|200px]]<br />
# Es wird nun eine ARN Adresse angezeigt, die für den Abschnitt [[#SmartHome_Skill_anlegen| SmartHome Skill anlegen]] benötigt wird<br />[[Datei:Aws.amazon.com-10-2-arn.png|200px]]<br />
<br />
=== Absichern des Zugriffs ===<br />
Natürlich muss der Zugriff auf den von Alexa-Fhem verwendeten Port (default: 3000, Bestandteil des Codes in der AWS Lambda-Funktion) durch die Firewall freigeschaltet werden (auf einer FritzBox unter "Portfreigaben").<br />
<br />
==== Absicherung direkt in Alexa-FHEM ====<br />
Die Kommunikation zwischen Amazon AWS und Alexa-FHEM ist auf die folgenden Arten gesichert:<br />
* Die Verbindung erfolgt per HTTPS<br />
* Es werden nur Verbindung angenommen auf denen ein gültiges Alexa-Event gesendet wird. <br />
* Es werden nur Verbindungen angenommen die ein gültiges und noch nicht abgelaufenes OAuth-Token enthalten. Jedes neue Token wird live bei Amazon auf Gültigkeit geprüft. <br />
* Es werden nur Verbindungen mit lokal konfigurierter Skill-ID angenommen.<br />
* Es ist nicht möglich von außen beliebige FHEM Kommandos zu senden. Die FHEM Kommandos werden nur lokal erzeugt.<br />
<br />
Wer möchte kann Alexa-FHEM natürlich noch weiter absichern. Es gilt aber, dass nicht jedes zusätzliche Glied in der Kette die Sicherheit sondern unter Umständen nur die Angriffsfläche erhöht. Ein falsch konfigurierter und nach aussen offener Apache (oder anderer ReverseProxy) ist unter Umständen ein größeres Risiko als Alexa-FHEM alleine.<br />
<br />
==== Absicherung per ReverseProxy ====<br />
<s>Die Kommunikation zwischen Amazon und FHEM ist wegen der Verwendung von SSL schon verschlüsselt - prinzipiell kann aber jeder von außen mit Alexa-Fhem kommunizieren. Man sollte sich deshalb im Klaren darüber sein, dass dies eine Sicherheitslücke darstellt:</s> Jeder offene Port verleitet zu Angriffen, und mit zunehmender Verbreitung von Alexa steigt auch das Risiko. Es wird deshalb empfohlen, vor den eigentlichen Alexa-Server zur Absicherung einen Apache-Webserver als ReverseProxy zu setzen. Nicht nur ist der Apache eine hervorragend stabile und seit Jahrzehnten getestete Software, sondern die Konfiguration als ReverseProxy erlaubt auch, den Zugriff auf den Alexa-Fhem-Rechner auf die Amazon-Maschinen zu beschränken.<br />
<br />
'''Achtung: Dies ist keine allgemeine Anleitung in Sachen Computersicherheit.''' Im Folgenden gehen wir davon aus, dass <br />
* Grundbegriffe wie Firewall, IP-Ports, SSL und Dynamic DNS vertraut sind<br />
* Ein Apache Webserver (idealerweise auf einer zweiten Maschine) bereits installiert ist und die Konfiguration verstanden wurde (wenn nicht: Es gibt im Netz ''tausende'' von Anleitungen dafür...)<br />
* Ein Servername von einem DynDNS-Anbieter - sagen wir ''myhome.is-my-castle.com'' - bereits von ''außen'' auf unser SmartHome zeigt.<br />
* Alexa-Fhem in einer der oben beschriebenen Basiskonfigurationen läuft, d.h. der Zugriff auf <code>https://myhome.is-my-castle.com:3000</code> ergibt, wie im Punkt [[#Alexa-Fhem_testen|Alexa-Fhem testen]] beschrieben, eine Antwort des Node.js Servers.<br />
<br />
Als erster Schritt zur Absicherung muss das ReverseProxy Modul für den Apache installiert und mit <code>a2enmod</code> aktiviert werden, hierzu sei auf [https://www.digitalocean.com/community/tutorials/how-to-use-apache-http-server-as-reverse-proxy-using-mod_proxy-extension diese Anleitung] verwiesen. Der zweite Schritt besteht darin, den SSL-Zugriff durch ein Passwort abzusichern. Dazu wird auf dem Apache-Rechner das Programm <br />
htpasswd <passwdfile> <username><br />
ausgeführt, das Programm fragt dann nach dem gewünschten Passwort. Wir nehmen im Folgenden an, dass das Passwortfile ''/etc/apache2/htpasswd'' ist, der gesetzte Username ''alexa'' lautet und das Passwort ''my_smarthome'' ist.<br />
<br />
Im dritten Schritt wird nun in das Apache-Konfigurationsfile die Weiterleitung auf den eigentlichen Alexa-Fhem-Rechner eingetragen. Dazu wählen wir, dass von außen der Standard-SSL-Port 443 benutzt werden soll, sowie als Verzeichnisname ''/alexa''. '''Achtung:''' Dieser Code soll '''nicht''' in die Default-Konfiguration des Apache-Webservers. Sondern in eine separate Datei (Dateiname z.B. "fhem"), die ins Unterverzeichnis /etc/apache2/conf.d gestellt wird.<br />
<br />
<VirtualHost *:443><br />
ServerName myhome.is-my-castle.com<br />
SSLEngine on<br />
SSLProxyEngine on<br />
SSLProxyCheckPeerCN off<br />
SSLProxyCheckPeerName off<br />
SSLCertificateKeyFile /etc/apache2/mycert/server.key<br />
SSLCertificateFile /etc/apache2/mycert/server.crt<br />
<Location /alexa><br />
AuthType Basic<br />
AuthName "Authentication Required"<br />
AuthUserFile "/etc/apache2/htpasswd"<br />
Require valid-user<br />
ProxyPass https://<hier IP-Adresse des Alexa-Fhem-Rechners>:3000/<br />
ProxyPassReverse https://<hier IP-Adresse des Alexa-Fhem-Rechners>:3000/<br />
Order deny,allow<br />
Allow from All<br />
</Location><br />
(... Hier eventuell weitere Umleitungen)<br />
</VirtualHost><br />
Nach einem Neustart des Apache-Servers, dem Schließen des Ports 3000 in der Firewall sowie dem Öffnen des Ports 443 ist der Alexa-Fhem-Rechner von außen nur noch erreichbar durch den Aufruf von <code>https://myhome.is-my-castle.com/alexa</code> und verlangt unmittelbar die Eingabe von Username und Passwort.<br />
<br />
Der vierte Schritt ist nun, den Code der AWS Lambda-Funktion an fünf Stellen zu verändern<br />
'''const PORT=443;'''<br />
const HOST='myhome.is-my-castle.com';<br />
'''const PATH='/alexa';'''<br />
'''const AUTH='alexa:my_smarthome';'''<br />
// entry<br />
exports.handler = function(event, context, callback) {<br />
console.log(`EVENT: ${event}`);<br />
console.log(`CONTEXT: ${context}`); <br />
var post_data = JSON.stringify(event);<br />
var options = {<br />
hostname: HOST,<br />
port: PORT,<br />
//family: 6,<br />
'''path: PATH,'''<br />
method: 'POST',<br />
'''auth: AUTH,'''<br />
rejectUnauthorized: false, // accept self-signed<br />
(etc., Rest des Codes wie gehabt)<br />
Natürlich muss der Zugriff getestet werden. Bei Beachtung aller dieser Schritte werden alle un-autorisierten Zugriffe von außen abgewehrt. Eine noch weiter gehende Sicherung ist möglich, dazu kann in der Serverkonfiguration der Zugriff auf die Amazon-Domains beschränkt werden. Das ganze Alexa-System ist aber noch in konstanter Weiterentwicklung, diese Domain-Namen können sich also noch ändern.<br />
<br />
== Einrichtung in der Alexa App==<br />
Nachdem die Alexa Skills angelegt wurden, müssen diese noch in der Alexa App eingerichtet werden.<br />
Dafür jeweils per Desktop-Browser auf [http://alexa.amazon.de alexa.amazon.de] anmelden, nicht die App unter iOS oder Android verwenden. Diese hat Probleme mit der OAuth Verknüpfung.<br />
<br />
=== Alexa Skill ===<br />
# Auf ''Skills'' klicken<br />[[Datei:Alexa.amazon.de-01-startseite.png|200px]]<br />
# Oben rechts ''Meine Skills'' bzw. ''Ihre Skills'' auswählen<br />[[Datei:Alexa.amazon.de-03-meine_skills.png|200px]]<br />
# In der Liste der Skills sollte das angelegte FHEM Skill angezeigt werden. Dieses anklicken<br />[[Datei:Alexa.amazon.de-02-liste_skills.png|200px]]<br />
# Oben Rechts in den Details des Skills auf ''Skill aktivieren'' klicken<br />[[Datei:Alexa.amazon.de-04-skill_details.png|200px]]<br />
# In dem neu geöffneten Fenster die Autorisierung bestätigen<br />[[Datei:Alexa.amazon.de-05-amazon_auth.png|200px]]<br />
# Anschließend sollte die Verbindung erfolgreich aufgebaut worden sein <br />[[Datei:Alexa.amazon.de-06-success.png|200px]]<br />
<br />
=== Geräte ===<br />
# Auf http://alexa.amazon.de anmelden<br />
# Auf ''Smart Home'' klicken<br />[[Datei:Alexa.amazon.de-01-startseite.png|200px]]<br />
# Anschließend den Punkt ''Geräte suchen'' anklicken<br />[[Datei:Alexa.amazon.de-07-Gerätesuche.png|200px]]<br />
# Wurde soweit alles korrekt eingerichtet, werden nun die gefundenen Geräte angezeigt.<br />
<br />
Tip: Es macht Sinn, unter ''Meine Gruppen'' Gruppen benannt nach den Räumen einzurichten. Hierdurch kann Alexa die Geräte besser auseinander halten, vor allem wenn die den gleichen Alias (z.B. "Licht") haben.<br />
<br />
== Einrichtung unter FHEM ==<br />
Im Folgenden werden exemplarisch ein paar Geräte beschrieben, die man nutzbringend mit FHEM einsetzen kann.<br />
<br />
Bei Verwendung des Custom Skills übersetzt die Kombination der Attribute ''alexaMapping'' und ''homebridgeMapping'' Sprachbefehle ("Intents") in gerätespezifische Kommandos. <br />
* Das Attribut alexaMapping wird am Alexa-Device gesetzt und dient dazu, erkannte Sprachkommandos in abstrakte Characteristiken zu überführen. Für den einfacheren SmartHome Skill hat darum das Attribut ''alexaMapping'' keine Bedeutung, sondern nur der ''genericDeviceType'' des zu steuernden Gerätes.<br />
* Das Attribut homebridgeMapping wird für beide Skills am zu steuernden Gerät gesetzt und übersetzt diese Charakteristiken in die konkreten Befehle, die das Gerät versteht. Der inhalt des Attributs wird von links nach rechts ausgewertet und ist wie folgt aufgebaut:<br />
** Das Attribut enthält eine durch Leerzeichen getrennte Liste aus Konfigurationen für jeweils eine Characteristik<br />
** Jede einzelne der Characteristik-Konfigurationen besteht aus dem Namen der Characteristik, gefolgt von "=" und einer kommaseparierten Liste von Parametern.<br />
attr <device> homebridgeMapping <Characteristic1>=<param1.1>,<param1.2>,... <Characteristic2>=<param2.1>,<param2.2>,...<br />
** Jeder Parameter besteht entweder aus<br />
*** <code><cmd>:<device>:<reading></code>, hier können nicht verwendete Elemente von links nach rechts weg gelassen werden.<br />
*** <code><name>=<value></code>, hier kann <code><value></code> entweder ein Wert oder semikolonseparierte Liste sein.<br />
*** Oder dem schlüsselwort <code>clear</code>, welches alle vorhandenen (default) Parameter dieser Characteristik löscht. <code>clear</code> kann auch an Stelle einer ganzen Characteristik-Konfiguration stehen<br />
Weiter führende Dokumentation zum homebridgeMapping findet sich unter https://forum.fhem.de/index.php/topic,48558.0.html<br />
<br />
=== Einfacher Schalter ===<br />
* Ein einfacher Schalter, der die set-Kommandos ''on'' und ''off'' kennt, kann direkt mit Alexa-Fhem gekoppelt werden <br />
* Für kompliziertere Aktionen, etwa das Übermitteln eines spezifischen Schaltbefehls an FHEM, ist die Einrichtung eines Dummies zu empfehlen. <br />
Ob Dummy oder nicht, wichtig sind die drei fett gedruckten Zeilen<br />
define Alexa.Party dummy<br />
'''attr Alexa.Party alexaName party'''<br />
'''attr Alexa.Party alexaRoom alexaroom'''<br />
'''attr Alexa.Party genericDeviceType switch'''<br />
attr Alexa.Party group AlexaGeräte<br />
attr Alexa.Party room AlexaRoom<br />
attr Alexa.Party setList on off<br />
Selbstverständlich kann man diesen Dummy mit einem notify oder DOIF abfangen, um die gewünschte Schaltaktion auszuführen. <br />
<br />
Ein Alternative zum Dummy ist das Anlegen eines readingsProxy, dem die entsprechenden Attribute gegeben werden.<br />
<br />
Weil es sich hierbei um eines der einfachen Geräte handelt, die Alexa selbst im SmartHome Skill bearbeiten kann, ist auch der zweite Schritt bei der Einrichtung in der Alexa App sinnvoll: Der Schalter wird dann im Bereich Smart Home der Alexa App erkannt. Wer ihn auch mit dem Custon Skill bedienen möchte, muss natürlich Sorge tragen, dass der Alexa-Name ''party'' bei den FHEM_Devices auftaucht und die entsprechenden weiteren Slot Types und Example Utterances in der Konfiguration des Custom Skills vorhanden sind (siehe Abschnitt [[##Custom_Skill_anlegen | Custom Skill Anlegen]]).<br />
<br />
=== Wecker ===<br />
Dieses Gerät kann man nur mit dem Custom Skill bedienen, es wird also '''nicht''' im Bereich Smart Home der Alexa App auftauchen. Wir richten einen Dummy ein, wichtig sind wieder die fett gedruckten Zeilen:<br />
define Alexa.Weckzeit dummy<br />
'''attr Alexa.Weckzeit alexaName weckzeit'''<br />
'''attr Alexa.Weckzeit alexaRoom alexaroom'''<br />
attr Alexa.Weckzeit genericDeviceType clock<br />
attr Alexa.Weckzeit group AlexaGeräte<br />
'''attr Alexa.Weckzeit homebridgeMapping Weckzeit=state,cmd=+'''<br />
attr Alexa.Weckzeit room AlexaRoom<br />
'''attr Alexa.Weckzeit setList Weckzeit:time'''<br />
Das Attribut ''genericDeviceTye'' ist nicht wichtig, weil es ein generisches Device dieser Art gar nicht gibt. Wichtig hingegen ist das Attribut ''homebridgeMapping'' <br />
<br />
Für das Gerät ''MyAlexa'', das in Abschnitt definiert wurde, muss im Attribut ''alexaMapping'' auftauchen<br />
Weckzeit=verb=stelle,valuePrefix=für;auf,values=AMAZON.TIME,valueSuffix=uhr<br />
Darüber hinaus muss der Alexa-Name ''weckzeit'' bei den FHEM_Devices auftauchen und die entsprechenden weiteren Slot Types und Example Utterances in der Konfiguration des Custom Skills vorhanden sein (siehe Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]]).<br />
<br />
Der Aufruf dieses Gerätes mit Alexa erfolgt dann z.B. mit den Sätzen<br />
<pre style="width:50%;"><br />
"Alexa, sage <Custom Skill Invocation Name>: Stelle Weckzeit auf Neunzehn Uhr Siebenundzwanzig"<br />
"Alexa, frage <Custom Skill Invocation Name> nach dem Status von Weckzeit"<br />
</pre><br />
Dabei ist natürlich der ''Custom Skill Invocation Name'' durch den Wert zu ersetzen, den man im Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]] unter Punkt 2 eingetragen hat.<br />
<br />
Zur weiteren Bearbeitung kann man jetzt mit einem DOIF Statusänderungen des Dummies abfangen und durch eine kleine Helperfunktion ins "echte" FHEM weiterleiten.<br />
define Alexa.Weckzeit.N DOIF (["Alexa.Weckzeit:.*"])({AlexaHelper("Alexa.Weckzeit","$EVENT")}) <br />
Die Helperfunktion (z.B. in 99_myUtils.pm) stellt aus der übergebenen Zeit (immer im Format dd:mm) eine sprachkompatible Nachricht $nc und einen mit den FHEM-Zeitangaben kompatiblen String $nt zusammen und reicht beide an eine Routine ''changeWakeTime'' weiter (dokumentiert in den [https://www.dpunkt.de/buecher/12387/9783960090120-smarthome-hacks.html Smart Home Hacks]).<br />
sub AlexaHelper($$){<br />
my ($name,$event)=@_;<br />
if( $name eq "Alexa.Weckzeit" ){ <br />
my ($nc,$nt);<br />
#-- volle Stunde----------------------------------------<br />
if( $event =~ /(\d+):00/ ){<br />
$nc=sprintf("%d Uhr",$1);<br />
$nt=sprintf("%02d:00:00",$1);<br />
#-- nicht volle Stunde---------------------------------<br />
}elsif( $event =~ /(\d+):(\d+)/ ){<br />
$nc=sprintf("%d Uhr %d",$1,$2);<br />
$nt=sprintf("%02d:%02d:00",$1,$2);<br />
}<br />
changeWakeTime(\'GalaxyTab.EG\',\'$nc\',\'$nt\');<br />
}<br />
}<br />
<br />
<hr><br />
<br />
=== Lichtszene ===<br />
Eine Lichtszene wird mit dem Modul LightScene angelegt. Wir gehen davon aus, dass in der Lichtszene die beiden Szenen Alle_An und Alle_Aus, sowie mindestens eine weitere Szene (hier: Sitzgruppe) definiert wurde.<br />
* Nachfolgend wird ein Beispiel beschrieben, wie man eine Lichtszene mit dem einfachen SmartHome Skill steuern kann. Die verwendeten Kommandos sind dann<br />
<pre><br />
"Alexa, schalte (die) Beleuchtung an" -> LightScene Alle_An wird ausgewählt<br />
"Alexa, schalte (die) Beleuchtungsitzgruppe an" -> LightScene Sitzgruppe wird ausgewählt<br />
...<br />
"Alexa, schalte (die) Beleuchtung aus" -> LightScene Alle_Aus wird ausgewählt<br />
</pre><br />
* Künftig wird man LightScene mit dem Custom Skill eventuell direkt steuern können - allerdings hat das einen geringeren WAF, als die Steuerung über den SmartHome Skill: Der Einschaltsatz muss dann mindestens lauten<br />
<pre><br />
"Alexa, sage <Custom Skill Invocation Name>: schalte (die) Beleuchtung an" -> LightScene Alle_An wird ausgewählt<br />
</pre><br />
Dafür wird es aber auch möglich sein direkt die SzenenNamen im gesprochenen Kommando zu verwenden und so auf die Umwege über dummys und ähnliches zu verzichten.<br />
<br />
<br />
Im ersten Schritt wird ein Dummy für die Gesamtbeleuchtung eingerichtet:<br />
define Alexa.Beleuchtung dummy <br />
attr Beleuchtung setList on off<br />
'''attr Alexa.Beleuchtung alexaName beleuchtung'''<br />
'''attr Alexa.Beleuchtung alexaRoom alexaroom'''<br />
'''attr Alexa.Beleuchtung genericDeviceType switch'''<br />
Anschließend wird für jede vorhandene Lichtszene (außer Alle_An und Alle_Aus) ein weiterer Dummy angelegt:<br />
define Alexa.Beleuchtung.Sitzgruppe dummy <br />
attr Beleuchtung setList on off<br />
'''attr Alexa.Beleuchtung.Sitzgruppe alexaName beleuchtungsitzgruppe'''<br />
'''attr Alexa.Beleuchtung.Sitzgruppe alexaRoom alexaroom'''<br />
'''attr Alexa.Beleuchtung.Sitzgruppe genericDeviceType switch''' <br />
Die eigentliche Steuerung übernimmt dann ein DOIF<br />
define Alexa.Beleuchtung.N DOIF<br />
(["Alexa.Beleuchtung.Sitzgruppe:on"])<br />
(set <devicename der Lichtszene> scene Sitzgruppe,<br />
set Alexa.Beleuchtung off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
DOELSIF<br />
... <weitere on-Events der anderen Szenen werden abgefangen><br />
DOELSEIF<br />
(["Alexa.Beleuchtung:on"])<br />
(set <devicename der Lichtszene> scene Alle_An,<br />
set Alexa.Beleuchtung.Sitzgruppe off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
DOELSEIF<br />
(["Alexa.Beleuchtung:off"])<br />
(set <devicename der Lichtszene> scene Alle_Aus,<br />
set Alexa.Beleuchtung.Sitzgruppe off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
Mit diesem DOIF wird ein Radiobutton simuliert, d.h. wie bei den Stationstasten vor Uralt-Radios sorgt die Auswahl einer Szene immer dafür, dass alle anderen Dummies ausgeschaltet werden.<br />
Natürlich kann man das auch mit einem kleinen Perl-Programm erreichen.<br />
<br />
<br />
Zwei andere Ansätze Lichtszenen zu schalten die ohne DOIF auskommen sind im Folgenden beschrieben:<br />
<br />
* Wenn es von Interesse ist die Steuerung mit einer Darstellung in FTUI zu verbinden: Statt der oben beschriebenen dummy Devices kann man readingsProxy Devices mit passenden setFn und valueFn analog zum [[Harmony#Button_f.C3.BCr_eine_bestimmte_Activity_im_Frontend_und_Homekit_.C3.BCber_readingsProxy|diesem Beispiel für harmony aktivitäten]] verwenden.<br />
<br />
* Für jede zu schaltende Szene wird ein dummy angelegt dessen homebridgeMapping direkt auf das LightScene Device zeigt:<br />
<br />
define <dummy> dummy<br />
attr <dummy> setList on off<br />
attr <dummy> genericDeviceType switch<br />
attr <dummy> homebridgeMapping On=<light scene>::state,valueOn=<szene>,cmdOn=scene+<szene>,cmdOff=scene+<szene aus><br />
<br />
Bei der zweiten Variante wird davon ausgegangen das der aktuelle status nicht abgefragt oder angezeigt werden soll. Deshalb gibt es keine direkte RadioButton Funktionalität.<br />
<br />
=== Harmony Hub ===<br />
Ein [https://forum.fhem.de/index.php/topic,60244.msg550298.html#msg550298 HowTo-Beitrag im Forum] beschreibt die Ansteuerung von Harmony-Aktionen über den Custom Skill, beispielsweise für eine Aktion ''ARD'': „Alexa, sage FHEM stelle Anlage auf ARD“.<br />
<br />
== Nutzung ==<br />
Um den Namen zu bestimmen, unter dem ein Gerät mit Alexa angesprochen wird, verwendet Alexa-Fhem mit absteigender Priorität:<br />
* das alexaName Attribut<br />
* das alias Attribut<br />
* das NAME Internal<br />
Damit Alexa ein Gerät eindeutig identifizieren kann, sollten eindeutige Gerätenamen verwendet werden, bestehed möglichst aus einem Wort und ohne Ziffern. Wenn Alexa einen Namen nicht versteht, kann man unter [http://alexa.amazon.de/spa/index.html] nachsehen was tatsächlich verstanden wurde und den Gerätenamen ggf. anpassen.<br />
<br />
=== SmartHome Skill ===<br />
Gruppen (Räume) müssen in der Alexa App konfiguriert werden. Über das API lassen sich nur der Name und die Schalteigenschaften übergeben.<br />
<br />
Nach erfolgreicher Einrichtung des SmartHome Skills sollte Alexa mit den folgenden Befehlen nutzbar sein:<br />
<pre style="width:50%;"><br />
“alexa, schalte <gerät/gruppe> ein”<br />
“alexa, schalte <gerät/gruppe> aus”<br />
“alexa, stelle <gerät/gruppe> auf <wert> prozent”<br />
“alexa, stelle <gerät/gruppe> auf <anzahl> grad”<br />
“alexa, erhöhe <gerät/gruppe> um <anzahl> prozent”<br />
“alexa, reduziere <gerät/gruppe> um <anzahl> prozent”<br />
“alexa, erhöhe <gerät/gruppe> um <anzahl> grad”<br />
“alexa, reduziere <gerät/gruppe> um <anzahl> grad”<br />
</pre><br />
<br />
=== Custom Skill ===<br />
Der Custom Skill erlaubt im Gegensatz zum SmartHome Skill eine weitreichende Konfiguration der möglichen Kommandos. Die Dokumentation ist aktuell noch über diverse Artikel im Wiki verstreut:<br />
<br />
*Das Prinzip der Kommandokonfiguration ist {{Link2Forum|Topic=60244|Message=532513|LinkText=hier}} beschrieben.<br />
*Die erste Umsetzung ist {{Link2Forum|Topic=60244|Message=540117|LinkText=hier}} beschrieben.<br />
*Mehr zu FHEM-Intents und deren Möglichkeiten gibt es {{Link2Forum|Topic=67490|Message=589378|LinkText=hier}}.<br />
*Wie man die Alexa TTS-Engine bei den Antworten auf FHEM-Intents beeinflussen kann {{Link2Forum|Topic=77421|Message=693631|LinkText=hier}}.<br />
<br />
<br />
<br />
TODO: Abfragen, Attribute (alexaMapping, alexaTypes, fhemIntents, articles, prepositions), alles hier sammeln.<br />
<br />
== Troubleshooting ==<br />
<br />
====Allgemeiner Hinweis====<br />
Besonders wichtig ist, dass man sich sehr genau an diese Anleitung hält. Ein häufiger Fehler ist, dass die einfachen Anführungszeichen in der Anleitung unter '''AWS Lambda Funktion anlegen''' Punkt 8 einfach weggelassen werden. Diese sind zwingend notwendig. Es darf auch nur der reine Hostname eingetragen werden. Also kein ''http://'' davor. Entweder eine feste IP Adresse oder den Hostnamen, um den Rechner zu erreichen, den ihr über den Port 3000 freigegeben habt. Das sollte dann so aussehen:<br />
<pre style="width:50%;"><br />
const PORT=3000;<br />
const HOST='mein.host.name';<br />
</pre><br />
<br />
====Freigabe von Port 3000====<br />
{{Randnotiz|RNTyp=Fehl|RNText=Derzeit müsst ihr über einen echten IPv4 Anschluss verfügen, damit der Amazon Lambda-Server euch erreichen kann. DS-Lite Anschlüsse wie die von <b>UnityMedia</b> z.B. funktionieren derzeit leider nicht. Eine möglicher "Workaround" wird hier beschrieben: https://forum.fhem.de/index.php/topic,60244.msg518276.html#msg518276}}<br />
<br />
Auf dem Router muss der Port 3000 Protokoll TCP freigegeben werden. D.h. von außen muss man wenn man den Port 3000 aufruft, auf dem intern laufenden node.js Alexa-Dienst zugreifen können.<br />
Je nach Router gestaltet sich das Portforwarding bzw. die Portumleitung etwas schwieriger.<br />
<br />
Bei einem Speedport Router der Telekom beispielsweise, muss der Router komplett neu gestartet werden, wenn die Portfreigabe eingerichtet wurde. <br />
<br />
Bei der Fritz!Box ist das nicht nötig, bei dieser finden die Freigabe unter ''Internet -> Freigaben -> Portfreigaben'' statt. Dort wählt man dann den Rechner aus und richtet eine neue Freigabe ein. Wichtig hierbei ist, dass man Portfreigabe auswählt und nicht MyFRITZ!-Freigabe. Bei Port von bis trägt man 3000 ein, bei Port extern ebenfalls.<br />
<br />
Um die Portweiterleitung zu testen, solltet ihr euch auch nicht im gleichen Netz befinden. Viele Router blockieren den Netzaufruf aus dem gleichen Netz. Am besten testet ihr es, wenn ihr an eurem Mobiltelefon W-LAN deaktiviert und im Browser folgende Seite aufruft: ''https://mein.hostname:3000''. Wenn ihr im Browser dann einen Quellcode von Alexa seht, funktioniert die Portumleitung.<br />
<br />
Wenn bis hier alles funktioniert und es läuft dennoch nicht rund, liegt das Problem woanders. Kommt z.B. bei der Gerätesuche kein Request rein (sichtbar auf dem Bildschirm, wenn bin/alexa gestartet wurden), kann evtl. der Lambda-Dienst falsch konfiguriert sein.<br />
<br />
====Probleme mit node.js - npm install====<br />
<br />
Falls eine Fehlermeldung auftritt, dass "npm" nicht gefunden werden kann, bitte NodeJS entsprechend der Anleitung im Homebridge-Artikel vorgehen: [[Homebridge_einrichten#NodeJS_installieren|NodeJS installieren]] sowie [[Homebridge_einrichten#Python.2C_g.2B.2B.2C_MDNS_installieren|Python, g++, MDNS installieren]], siehe auch folgenden Abschnitt.<br />
<br />
====Es kommen diverse Fehlermeldungen beim Starten von alexa-fhem und es beendet sich====<br />
Wenn man auf der Konsole angemeldet ist, den Befehl<syntaxhighlight lang="bash" style="width:50%;">node -v</syntaxhighlight>eingeben. Ist die Version niedriger als die geforderte 0.12, muss eine neuere installiert werden. Hier darf man dann im Wiki unter [[Homebridge_einrichten#NodeJS_installieren]] nachschauen. NodeJS V4 sollte hierbei schon ausreichen. Solange die node.js Version nicht passt, gar nicht groß rum experimentieren! Bitte beachtet, dass alle Voraussetzungen unter [[Alexa-Fhem#Voraussetzungen]] erfüllt sind! Keine Experimente mit Versionen die darunter liegen.<br />
<br />
====Fehlermeldung ''NAT-PMP failed: Error: timeout'' Fehler angezeigt beim Start von alexa-fhem====<br />
Wenn ihr dann alexa-fhem über die Konsole startet und bekommt folgenden Fehler: ''NAT-PMP failed: Error: timeout'', lasst euch davon nicht irritieren. Das bedeutet lediglich, dass der Port nicht automatich freigegeben wurde über uPNP. Alternativ prüft, ob die Funktion der Portfreigabe via uPNP auf eurem Router aktiviert ist.<br />
<br />
====Nach Start auf der Console beendet sich Alexa-FHEM sofort wieder====<br />
Unmittelbar nach dem Start von Alexa-FHEM werden ein paar UPNP Fehlermeldungen ausgegeben. Unmittelbar danach beendet sich Alexa-FHEM wieder. <br />
<br />
Viele scheinen ein Problem mit UPNP auf dem Raspberry Pi zu haben. Wenn dieses Problem auftritt einfach in der <code>~/.alexa/config.json</code> die folgenden Zeilen rauslöschen:<br />
<br />
<pre><br />
"nat-pmp": "10.0.1.1",<br />
"nat-upnp": true,<br />
</pre><br />
<br />
Jetzt erneut Alexa-FHEM starten. Sollte nun laufen.<br />
<br />
====Was ist zu tun, wenn alexa-fhem keine Geräte findet?====<br />
Zunächst müssen die Geräte, die angesprochen werden wollen, unter FHEM ein neues Attribut zugewiesen bekommen. Dazu das Gerät in FHEM öffnen und das Attribut ''genericDeviceType switch'' hinzufügen, wenn es ein Schalter mit der Funktiona AN/AUS sein soll. Wenn man will, kann man dem Gerät jetzt noch über das Attribut ''alias'' eine besseren Namen geben, mit dem Alexa das Gerät dann auch finden kann.<br />
Anschließend muss alexa-fhem neu gestartet werden und die definierten Geräte sollten nun gefunden werden.<br />
<br />
====Was ist zu tun, wenn Alexa zwar Geräte findet, diese aber nicht angesprochen werden können?====<br />
Zuerst die Informationen zum Datenfluss ganz oben ansehen. Dann am besten von hinten nach vorne vorgehen:<br />
* wenn nichts bei alexa-fhem ankommt: port forwarding prüfen<br />
* wenn lambda.js nichts los wird: im cloudwatch log nachsehen<br />
* wenn bei lambda.js nichts ankommt: den trigger prüfen<br />
<br />
<br />
Zunächst sollte man sich unter ''http://aws.amazon.com'' das Logfile seiner erstellten Funktion anschauen. Ist überhaupt ein Logfile vorhanden? Falls nicht, liegt es vermutlich am Trigger.<br />
Den solltet ihr überprüfen. Scheinbar kommt es hin und wieder vor, dass dieser nicht gesetzt ist. Dazu einfach auf ''Triggers'' klicken und mit ''Add trigger'' erneut einen anlegen. Hier muss, wie in der Anleitung unter '''AWS Lambda Funktion anlegen''' Punkt 7, die ''Application Id'' stehen und der Haken bei ''Enable trigger'' gesetzt sein. Dann alexa-fhem neu starten.<br />
Wenn ihr Änderungen gemacht habt und den alexa-fhem Dienst noch nicht neu gestartet habt, wäre jetzt der richtige Zeitpunkt. Fürs Debugging empfiehlt es sich, alexa-fhem in einer Konsole laufen zu lassen, um eingehende Anfragen mitverfolgen zu können.<br />
<br />
<br />
Es kann sein, dass immer noch keine Log im Cloudwatch ([http://docs.aws.amazon.com/de_de/lambda/latest/dg/monitoring-functions-logs.html]) zu sehen ist. In dem Fall hilft es, eine neue Role Policy anzulegen. <br />
* in der AWS Console [https://console.aws.amazon.com] oben links auf Services klicken, und in der Gruppe "Security, Identity & Compliance" auf IAM klicken<br />
* links auf Roles klicken<br />
* Auf dem Knopf "Create Role" klicken<br />
* AWS Services > Lambda auswählen, unten auf Next:Permissions klicken<br />
* im Filter / Policy Type, "log" eintragen (ohne quotes)<br />
* CloudWatchLogsFullAccess hacken, auf Next:Review unten klicken<br />
* Name vergeben und mit "Create role" bestätigen<br />
* Oben links auf Services klicken, und in der Gruppe "Compute", auf Lambda klicken<br />
* auf den Name der Funktion klicken<br />
* Reiter Configuration auswählen<br />
* in Existing Role, den neukreierten Role auswählen<br />
* oben auf Save (und Testen wenn gewünscht) klicken.<br />
Schon sollte eine neue Gruppe im Cloudwatch sichtbar sein. Die Suche von den Devices in Alexa wiederholen, und die Logs analysieren<br />
<br />
====Was ist zu tun, wenn sich der Alexa-Service nicht starten lässt?====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Der User in der User= Directive von alexa.service muss Ausführungsrecht auf dem alexa binary haben (x), so wie auch mind. Lesezugriff auf dem Verzeichnis nach -U Option in der ExecStart= Directive und auch auf dem WorkingDirectory }}<br />
Schaut bitte in das Unterverzeichnis [alexa-fhem (also dort, wo Ihr Alexa-FHEM instelliert habt]/bin. Die dort befindliche Datei ''alexa'' muss ausführbar sein. Also z.B. so:<br />
<syntaxhighlight lang="bash" style="width:70%;">2755327 4 -rwxr-xr-x 1 pi pi 339 Nov 26 23:20 alexa</syntaxhighlight><br />
Sollte dies nicht der Fall sein bitte mit:<br />
<syntaxhighlight lang="bash" style="width:70%;">chmod +x alexa</syntaxhighlight><br />
die Datei ausführbar machen. Sofern der User "pi" Eigentümer ist, ist kein sudo erforderlich.<br />
<br />
Eine lauffähige Konfiguration ist {{Link2Forum|Topic=71612|Message=668383|LinkText=hier}} zu sehen.<br />
<br />
Ein Fehler in der Rechtekonfiguration führt in der Regel zu folgendem Ergebnis nach <code>sudo systemctl status alexa</code>:<br />
<br />
<syntaxhighlight lang="bash"> Loaded: loaded (/etc/systemd/system/alexa.service; enabled)<br />
Active: activating (auto-restart) (Result: exit-code) since mer. 2017-09-06 02:33:23 CEST; 3s ago<br />
Process: 18332 ExecStart=/opt/fhem/alexa-fhem/bin/alexa -U /home/alexa/.alexa (code=exited, status=217/USER)<br />
Main PID: 18332 (code=exited, status=217/USER)</syntaxhighlight><br />
<br />
====Wie kann ich via Alexa-FHEM auf FHEM zugreifen, wenn der Port mit Benutzername/Kennwort geschützt ist?====<br />
<br />
Hierzu muss die Datei <code>~/.alexa/config.json</code> geöffnet werden und der Abschnitt "connections" um folgende Zeile ergänzt werden:<pre><br />
"auth": {"user": "fhem", "pass": "fhempassword"},</pre><br />
Bei Verwendung von SSL bei FHEM muss auch noch <pre><br />
"ssl": true,</pre> hinzugefügt werden<br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Sprachsteuerung]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=First_steps_in_FHEM&diff=23049First steps in FHEM2017-10-24T22:25:07Z<p>Amenomade: /* Modifying existing – modify */ New §</p>
<hr />
<div>{{Baustelle}}<br />
----<br />
----<br />
Hier entsteht die englische Fassung von [[Erste Schritte in FHEM]]...<br />
<br />
* Letzte Änderung der dt. Fassung: {{REVISIONDAY2: Erste Schritte in FHEM}}.{{REVISIONMONTH: Erste Schritte in FHEM}}.{{REVISIONYEAR: Erste Schritte in FHEM}} <br />
* Letzte Änderung der engl. Fassung: {{REVISIONDAY2: First steps in FHEM}}.{{REVISIONMONTH: First steps in FHEM}}.{{REVISIONYEAR: First steps in FHEM}}<br />
* '''Neuere''' Version ist: '''{{#ifexpr: {{REVISIONTIMESTAMP: Erste Schritte in FHEM}} > {{REVISIONTIMESTAMP: First steps in FHEM}}| dt. Version|engl. Version}}'''<br />
<br />
----<br />
----<br />
<br />
This a beginners course for those starting to work with FHEM. After you have installed FHEM on your server you may reproduce all steps without any additional smart home hardware.<br />
<br />
This guide was originally published by Ulrich Maass, who gave his permission to publish it in the FHEM wiki.<br />
<br />
Note to editors: Everybody is welcome to improve typo, grammar and style. Content changes and extentions should be discussed with the author (e. g. on associated [[Diskussion:First_steps_in_FHEM|discussion page]]).<br />
<br />
== First attempt ==<br />
To start FHEM for the first time, enter in your browsers address field:<br />
<nowiki>http://<ip-address>:8083</nowiki><br />
e. g. <nowiki>http://192.168.1.1:8083</nowiki>.<br />
<br />
The FHEM homepage is displayed:<br />
<br />
[[Datei:ErsteSchritteInFhem01.png|border]]<br />
<br />
* At the top of the screen you can see the white ''command line'' where you can enter commands.<br />
* The first menu item is the ''Save config'' button, which saves changes so that they are still available even after a restart.<br />
* Furthermore, there are already the rooms ''Unsorted'' and ''Everything'' that we will soon get to know<br />
* In the lower block there are further links, which we will also discuss later.<br />
<br />
The ''Security Check'' note indicates that you have not yet set a password for FHEM. To set up password protection, see the FHEM command reference [http://fhem.de/commandref.html#basicAuth commandref], which contains a description of all FHEM functions and modules. To suppress this message for now, enter the following in the command line: <br />
attr global motd none<br />
and confirm this change with {{Taste|Enter}}.<br />
<br />
[[Datei:ErsteSchritteInFhem02.png|border]]<br />
<br />
== Creating device - define ==<br />
The basic element of FHEM is called ''device''.Typical devices are, for example, remote controlled outlets, roller shutter motors, temperature sensors, solenoid valves etc.<br />
<br />
But other things that at first glance wouldn't appear to be a physical device are devices: for example, the user interface of FHEM itself is a device (''"FHEMWEB"''), and there are devices without physical equipment that can be used to store a variable. <br />
<br />
We will now create a very simple device, called ''dummy''.<br />
<br />
A dummy device is a special object in that it does not necessarily require a corresponding physical device (physical lamp, roller shutter, solenoid valve). In this way, you can carry out these steps without any hardware, and you can go through this general introduction without having to deal with the differences between the various hardware systems. A dummy device typically looks exactly the same in the FHEM interface as a FHEM device corresponding to a physical device in your hardware environment. <br />
<br />
First, we'll create a switch. This simulates a light switch in the wall. To do this, enter the following command in the command field:<br />
define mySwitch1 dummy<br />
<br />
"define" is the needed FHEM command, "mySwitch1" the future name of our device, "dummy" describes its type. The words "define" and "dummy" are part of FHEM'S command syntax and cannot be modified, "mySwitch1" is (more or less) arbitrary. After pressing {{Taste|Enter}} the detailed view of our new FHEM device ''mySwitch1'' is displayed.<br />
<br />
[[Datei:ErsteSchritteInFhem03.png|border]]<br />
<br />
{{Hinweis|Each device has exactly one "type". This type also defines the Perl command file (more precisely referred to as the "module") in which certain routines and properties are coded. Since our device is of type ''dummy'', FHEM knows that the routines and properties are located in module 98_dummy. pm. (The number 98 used to have a meaning, but today this is no longer the case, though it is still used for historical reasons.)}}<br />
<br />
Devices have a "state" that changes over time and that FHEM records. For example, a window is opened, a roller shutter curtain is closed and a radio socket is alive. A state does not have to contain exactly one variable (window either "open" or "closed"), a state can also be described by several variables (the state of a raspberry system, device-type sysmon, includes for example the CPU frequency, the CPU temperature, the workload and much more). <br />
<br />
The device status in FHEM consists of three blocks of values, called ''Internals'', ''Attributes'' and ''Readings''. It would be too early to go into the meaning of the three terms in detail, but the following remarks are important for the following steps:<br />
* ''Internals'' store very basic information about a device. They are rarely edited directly by the user (usually only during device setup).<br />
* ''Attributs'' control device behavior. Typically they can be changed (or even defined) by users.<br />
* ''Readings'' have, in contrast to the values of the other two blocks, a timestamp. Usually they are measured values of your device.<br />
<br />
It may be confusing for beginners that there could be Internals and Readings with the same names (e.g. STATE and state). However, Perl is case sensitive!<br />
<br />
{{Hinweis|Block '''''Internals''''' always show basic characteristics of a FHEM device:<br />
*'''''NAME:''''' device name assigned by the user<br />
*'''''TYPE:''''' device type of FHEM device, here: ''dummy''<br />
*'''''STATE:''''' device state shown in all summaries. Since there was no assignment till now it is initially '''''???'''''.}}<br />
<br />
== Creating rooms ==<br />
<br />
Let's do a step forward and arrange our devices in rooms. You may consider reasonable to put together devices physically (really) located in one room into a FHEM room. So you can find in "''bedroom''" appropriate devices like "''shutter''", "''time switch''" and "''radio set''". You may decide other assignments: put all measuring devices like thermometers, electric meters and hygrometers in one (possibly only virtually and not physically existing) room "''measuring devices''". Name of a room is arbitrary.<br />
<br />
To achieve this you have to add to all devices your room should contain an "Attribute" (see above). Name of the attribute is "room" and it should get as its value the room name. Let's try it with our room ''dummy''. Use command<br />
attr mySwitch1 room Training<br />
and finish input with {{Taste|Enter}}).<br />
<br />
With this command you have added to device ''mySwitch1'' Attribute ''room'' with value ''Training''. Again, ''attr'', ''mySwitch1'' (while referencing to an existing object's name) and ''room'' are part of FHEM's command syntax and are unalterable, ''Training'' is arbitrary.<br />
<br />
Now ''mySwitch1'' belongs to room ''Training''. Due to this assignment room appears in navigation bar on the left hand side in room's block. Try to click at room ''Training''.<br />
<br />
[[Datei:ErsteSchritteInFhem04.png]]<br />
<br />
FHEM will show all devices belonging to this room. Until now we have only one device: ''mySwitch1'' - our dummy.<br />
<br />
Beside device name always device status is on display, we still get ''???''. Clicking at name ''mySwitch1'' you will return to its detailed view.<br />
<br />
Our dummy is shown in a block with (type) label ''dummy''. You may change label as well introducing a further attribute "''group''" and assigning to it (arbitrary as well) name: groups order devices inside a room.<br />
<br />
'''Note''':<br />If you want to delete a room, you may do so removing all devices from this room. In our example of room ''Training'' you have to delete in all devices of room ''Training'' attribute room. Room ''Training'' will dispear by itself.<br />
<br />
== Creating switching commands ==<br />
Now we want to add on/off-buttons to "mySwitch1": <br />
attr mySwitch1 webCmd on:off<br />
<br />
Again we use an attribute named webCmd with values on:off, we want to add to device "mySwitch1". Instead of entering mentioned above command into command line field you may choose desired attribute (in this case: '''''webCmd''''') in lower part of detail view and enter needed values into text field right next, in this case '''''on:off'''''. Complete your input with a click on button {{Taste|attr}}.<br />
<br />
[[Datei:ErsteSchritteInFhem05.png]]<br />
<br />
Now let's click again on room ''Training''.<br />
<br />
You may see, that due to atribute added in last step in room view switch buttons for ''on'' and ''off'' have appeared.<br />
<br />
[[Datei:ErsteSchritteInFhem06.png]]<br />
<br />
Click experimentally on ''on'' and ''off'': instead of ''???'' you got so far you may find a bulb symbol showing current state.<br />
<br />
Clicking on device name ''mySwitch1'' you change back to detail view and may see in block ''Internals'' current state ''STATE'' - being shown in room view as an icon (bulb).<br />
<br />
[[Datei:ErsteSchritteInFhem07.png]]<br />
<br />
In detail view you can see a new block ''Readings'' as well.<br />
<br />
Please switch off ''mySwitch1'' once again. Pay attention to readings: next to internal ''STATE'' you may find a reading of same name (see above: Perl distinguishes lower and upper case), but equipped with a timestamp. Check reading ''state'' for updating at value and timestamp.<br />
<br />
== Event monitor ==<br />
<br />
Please, open in your browser another window with FHEM and in FHEM its '''[[Event monitor]]'''. The shortest way is to right-click on ''Event monitor'' and to select from the local menu "Open in new window". Place Windows in such a way, that you can follow event monitor and operate your "mySwitch1" at once. Using Windows 7 or newer simply activate one window and press {{Taste|Windows}}+{{Taste|Pfeil rechts}}, followed by activating second window and pressing {{Taste|Windows}}+{{Taste|Pfeil links}}.<br />
<br />
[[Datei:ErsteSchritteInFhem08.png]]<br />
<br />
Devices communicate via events. One device sends an event to FHEM and FHEM distributes this event to all devices. Devices decide whether to react or not and if yes - how. Let's have a closer look at this.<br />
<br />
Switching ''mySwitch1'' FHEM generates an event. With every actuation of the switch yet another event appears in ''Event monitor''. Please look what happens when you consecutively click twice on ''on''.<br />
<br />
Events always consist of a timestamp followed by the type of the triggering device (in this case: ''dummy''), name of the triggering device (in this case: ''mySwitch1'') as well as triggered command (in this case: ''on'' or ''off''). <br />
<br />
FHEM devices like remotes or remote-controlled wall switches, which trigger physical events, generate events in FHEM with every keypress in device itself or click on associated FHEM device. <br />
<br />
Understanding events, their structure and operation is crucial - we will frequently need them below.<br />
<br />
== Operating devices - set ==<br />
<br />
So you have learned to switch ''mySwitch1'' clicking at ''on'' or ''off''. Alternatively you can use command line entering instructions there.<br />
<br />
So please, enter in command line field <code>set mySwitch1 on</code> or <code>set mySwitch1 off</code> and confirm this with button {{Taste|Enter}}. Switching status will change accordingly as well and an Event will be triggered. By the way, we will frequently use command ''set'' in future.<br />
<br />
Preparing further tests we now create a new device '''''myLamp1''''' that we later on want to control with '''''mySwitch1'''''.<br />
define myLamp1 dummy<br />
<br />
Since ''myLamp1'' is a lamp - an actor - it won't get buttons for ''on'' or ''off''. <br />
<br />
Lamp should be located in room ''Training''. You might set this assignment via command line, like shown above. But this time we will use computer mouse...<br />
<br />
Until now ''myLamp1'' has no room assignment, so it appears in room ''Unsorted''. Change over in this room and click at name ''myLamp1'' getting so detail view.<br />
<br />
In the lower part we can set attribute assignments.<br />
<br />
Attribute ''room'' is already selected (as default). When you click at text field next to ''room'', a dialog box opens that contains all rooms FHEM knows so far. You may select one ore more checkboxes and assign this or these rooms to device. Now select only room ''Training'' and confirm selection with button {{Taste|OK}}. Selected room will be transferred into text field and it remains only to click at button {{Taste|attr}} to activate assingment. <br />
<br />
[[Datei:ErsteSchritteInFhem09.png]]<br />
<br />
Now change back to room ''Training'' and you will see both devices:<br />
<br />
[[Datei:ErsteSchritteInFhem10.png]]<br />
<br />
== Event trigger - notify ==<br />
Now we will enable FHEM to react to an event of ''mySwitch1'': Every time ''mySwitch1'' is triggering event with command ''on'' we want to switch on ''myLamp1''.<br />
<br />
For it FHEM uses a "notify". Defining syntax looks like<br />
define <NAME> notify <REGEXP> <command><br />
<br />
* Name '''<NAME>''' will help us to find this FHEM device and display its properties. This time we name the device ''n_mySwitch1_on'' - ''n_'' for marking es a notify, following by the name of triggering device and triggering command. Such a name may seem too complicated but it is very useful when working with a whole bunch ov notifies. You may name it if desired ''n1'' or ''John Doe''. Device names may consist of characters '''a-z''', '''A-Z''', '''0-9''', '''_ (underscore)''' and '''. (period)''' with a period not at first position. In perl and therefore in FHEM period has a special meaning, so avoid if possible periods in device names.<br />
*'''<REGEXP>''' stands for "regular expression" and describes a condition for raising notify. We will meet regular expressions in perl and FHEM frequently. They are used to describe syntactical characteristics of strings, e. g. whether a string contains a given word or not, whether digits are in our string and much more. When ever in FHEM a event raises for every notify runs a check for regexp matching. In our case ''mySwitch1'' raises an event with command ''on''. To "catch" this event and react to it we have notation <code>mySwitch1:on</code>. In future you will have much more moments to deal with regexps in detail. :)<br />
*'''<command>''' tells what to do. In our case: <code>set myLamp1 on</code>.<br />
<br />
So our notify looks like <br />
define n_mySwitch1_on notify mySwitch1:on set myLamp1 on<br />
<br />
After you have entered this in command field followed by {{Taste|Enter}}, you will see again detail view of the new FHEM notify device (see TYPE).<br />
<br />
[[Datei:ErsteSchritteInFhem11.png]]<br />
<br />
In block ''Internals'' you can find definition '''DEF'''. Here you see all text you have entered in event definition after the word "notify" (device type). So you can see ''<regexp>'' and ''<command>''.<br />
{{Hinweis|In Block '''''Probably associated with''''' you can find all FHEM devices associated with this notify. Devices are listed as clickable device names, so you can jump over with only one click to detail view of the respective device.}}<br />
<br />
Please assign notify to room ''Training'' (find in the lower part attribute ''room'' and choose correct room followed by a click at ''attr'').<br />
<br />
So clicking in FHEM's main menu at ''Training'' you will get our three FHEM devices.<br />
<br />
[[Datei:ErsteSchritteInFhem12.png]]<br />
<br />
{{Hinweis|Usally a notify wouldn't be assigned to a room since it shouldn't be visible for user later on. We will do it anyway for our training purposes.}}<br />
<br />
Now switch ''mySwitch1'' to ''on'' - ''myLamp1'' will be switched too. It seems that it works only at first time, but checking event monitor or looking in ''myLamp1'''s detail view at timestamp of last state change you can notice that it executes every time.<br />
<br />
To get it working for switching off too we define a second notify:<br />
define n_mySwitch1_off notify mySwitch1:off set myLamp1 off<br />
<br />
Does it work like expected?<br />
<br />
Doubtless you dislike defining an own notify for every command a device should raise. You can get it easier.<br />
<br />
Instead of <br />
define n_mySwitch1_on notify mySwitch1:on set myLamp1 on<br />
define n_mySwitch1_off notify mySwitch1:off set myLamp1 off<br />
we define<br />
define n_mySwitch1 notify mySwitch1 set myLamp1 '''$EVENT'''<br />
We see that this time regexp doesn't differ events ''on'' and ''off'' of ''mySwitch1''. With an absent regexp declaration notify raises for any event with whatsoever command. In executing set command we use FHEM variable '''$EVENT''' (follow the capital notation!). This is a placeholder for the command taken over from the raising event. Having from ''mySwitch1'' an ''on'', '''$EVENT''' will stand for value ''on'' too, accordingly for ''off'' and any other command.<br />
<br />
== Deleting or disabling devices – delete, disable ==<br />
Looking at Event Monitor you see that after activation of ''mySwitch1'' command for ''myLamp1'' is executed twice. The reason is, that any event of ''mySwitch1'' is catched by two notifies - by the "old" notify as well as by the new one. To avoid this we should get rid of the old. For that purpose we have two choices.<br />
<br />
#'''Delete''' a notify with command <code>delete <name></code>, e. g. with <code>delete n_mySwitch1_on</code>. By the way, command <code>delete</code> works with any object in FHEM. So you can delete this way "real" devices too.<br />
#'''Deactivate''' a notify, using attribute ''disable''. You can assign it in detail view of the related notify (find attribute ''disable'' in lower part and choose value ''1'' with a following click at {{Taste|attr}}), or enter in command line: <code>attr n_mySwitch1_off disable 1</code>.<br />
<br />
== Save Config ==<br />
Whenever you are satisfied with the current state of your FHEM configuration, click on '''''Save config''''' in the top left corner of the FHEM menu or enter the command <code>save</code> in the command field followed by {{Taste|Enter}}. Your configuration is now saved. If you do not do this, all changes will be lost after the next FHEM restart. FHEM therefore reminds you of unsaved changes with a red question mark next to '''''Save config'''''.<br />
<br />
== Modifying existing devices – modify ==<br />
<br />
We now create a second lamp, which should also be switched by our ''mySwitch1'' and our Notify. The new lamp is created by entering the following in the command field: <br />
define myLamp2 dummy<br />
<br />
With several clicks in the detail screen of ''myLamp2'' you can also assign them to the room Training and assign buttons for ''on'' and ''off'' via the ''webCmd'' attribute.<br />
<br />
<br />
[[Datei:ErsteSchritteInFhem13.png]]<br />
<br />
<br />
Now we adjust the Notify ''n_mySwitch1''. To do this, navigate to the Notify detail screen: Switch to the ''Training'' room and click on the name of ''n_mySwitch1''.<br />
<br />
In the detail screen there is the line ''DEF'', which we have already looked at before. If you click on the word ''DEF'', you can edit the definition of an FHEM object.<br />
<br />
{{Hinweis|The ''DEF'' field displays only the part of the definition that followed the object type, i. e. notify, as you created this notification. Here you will find the regex to which the Notify reacts, then the command to be executed after an empty space. For the sake of readability, the entire define statement is always shown below, even if it is not completely visible in the ''DEF'' field.}}<br />
<br />
We change here from <br />
define n_mySwitch1 notify mySwitch1 set myLamp1 $EVENT<br />
to<br />
define n_mySwitch1 notify mySwitch1 set myLamp1,myLamp2 $EVENT<br />
<br />
<br />
[[Datei:ErsteSchritteInFhem14.png]]<br />
<br />
<br />
To finish editing click on the ''''modify <name>'''' button, i. e. {{Taste|modify n_mySwitch1}}. If you check the details in the detail screen, you will see that the ''DEF''inition of the notify has been adjusted.<br />
<br />
[[Datei:ErsteSchritteInFhem14B.png]]<br />
<br />
Note again that in the detail screen below under ''Probably associated with'' the switched lamps will appear in the lower section of the detail screen - this will often be useful.<br />
<br />
{{Hinweis|By the way, you can use the link ''''Device specific help'''' to view the complete help text for your device type from commandref, i. e. the help text for ''notify''. This link is often helpful, especially at the beginning.}}<br />
<br />
Now you can test whether a click on ''mySwitch1'' really switches both lamps. Take a look at the events in a separate window with the Event Monitor.<br />
<br />
<br />
[[Datei:ErsteSchritteInFhem15.png]]<br />
<br />
== Switching a couple of devices at once ==<br />
== Renaming devices ==<br />
== Scheduler - at ==<br />
== Event-driven timer start - notify und at ==<br />
== How do we go on? ==<br />
<br />
[[Kategorie:HOWTOS]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=First_steps_in_FHEM&diff=23048First steps in FHEM2017-10-24T22:05:12Z<p>Amenomade: /* Creating device - define */ eng. improvment</p>
<hr />
<div>{{Baustelle}}<br />
----<br />
----<br />
Hier entsteht die englische Fassung von [[Erste Schritte in FHEM]]...<br />
<br />
* Letzte Änderung der dt. Fassung: {{REVISIONDAY2: Erste Schritte in FHEM}}.{{REVISIONMONTH: Erste Schritte in FHEM}}.{{REVISIONYEAR: Erste Schritte in FHEM}} <br />
* Letzte Änderung der engl. Fassung: {{REVISIONDAY2: First steps in FHEM}}.{{REVISIONMONTH: First steps in FHEM}}.{{REVISIONYEAR: First steps in FHEM}}<br />
* '''Neuere''' Version ist: '''{{#ifexpr: {{REVISIONTIMESTAMP: Erste Schritte in FHEM}} > {{REVISIONTIMESTAMP: First steps in FHEM}}| dt. Version|engl. Version}}'''<br />
<br />
----<br />
----<br />
<br />
This a beginners course for those starting to work with FHEM. After you have installed FHEM on your server you may reproduce all steps without any additional smart home hardware.<br />
<br />
This guide was originally published by Ulrich Maass, who gave his permission to publish it in the FHEM wiki.<br />
<br />
Note to editors: Everybody is welcome to improve typo, grammar and style. Content changes and extentions should be discussed with the author (e. g. on associated [[Diskussion:First_steps_in_FHEM|discussion page]]).<br />
<br />
== First attempt ==<br />
To start FHEM for the first time, enter in your browsers address field:<br />
<nowiki>http://<ip-address>:8083</nowiki><br />
e. g. <nowiki>http://192.168.1.1:8083</nowiki>.<br />
<br />
The FHEM homepage is displayed:<br />
<br />
[[Datei:ErsteSchritteInFhem01.png|border]]<br />
<br />
* At the top of the screen you can see the white ''command line'' where you can enter commands.<br />
* The first menu item is the ''Save config'' button, which saves changes so that they are still available even after a restart.<br />
* Furthermore, there are already the rooms ''Unsorted'' and ''Everything'' that we will soon get to know<br />
* In the lower block there are further links, which we will also discuss later.<br />
<br />
The ''Security Check'' note indicates that you have not yet set a password for FHEM. To set up password protection, see the FHEM command reference [http://fhem.de/commandref.html#basicAuth commandref], which contains a description of all FHEM functions and modules. To suppress this message for now, enter the following in the command line: <br />
attr global motd none<br />
and confirm this change with {{Taste|Enter}}.<br />
<br />
[[Datei:ErsteSchritteInFhem02.png|border]]<br />
<br />
== Creating device - define ==<br />
The basic element of FHEM is called ''device''.Typical devices are, for example, remote controlled outlets, roller shutter motors, temperature sensors, solenoid valves etc.<br />
<br />
But other things that at first glance wouldn't appear to be a physical device are devices: for example, the user interface of FHEM itself is a device (''"FHEMWEB"''), and there are devices without physical equipment that can be used to store a variable. <br />
<br />
We will now create a very simple device, called ''dummy''.<br />
<br />
A dummy device is a special object in that it does not necessarily require a corresponding physical device (physical lamp, roller shutter, solenoid valve). In this way, you can carry out these steps without any hardware, and you can go through this general introduction without having to deal with the differences between the various hardware systems. A dummy device typically looks exactly the same in the FHEM interface as a FHEM device corresponding to a physical device in your hardware environment. <br />
<br />
First, we'll create a switch. This simulates a light switch in the wall. To do this, enter the following command in the command field:<br />
define mySwitch1 dummy<br />
<br />
"define" is the needed FHEM command, "mySwitch1" the future name of our device, "dummy" describes its type. The words "define" and "dummy" are part of FHEM'S command syntax and cannot be modified, "mySwitch1" is (more or less) arbitrary. After pressing {{Taste|Enter}} the detailed view of our new FHEM device ''mySwitch1'' is displayed.<br />
<br />
[[Datei:ErsteSchritteInFhem03.png|border]]<br />
<br />
{{Hinweis|Each device has exactly one "type". This type also defines the Perl command file (more precisely referred to as the "module") in which certain routines and properties are coded. Since our device is of type ''dummy'', FHEM knows that the routines and properties are located in module 98_dummy. pm. (The number 98 used to have a meaning, but today this is no longer the case, though it is still used for historical reasons.)}}<br />
<br />
Devices have a "state" that changes over time and that FHEM records. For example, a window is opened, a roller shutter curtain is closed and a radio socket is alive. A state does not have to contain exactly one variable (window either "open" or "closed"), a state can also be described by several variables (the state of a raspberry system, device-type sysmon, includes for example the CPU frequency, the CPU temperature, the workload and much more). <br />
<br />
The device status in FHEM consists of three blocks of values, called ''Internals'', ''Attributes'' and ''Readings''. It would be too early to go into the meaning of the three terms in detail, but the following remarks are important for the following steps:<br />
* ''Internals'' store very basic information about a device. They are rarely edited directly by the user (usually only during device setup).<br />
* ''Attributs'' control device behavior. Typically they can be changed (or even defined) by users.<br />
* ''Readings'' have, in contrast to the values of the other two blocks, a timestamp. Usually they are measured values of your device.<br />
<br />
It may be confusing for beginners that there could be Internals and Readings with the same names (e.g. STATE and state). However, Perl is case sensitive!<br />
<br />
{{Hinweis|Block '''''Internals''''' always show basic characteristics of a FHEM device:<br />
*'''''NAME:''''' device name assigned by the user<br />
*'''''TYPE:''''' device type of FHEM device, here: ''dummy''<br />
*'''''STATE:''''' device state shown in all summaries. Since there was no assignment till now it is initially '''''???'''''.}}<br />
<br />
== Creating rooms ==<br />
<br />
Let's do a step forward and arrange our devices in rooms. You may consider reasonable to put together devices physically (really) located in one room into a FHEM room. So you can find in "''bedroom''" appropriate devices like "''shutter''", "''time switch''" and "''radio set''". You may decide other assignments: put all measuring devices like thermometers, electric meters and hygrometers in one (possibly only virtually and not physically existing) room "''measuring devices''". Name of a room is arbitrary.<br />
<br />
To achieve this you have to add to all devices your room should contain an "Attribute" (see above). Name of the attribute is "room" and it should get as its value the room name. Let's try it with our room ''dummy''. Use command<br />
attr mySwitch1 room Training<br />
and finish input with {{Taste|Enter}}).<br />
<br />
With this command you have added to device ''mySwitch1'' Attribute ''room'' with value ''Training''. Again, ''attr'', ''mySwitch1'' (while referencing to an existing object's name) and ''room'' are part of FHEM's command syntax and are unalterable, ''Training'' is arbitrary.<br />
<br />
Now ''mySwitch1'' belongs to room ''Training''. Due to this assignment room appears in navigation bar on the left hand side in room's block. Try to click at room ''Training''.<br />
<br />
[[Datei:ErsteSchritteInFhem04.png]]<br />
<br />
FHEM will show all devices belonging to this room. Until now we have only one device: ''mySwitch1'' - our dummy.<br />
<br />
Beside device name always device status is on display, we still get ''???''. Clicking at name ''mySwitch1'' you will return to its detailed view.<br />
<br />
Our dummy is shown in a block with (type) label ''dummy''. You may change label as well introducing a further attribute "''group''" and assigning to it (arbitrary as well) name: groups order devices inside a room.<br />
<br />
'''Note''':<br />If you want to delete a room, you may do so removing all devices from this room. In our example of room ''Training'' you have to delete in all devices of room ''Training'' attribute room. Room ''Training'' will dispear by itself.<br />
<br />
== Creating switching commands ==<br />
Now we want to add on/off-buttons to "mySwitch1": <br />
attr mySwitch1 webCmd on:off<br />
<br />
Again we use an attribute named webCmd with values on:off, we want to add to device "mySwitch1". Instead of entering mentioned above command into command line field you may choose desired attribute (in this case: '''''webCmd''''') in lower part of detail view and enter needed values into text field right next, in this case '''''on:off'''''. Complete your input with a click on button {{Taste|attr}}.<br />
<br />
[[Datei:ErsteSchritteInFhem05.png]]<br />
<br />
Now let's click again on room ''Training''.<br />
<br />
You may see, that due to atribute added in last step in room view switch buttons for ''on'' and ''off'' have appeared.<br />
<br />
[[Datei:ErsteSchritteInFhem06.png]]<br />
<br />
Click experimentally on ''on'' and ''off'': instead of ''???'' you got so far you may find a bulb symbol showing current state.<br />
<br />
Clicking on device name ''mySwitch1'' you change back to detail view and may see in block ''Internals'' current state ''STATE'' - being shown in room view as an icon (bulb).<br />
<br />
[[Datei:ErsteSchritteInFhem07.png]]<br />
<br />
In detail view you can see a new block ''Readings'' as well.<br />
<br />
Please switch off ''mySwitch1'' once again. Pay attention to readings: next to internal ''STATE'' you may find a reading of same name (see above: Perl distinguishes lower and upper case), but equipped with a timestamp. Check reading ''state'' for updating at value and timestamp.<br />
<br />
== Event monitor ==<br />
<br />
Please, open in your browser another window with FHEM and in FHEM its '''[[Event monitor]]'''. The shortest way is to right-click on ''Event monitor'' and to select from the local menu "Open in new window". Place Windows in such a way, that you can follow event monitor and operate your "mySwitch1" at once. Using Windows 7 or newer simply activate one window and press {{Taste|Windows}}+{{Taste|Pfeil rechts}}, followed by activating second window and pressing {{Taste|Windows}}+{{Taste|Pfeil links}}.<br />
<br />
[[Datei:ErsteSchritteInFhem08.png]]<br />
<br />
Devices communicate via events. One device sends an event to FHEM and FHEM distributes this event to all devices. Devices decide whether to react or not and if yes - how. Let's have a closer look at this.<br />
<br />
Switching ''mySwitch1'' FHEM generates an event. With every actuation of the switch yet another event appears in ''Event monitor''. Please look what happens when you consecutively click twice on ''on''.<br />
<br />
Events always consist of a timestamp followed by the type of the triggering device (in this case: ''dummy''), name of the triggering device (in this case: ''mySwitch1'') as well as triggered command (in this case: ''on'' or ''off''). <br />
<br />
FHEM devices like remotes or remote-controlled wall switches, which trigger physical events, generate events in FHEM with every keypress in device itself or click on associated FHEM device. <br />
<br />
Understanding events, their structure and operation is crucial - we will frequently need them below.<br />
<br />
== Operating devices - set ==<br />
<br />
So you have learned to switch ''mySwitch1'' clicking at ''on'' or ''off''. Alternatively you can use command line entering instructions there.<br />
<br />
So please, enter in command line field <code>set mySwitch1 on</code> or <code>set mySwitch1 off</code> and confirm this with button {{Taste|Enter}}. Switching status will change accordingly as well and an Event will be triggered. By the way, we will frequently use command ''set'' in future.<br />
<br />
Preparing further tests we now create a new device '''''myLamp1''''' that we later on want to control with '''''mySwitch1'''''.<br />
define myLamp1 dummy<br />
<br />
Since ''myLamp1'' is a lamp - an actor - it won't get buttons for ''on'' or ''off''. <br />
<br />
Lamp should be located in room ''Training''. You might set this assignment via command line, like shown above. But this time we will use computer mouse...<br />
<br />
Until now ''myLamp1'' has no room assignment, so it appears in room ''Unsorted''. Change over in this room and click at name ''myLamp1'' getting so detail view.<br />
<br />
In the lower part we can set attribute assignments.<br />
<br />
Attribute ''room'' is already selected (as default). When you click at text field next to ''room'', a dialog box opens that contains all rooms FHEM knows so far. You may select one ore more checkboxes and assign this or these rooms to device. Now select only room ''Training'' and confirm selection with button {{Taste|OK}}. Selected room will be transferred into text field and it remains only to click at button {{Taste|attr}} to activate assingment. <br />
<br />
[[Datei:ErsteSchritteInFhem09.png]]<br />
<br />
Now change back to room ''Training'' and you will see both devices:<br />
<br />
[[Datei:ErsteSchritteInFhem10.png]]<br />
<br />
== Event trigger - notify ==<br />
Now we will enable FHEM to react to an event of ''mySwitch1'': Every time ''mySwitch1'' is triggering event with command ''on'' we want to switch on ''myLamp1''.<br />
<br />
For it FHEM uses a "notify". Defining syntax looks like<br />
define <NAME> notify <REGEXP> <command><br />
<br />
* Name '''<NAME>''' will help us to find this FHEM device and display its properties. This time we name the device ''n_mySwitch1_on'' - ''n_'' for marking es a notify, following by the name of triggering device and triggering command. Such a name may seem too complicated but it is very useful when working with a whole bunch ov notifies. You may name it if desired ''n1'' or ''John Doe''. Device names may consist of characters '''a-z''', '''A-Z''', '''0-9''', '''_ (underscore)''' and '''. (period)''' with a period not at first position. In perl and therefore in FHEM period has a special meaning, so avoid if possible periods in device names.<br />
*'''<REGEXP>''' stands for "regular expression" and describes a condition for raising notify. We will meet regular expressions in perl and FHEM frequently. They are used to describe syntactical characteristics of strings, e. g. whether a string contains a given word or not, whether digits are in our string and much more. When ever in FHEM a event raises for every notify runs a check for regexp matching. In our case ''mySwitch1'' raises an event with command ''on''. To "catch" this event and react to it we have notation <code>mySwitch1:on</code>. In future you will have much more moments to deal with regexps in detail. :)<br />
*'''<command>''' tells what to do. In our case: <code>set myLamp1 on</code>.<br />
<br />
So our notify looks like <br />
define n_mySwitch1_on notify mySwitch1:on set myLamp1 on<br />
<br />
After you have entered this in command field followed by {{Taste|Enter}}, you will see again detail view of the new FHEM notify device (see TYPE).<br />
<br />
[[Datei:ErsteSchritteInFhem11.png]]<br />
<br />
In block ''Internals'' you can find definition '''DEF'''. Here you see all text you have entered in event definition after the word "notify" (device type). So you can see ''<regexp>'' and ''<command>''.<br />
{{Hinweis|In Block '''''Probably associated with''''' you can find all FHEM devices associated with this notify. Devices are listed as clickable device names, so you can jump over with only one click to detail view of the respective device.}}<br />
<br />
Please assign notify to room ''Training'' (find in the lower part attribute ''room'' and choose correct room followed by a click at ''attr'').<br />
<br />
So clicking in FHEM's main menu at ''Training'' you will get our three FHEM devices.<br />
<br />
[[Datei:ErsteSchritteInFhem12.png]]<br />
<br />
{{Hinweis|Usally a notify wouldn't be assigned to a room since it shouldn't be visible for user later on. We will do it anyway for our training purposes.}}<br />
<br />
Now switch ''mySwitch1'' to ''on'' - ''myLamp1'' will be switched too. It seems that it works only at first time, but checking event monitor or looking in ''myLamp1'''s detail view at timestamp of last state change you can notice that it executes every time.<br />
<br />
To get it working for switching off too we define a second notify:<br />
define n_mySwitch1_off notify mySwitch1:off set myLamp1 off<br />
<br />
Does it work like expected?<br />
<br />
Doubtless you dislike defining an own notify for every command a device should raise. You can get it easier.<br />
<br />
Instead of <br />
define n_mySwitch1_on notify mySwitch1:on set myLamp1 on<br />
define n_mySwitch1_off notify mySwitch1:off set myLamp1 off<br />
we define<br />
define n_mySwitch1 notify mySwitch1 set myLamp1 '''$EVENT'''<br />
We see that this time regexp doesn't differ events ''on'' and ''off'' of ''mySwitch1''. With an absent regexp declaration notify raises for any event with whatsoever command. In executing set command we use FHEM variable '''$EVENT''' (follow the capital notation!). This is a placeholder for the command taken over from the raising event. Having from ''mySwitch1'' an ''on'', '''$EVENT''' will stand for value ''on'' too, accordingly for ''off'' and any other command.<br />
<br />
== Deleting or disabling devices – delete, disable ==<br />
Looking at Event Monitor you see that after activation of ''mySwitch1'' command for ''myLamp1'' is executed twice. The reason is, that any event of ''mySwitch1'' is catched by two notifies - by the "old" notify as well as by the new one. To avoid this we should get rid of the old. For that purpose we have two choices.<br />
<br />
#'''Delete''' a notify with command <code>delete <name></code>, e. g. with <code>delete n_mySwitch1_on</code>. By the way, command <code>delete</code> works with any object in FHEM. So you can delete this way "real" devices too.<br />
#'''Deactivate''' a notify, using attribute ''disable''. You can assign it in detail view of the related notify (find attribute ''disable'' in lower part and choose value ''1'' with a following click at {{Taste|attr}}), or enter in command line: <code>attr n_mySwitch1_off disable 1</code>.<br />
<br />
== Save Config ==<br />
Whenever you are satisfied with the current state of your FHEM configuration, click on '''''Save config''''' in the top left corner of the FHEM menu or enter the command <code>save</code> in the command field followed by {{Taste|Enter}}. Your configuration is now saved. If you do not do this, all changes will be lost after the next FHEM restart. FHEM therefore reminds you of unsaved changes with a red question mark next to '''''Save config'''''.<br />
<br />
== Modifying existing – modify ==<br />
== Switching a couple of devices at once ==<br />
== Renaming devices ==<br />
== Scheduler - at ==<br />
== Event-driven timer start - notify und at ==<br />
== How do we go on? ==<br />
<br />
[[Kategorie:HOWTOS]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=First_steps_in_FHEM&diff=23047First steps in FHEM2017-10-24T21:44:43Z<p>Amenomade: /* Creating device - define */ eng. improvment</p>
<hr />
<div>{{Baustelle}}<br />
----<br />
----<br />
Hier entsteht die englische Fassung von [[Erste Schritte in FHEM]]...<br />
<br />
* Letzte Änderung der dt. Fassung: {{REVISIONDAY2: Erste Schritte in FHEM}}.{{REVISIONMONTH: Erste Schritte in FHEM}}.{{REVISIONYEAR: Erste Schritte in FHEM}} <br />
* Letzte Änderung der engl. Fassung: {{REVISIONDAY2: First steps in FHEM}}.{{REVISIONMONTH: First steps in FHEM}}.{{REVISIONYEAR: First steps in FHEM}}<br />
* '''Neuere''' Version ist: '''{{#ifexpr: {{REVISIONTIMESTAMP: Erste Schritte in FHEM}} > {{REVISIONTIMESTAMP: First steps in FHEM}}| dt. Version|engl. Version}}'''<br />
<br />
----<br />
----<br />
<br />
This a beginners course for those starting to work with FHEM. After you have installed FHEM on your server you may reproduce all steps without any additional smart home hardware.<br />
<br />
This guide was originally published by Ulrich Maass, who gave his permission to publish it in the FHEM wiki.<br />
<br />
Note to editors: Everybody is welcome to improve typo, grammar and style. Content changes and extentions should be discussed with the author (e. g. on associated [[Diskussion:First_steps_in_FHEM|discussion page]]).<br />
<br />
== First attempt ==<br />
To start FHEM for the first time, enter in your browsers address field:<br />
<nowiki>http://<ip-address>:8083</nowiki><br />
e. g. <nowiki>http://192.168.1.1:8083</nowiki>.<br />
<br />
The FHEM homepage is displayed:<br />
<br />
[[Datei:ErsteSchritteInFhem01.png|border]]<br />
<br />
* At the top of the screen you can see the white ''command line'' where you can enter commands.<br />
* The first menu item is the ''Save config'' button, which saves changes so that they are still available even after a restart.<br />
* Furthermore, there are already the rooms ''Unsorted'' and ''Everything'' that we will soon get to know<br />
* In the lower block there are further links, which we will also discuss later.<br />
<br />
The ''Security Check'' note indicates that you have not yet set a password for FHEM. To set up password protection, see the FHEM command reference [http://fhem.de/commandref.html#basicAuth commandref], which contains a description of all FHEM functions and modules. To suppress this message for now, enter the following in the command line: <br />
attr global motd none<br />
and confirm this change with {{Taste|Enter}}.<br />
<br />
[[Datei:ErsteSchritteInFhem02.png|border]]<br />
<br />
== Creating device - define ==<br />
The basic element of FHEM is called ''device''.Typical devices are, for example, remote controlled outlets, roller shutter motors, temperature sensors, solenoid valves etc.<br />
<br />
But other things that at first glance wouldn't appear to be a physical device are devices: for example, the user interface of FHEM itself is a device (''"FHEMWEB"''), and there are devices without physical equipment that can be used to store a variable. <br />
<br />
We will now create a very simple device, called ''dummy''.<br />
<br />
The dummy devices is a special object in that it does not necessarily require a corresponding physical device (physical lamp, roller shutter, solenoid valve). In this way, you can carry out these steps without any hardware, and you can go through this general introduction without having to deal with the differences between the various hardware systems. A dummy device typically looks exactly the same in the FHEM interface as an FHEM device corresponding to a physical device in your hardware environment. <br />
<br />
First, we'll create a switch. This simulates a light switch in the wall. To do this, enter the following command in the command field:<br />
define mySwitch1 dummy<br />
<br />
"define" is the needed FHEM command, "mySwitch1" the future name of our device, "dummy" describes its type. The words "define" and "dummy" are part of FHEM'S command syntax and cannot be modified, "mySwitch1" is (more or less) arbitrary. After pressing {{Taste|Enter}} the detailed view of our new FHEM device ''mySwitch1'' appears.<br />
<br />
[[Datei:ErsteSchritteInFhem03.png|border]]<br />
<br />
{{Hinweis|Each device has exactly one "type". This type also defines the Perl command file (more precisely referred to as the "module") in which certain routines and properties are coded. Since our device is of type ''dummy'', FHEM knows that the routines and properties are located in module 98_dummy. pm. (The number 98 used to have a meaning, but today this is no longer the case, though it is still used for historical reasons.)}}<br />
<br />
Devices have a "state", changing in time and recorded by FHEM. E.g., some window is open, a shutter is closed, an outlet is under voltage. A state not necessary consists of exactly one value (window: "open" or "closed"), state can be described by a bunch of values (state of a Raspberry system - device type ''sysmon'' - contains CPU frequency, CPU temperature, load and much more).<br />
<br />
Device status in FHEM consists of overall three blocks of values, called ''Internals'', ''Attributes'' and ''Readings''. It's early days yet to discuss in-depth meaning of these terms, but some remarks are important for our next steps:<br />
* ''Internals'' store very basic informationen about a device. Only in rare cases users will edit directly internals (mostly during define step).<br />
* ''Attributs'' control device behavior. Typically they can be changed (or even defined) by users.<br />
* ''Readings'' have in contrast to the values of the other two blocks a timestamp. Usually they are measured values of your device.<br />
<br />
It may be confusing for beginners that there can be Internals and Readings of equal names (e.g. STATE and state). Though Perl distinguishes lower and upper case.<br />
<br />
{{Hinweis|Block '''''Internals''''' always shows basic characteristics of a FHEM device:<br />
*'''''NAME:''''' device name assigned by the user<br />
*'''''TYPE:''''' device type of FHEM device, here: ''dummy''<br />
*'''''STATE:''''' device state shown in all summaries. Since there was no assignment till now it is initially '''''???'''''.}}<br />
<br />
== Creating rooms ==<br />
<br />
Let's do a step forward and arrange our devices in rooms. You may consider reasonable to put together devices physically (really) located in one room into a FHEM room. So you can find in "''bedroom''" appropriate devices like "''shutter''", "''time switch''" and "''radio set''". You may decide other assignments: put all measuring devices like thermometers, electric meters and hygrometers in one (possibly only virtually and not physically existing) room "''measuring devices''". Name of a room is arbitrary.<br />
<br />
To achieve this you have to add to all devices your room should contain an "Attribute" (see above). Name of the attribute is "room" and it should get as its value the room name. Let's try it with our room ''dummy''. Use command<br />
attr mySwitch1 room Training<br />
and finish input with {{Taste|Enter}}).<br />
<br />
With this command you have added to device ''mySwitch1'' Attribute ''room'' with value ''Training''. Again, ''attr'', ''mySwitch1'' (while referencing to an existing object's name) and ''room'' are part of FHEM's command syntax and are unalterable, ''Training'' is arbitrary.<br />
<br />
Now ''mySwitch1'' belongs to room ''Training''. Due to this assignment room appears in navigation bar on the left hand side in room's block. Try to click at room ''Training''.<br />
<br />
[[Datei:ErsteSchritteInFhem04.png]]<br />
<br />
FHEM will show all devices belonging to this room. Until now we have only one device: ''mySwitch1'' - our dummy.<br />
<br />
Beside device name always device status is on display, we still get ''???''. Clicking at name ''mySwitch1'' you will return to its detailed view.<br />
<br />
Our dummy is shown in a block with (type) label ''dummy''. You may change label as well introducing a further attribute "''group''" and assigning to it (arbitrary as well) name: groups order devices inside a room.<br />
<br />
'''Note''':<br />If you want to delete a room, you may do so removing all devices from this room. In our example of room ''Training'' you have to delete in all devices of room ''Training'' attribute room. Room ''Training'' will dispear by itself.<br />
<br />
== Creating switching commands ==<br />
Now we want to add on/off-buttons to "mySwitch1": <br />
attr mySwitch1 webCmd on:off<br />
<br />
Again we use an attribute named webCmd with values on:off, we want to add to device "mySwitch1". Instead of entering mentioned above command into command line field you may choose desired attribute (in this case: '''''webCmd''''') in lower part of detail view and enter needed values into text field right next, in this case '''''on:off'''''. Complete your input with a click on button {{Taste|attr}}.<br />
<br />
[[Datei:ErsteSchritteInFhem05.png]]<br />
<br />
Now let's click again on room ''Training''.<br />
<br />
You may see, that due to atribute added in last step in room view switch buttons for ''on'' and ''off'' have appeared.<br />
<br />
[[Datei:ErsteSchritteInFhem06.png]]<br />
<br />
Click experimentally on ''on'' and ''off'': instead of ''???'' you got so far you may find a bulb symbol showing current state.<br />
<br />
Clicking on device name ''mySwitch1'' you change back to detail view and may see in block ''Internals'' current state ''STATE'' - being shown in room view as an icon (bulb).<br />
<br />
[[Datei:ErsteSchritteInFhem07.png]]<br />
<br />
In detail view you can see a new block ''Readings'' as well.<br />
<br />
Please switch off ''mySwitch1'' once again. Pay attention to readings: next to internal ''STATE'' you may find a reading of same name (see above: Perl distinguishes lower and upper case), but equipped with a timestamp. Check reading ''state'' for updating at value and timestamp.<br />
<br />
== Event monitor ==<br />
<br />
Please, open in your browser another window with FHEM and in FHEM its '''[[Event monitor]]'''. The shortest way is to right-click on ''Event monitor'' and to select from the local menu "Open in new window". Place Windows in such a way, that you can follow event monitor and operate your "mySwitch1" at once. Using Windows 7 or newer simply activate one window and press {{Taste|Windows}}+{{Taste|Pfeil rechts}}, followed by activating second window and pressing {{Taste|Windows}}+{{Taste|Pfeil links}}.<br />
<br />
[[Datei:ErsteSchritteInFhem08.png]]<br />
<br />
Devices communicate via events. One device sends an event to FHEM and FHEM distributes this event to all devices. Devices decide whether to react or not and if yes - how. Let's have a closer look at this.<br />
<br />
Switching ''mySwitch1'' FHEM generates an event. With every actuation of the switch yet another event appears in ''Event monitor''. Please look what happens when you consecutively click twice on ''on''.<br />
<br />
Events always consist of a timestamp followed by the type of the triggering device (in this case: ''dummy''), name of the triggering device (in this case: ''mySwitch1'') as well as triggered command (in this case: ''on'' or ''off''). <br />
<br />
FHEM devices like remotes or remote-controlled wall switches, which trigger physical events, generate events in FHEM with every keypress in device itself or click on associated FHEM device. <br />
<br />
Understanding events, their structure and operation is crucial - we will frequently need them below.<br />
<br />
== Operating devices - set ==<br />
<br />
So you have learned to switch ''mySwitch1'' clicking at ''on'' or ''off''. Alternatively you can use command line entering instructions there.<br />
<br />
So please, enter in command line field <code>set mySwitch1 on</code> or <code>set mySwitch1 off</code> and confirm this with button {{Taste|Enter}}. Switching status will change accordingly as well and an Event will be triggered. By the way, we will frequently use command ''set'' in future.<br />
<br />
Preparing further tests we now create a new device '''''myLamp1''''' that we later on want to control with '''''mySwitch1'''''.<br />
define myLamp1 dummy<br />
<br />
Since ''myLamp1'' is a lamp - an actor - it won't get buttons for ''on'' or ''off''. <br />
<br />
Lamp should be located in room ''Training''. You might set this assignment via command line, like shown above. But this time we will use computer mouse...<br />
<br />
Until now ''myLamp1'' has no room assignment, so it appears in room ''Unsorted''. Change over in this room and click at name ''myLamp1'' getting so detail view.<br />
<br />
In the lower part we can set attribute assignments.<br />
<br />
Attribute ''room'' is already selected (as default). When you click at text field next to ''room'', a dialog box opens that contains all rooms FHEM knows so far. You may select one ore more checkboxes and assign this or these rooms to device. Now select only room ''Training'' and confirm selection with button {{Taste|OK}}. Selected room will be transferred into text field and it remains only to click at button {{Taste|attr}} to activate assingment. <br />
<br />
[[Datei:ErsteSchritteInFhem09.png]]<br />
<br />
Now change back to room ''Training'' and you will see both devices:<br />
<br />
[[Datei:ErsteSchritteInFhem10.png]]<br />
<br />
== Event trigger - notify ==<br />
Now we will enable FHEM to react to an event of ''mySwitch1'': Every time ''mySwitch1'' is triggering event with command ''on'' we want to switch on ''myLamp1''.<br />
<br />
For it FHEM uses a "notify". Defining syntax looks like<br />
define <NAME> notify <REGEXP> <command><br />
<br />
* Name '''<NAME>''' will help us to find this FHEM device and display its properties. This time we name the device ''n_mySwitch1_on'' - ''n_'' for marking es a notify, following by the name of triggering device and triggering command. Such a name may seem too complicated but it is very useful when working with a whole bunch ov notifies. You may name it if desired ''n1'' or ''John Doe''. Device names may consist of characters '''a-z''', '''A-Z''', '''0-9''', '''_ (underscore)''' and '''. (period)''' with a period not at first position. In perl and therefore in FHEM period has a special meaning, so avoid if possible periods in device names.<br />
*'''<REGEXP>''' stands for "regular expression" and describes a condition for raising notify. We will meet regular expressions in perl and FHEM frequently. They are used to describe syntactical characteristics of strings, e. g. whether a string contains a given word or not, whether digits are in our string and much more. When ever in FHEM a event raises for every notify runs a check for regexp matching. In our case ''mySwitch1'' raises an event with command ''on''. To "catch" this event and react to it we have notation <code>mySwitch1:on</code>. In future you will have much more moments to deal with regexps in detail. :)<br />
*'''<command>''' tells what to do. In our case: <code>set myLamp1 on</code>.<br />
<br />
So our notify looks like <br />
define n_mySwitch1_on notify mySwitch1:on set myLamp1 on<br />
<br />
After you have entered this in command field followed by {{Taste|Enter}}, you will see again detail view of the new FHEM notify device (see TYPE).<br />
<br />
[[Datei:ErsteSchritteInFhem11.png]]<br />
<br />
In block ''Internals'' you can find definition '''DEF'''. Here you see all text you have entered in event definition after the word "notify" (device type). So you can see ''<regexp>'' and ''<command>''.<br />
{{Hinweis|In Block '''''Probably associated with''''' you can find all FHEM devices associated with this notify. Devices are listed as clickable device names, so you can jump over with only one click to detail view of the respective device.}}<br />
<br />
Please assign notify to room ''Training'' (find in the lower part attribute ''room'' and choose correct room followed by a click at ''attr'').<br />
<br />
So clicking in FHEM's main menu at ''Training'' you will get our three FHEM devices.<br />
<br />
[[Datei:ErsteSchritteInFhem12.png]]<br />
<br />
{{Hinweis|Usally a notify wouldn't be assigned to a room since it shouldn't be visible for user later on. We will do it anyway for our training purposes.}}<br />
<br />
Now switch ''mySwitch1'' to ''on'' - ''myLamp1'' will be switched too. It seems that it works only at first time, but checking event monitor or looking in ''myLamp1'''s detail view at timestamp of last state change you can notice that it executes every time.<br />
<br />
To get it working for switching off too we define a second notify:<br />
define n_mySwitch1_off notify mySwitch1:off set myLamp1 off<br />
<br />
Does it work like expected?<br />
<br />
Doubtless you dislike defining an own notify for every command a device should raise. You can get it easier.<br />
<br />
Instead of <br />
define n_mySwitch1_on notify mySwitch1:on set myLamp1 on<br />
define n_mySwitch1_off notify mySwitch1:off set myLamp1 off<br />
we define<br />
define n_mySwitch1 notify mySwitch1 set myLamp1 '''$EVENT'''<br />
We see that this time regexp doesn't differ events ''on'' and ''off'' of ''mySwitch1''. With an absent regexp declaration notify raises for any event with whatsoever command. In executing set command we use FHEM variable '''$EVENT''' (follow the capital notation!). This is a placeholder for the command taken over from the raising event. Having from ''mySwitch1'' an ''on'', '''$EVENT''' will stand for value ''on'' too, accordingly for ''off'' and any other command.<br />
<br />
== Deleting or disabling devices – delete, disable ==<br />
Looking at Event Monitor you see that after activation of ''mySwitch1'' command for ''myLamp1'' is executed twice. The reason is, that any event of ''mySwitch1'' is catched by two notifies - by the "old" notify as well as by the new one. To avoid this we should get rid of the old. For that purpose we have two choices.<br />
<br />
#'''Delete''' a notify with command <code>delete <name></code>, e. g. with <code>delete n_mySwitch1_on</code>. By the way, command <code>delete</code> works with any object in FHEM. So you can delete this way "real" devices too.<br />
#'''Deactivate''' a notify, using attribute ''disable''. You can assign it in detail view of the related notify (find attribute ''disable'' in lower part and choose value ''1'' with a following click at {{Taste|attr}}), or enter in command line: <code>attr n_mySwitch1_off disable 1</code>.<br />
<br />
== Save Config ==<br />
Whenever you are satisfied with the current state of your FHEM configuration, click on '''''Save config''''' in the top left corner of the FHEM menu or enter the command <code>save</code> in the command field followed by {{Taste|Enter}}. Your configuration is now saved. If you do not do this, all changes will be lost after the next FHEM restart. FHEM therefore reminds you of unsaved changes with a red question mark next to '''''Save config'''''.<br />
<br />
== Modifying existing – modify ==<br />
== Switching a couple of devices at once ==<br />
== Renaming devices ==<br />
== Scheduler - at ==<br />
== Event-driven timer start - notify und at ==<br />
== How do we go on? ==<br />
<br />
[[Kategorie:HOWTOS]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=First_steps_in_FHEM&diff=23046First steps in FHEM2017-10-24T21:26:35Z<p>Amenomade: eng. improvement</p>
<hr />
<div>{{Baustelle}}<br />
----<br />
----<br />
Hier entsteht die englische Fassung von [[Erste Schritte in FHEM]]...<br />
<br />
* Letzte Änderung der dt. Fassung: {{REVISIONDAY2: Erste Schritte in FHEM}}.{{REVISIONMONTH: Erste Schritte in FHEM}}.{{REVISIONYEAR: Erste Schritte in FHEM}} <br />
* Letzte Änderung der engl. Fassung: {{REVISIONDAY2: First steps in FHEM}}.{{REVISIONMONTH: First steps in FHEM}}.{{REVISIONYEAR: First steps in FHEM}}<br />
* '''Neuere''' Version ist: '''{{#ifexpr: {{REVISIONTIMESTAMP: Erste Schritte in FHEM}} > {{REVISIONTIMESTAMP: First steps in FHEM}}| dt. Version|engl. Version}}'''<br />
<br />
----<br />
----<br />
<br />
This a beginners course for those starting to work with FHEM. After you have installed FHEM on your server you may reproduce all steps without any additional smart home hardware.<br />
<br />
This guide was originally published by Ulrich Maass, who gave his permission to publish it in the FHEM wiki.<br />
<br />
Note to editors: Everybody is welcome to improve typo, grammar and style. Content changes and extentions should be discussed with the author (e. g. on associated [[Diskussion:First_steps_in_FHEM|discussion page]]).<br />
<br />
== First attempt ==<br />
To start FHEM for the first time, enter in your browsers address field:<br />
<nowiki>http://<ip-address>:8083</nowiki><br />
e. g. <nowiki>http://192.168.1.1:8083</nowiki>.<br />
<br />
The FHEM homepage is displayed:<br />
<br />
[[Datei:ErsteSchritteInFhem01.png|border]]<br />
<br />
* At the top of the screen you can see the white ''command line'' where you can enter commands.<br />
* The first menu item is the ''Save config'' button, which saves changes so that they are still available even after a restart.<br />
* Furthermore, there are already the rooms ''Unsorted'' and ''Everything'' that we will soon get to know<br />
* In the lower block there are further links, which we will also discuss later.<br />
<br />
The ''Security Check'' note indicates that you have not yet set a password for FHEM. To set up password protection, see the FHEM command reference [http://fhem.de/commandref.html#basicAuth commandref], which contains a description of all FHEM functions and modules. To suppress this message for now, enter the following in the command line: <br />
attr global motd none<br />
and confirm this change with {{Taste|Enter}}.<br />
<br />
[[Datei:ErsteSchritteInFhem02.png|border]]<br />
<br />
== Creating device - define ==<br />
The main component type in FHEM is called ''device''.Typical devices are e.g. remote controlled outlets, roller shutter motors, temperature sensors, solenoid valves etc.<br />
<br />
But there are other kinds of devices too, where at first view you wouldn't expect it: FHEM's user interface (''"FHEMWEB"'') is a device, there are devices without a physical equipment used to store a variable's value. <br />
<br />
Now we will create a very simple device, called ''dummy''.<br />
<br />
A device of type ''dummy'' is a special object, inasmuch as it nonessential needs corresponding physical equipment (physical lamp, roller shutter, solenoid valve). So we can proceed in this guide without a real hardware system, or rather we don't need to concider differences between differrent hardware. A dummy device is generally represented on FHEM's user interface like a FHEM device with a physical equivalent. <br />
<br />
Lets begin with a switch. It is designed to simulate a light switch on the wall. Please, enter command in command field:<br />
define mySwitch1 dummy<br />
<br />
"define" is the needed FHEM command, "mySwitch1" the future name of our device, "dummy" describes its type. Words "define" and "dummy" are part of FHEM'S command syntax and are unalterable, "mySwitch1" is (more or less) arbitrary. After pressing button {{Taste|Enter}} detail view of our new FHEM device ''mySwitch1'' appears.<br />
<br />
[[Datei:ErsteSchritteInFhem03.png|border]]<br />
<br />
{{Hinweis|Each device is of exactly one "type". This type determines Perl program file (more precisly called: "module"), with certain routines and properties coded. Since our device is of type ''dummy'', FHEM can find routines and properties in module 98_dummy.pm. (Figure ''98'' formerly bore a meaning, now it doesn't no longer - for historical reason it is further used.)}}<br />
<br />
Devices have a "state", changing in time and recorded by FHEM. E.g., some window is open, a shutter is closed, an outlet is under voltage. A state not necessary consists of exactly one value (window: "open" or "closed"), state can be described by a bunch of values (state of a Raspberry system - device type ''sysmon'' - contains CPU frequency, CPU temperature, load and much more).<br />
<br />
Device status in FHEM consists of overall three blocks of values, called ''Internals'', ''Attributes'' and ''Readings''. It's early days yet to discuss in-depth meaning of these terms, but some remarks are important for our next steps:<br />
* ''Internals'' store very basic informationen about a device. Only in rare cases users will edit directly internals (mostly during define step).<br />
* ''Attributs'' control device behavior. Typically they can be changed (or even defined) by users.<br />
* ''Readings'' have in contrast to the values of the other two blocks a timestamp. Usually they are measured values of your device.<br />
<br />
It may be confusing for beginners that there can be Internals and Readings of equal names (e.g. STATE and state). Though Perl distinguishes lower and upper case.<br />
<br />
{{Hinweis|Block '''''Internals''''' always shows basic characteristics of a FHEM device:<br />
*'''''NAME:''''' device name assigned by the user<br />
*'''''TYPE:''''' device type of FHEM device, here: ''dummy''<br />
*'''''STATE:''''' device state shown in all summaries. Since there was no assignment till now it is initially '''''???'''''.}}<br />
<br />
== Creating rooms ==<br />
<br />
Let's do a step forward and arrange our devices in rooms. You may consider reasonable to put together devices physically (really) located in one room into a FHEM room. So you can find in "''bedroom''" appropriate devices like "''shutter''", "''time switch''" and "''radio set''". You may decide other assignments: put all measuring devices like thermometers, electric meters and hygrometers in one (possibly only virtually and not physically existing) room "''measuring devices''". Name of a room is arbitrary.<br />
<br />
To achieve this you have to add to all devices your room should contain an "Attribute" (see above). Name of the attribute is "room" and it should get as its value the room name. Let's try it with our room ''dummy''. Use command<br />
attr mySwitch1 room Training<br />
and finish input with {{Taste|Enter}}).<br />
<br />
With this command you have added to device ''mySwitch1'' Attribute ''room'' with value ''Training''. Again, ''attr'', ''mySwitch1'' (while referencing to an existing object's name) and ''room'' are part of FHEM's command syntax and are unalterable, ''Training'' is arbitrary.<br />
<br />
Now ''mySwitch1'' belongs to room ''Training''. Due to this assignment room appears in navigation bar on the left hand side in room's block. Try to click at room ''Training''.<br />
<br />
[[Datei:ErsteSchritteInFhem04.png]]<br />
<br />
FHEM will show all devices belonging to this room. Until now we have only one device: ''mySwitch1'' - our dummy.<br />
<br />
Beside device name always device status is on display, we still get ''???''. Clicking at name ''mySwitch1'' you will return to its detailed view.<br />
<br />
Our dummy is shown in a block with (type) label ''dummy''. You may change label as well introducing a further attribute "''group''" and assigning to it (arbitrary as well) name: groups order devices inside a room.<br />
<br />
'''Note''':<br />If you want to delete a room, you may do so removing all devices from this room. In our example of room ''Training'' you have to delete in all devices of room ''Training'' attribute room. Room ''Training'' will dispear by itself.<br />
<br />
== Creating switching commands ==<br />
Now we want to add on/off-buttons to "mySwitch1": <br />
attr mySwitch1 webCmd on:off<br />
<br />
Again we use an attribute named webCmd with values on:off, we want to add to device "mySwitch1". Instead of entering mentioned above command into command line field you may choose desired attribute (in this case: '''''webCmd''''') in lower part of detail view and enter needed values into text field right next, in this case '''''on:off'''''. Complete your input with a click on button {{Taste|attr}}.<br />
<br />
[[Datei:ErsteSchritteInFhem05.png]]<br />
<br />
Now let's click again on room ''Training''.<br />
<br />
You may see, that due to atribute added in last step in room view switch buttons for ''on'' and ''off'' have appeared.<br />
<br />
[[Datei:ErsteSchritteInFhem06.png]]<br />
<br />
Click experimentally on ''on'' and ''off'': instead of ''???'' you got so far you may find a bulb symbol showing current state.<br />
<br />
Clicking on device name ''mySwitch1'' you change back to detail view and may see in block ''Internals'' current state ''STATE'' - being shown in room view as an icon (bulb).<br />
<br />
[[Datei:ErsteSchritteInFhem07.png]]<br />
<br />
In detail view you can see a new block ''Readings'' as well.<br />
<br />
Please switch off ''mySwitch1'' once again. Pay attention to readings: next to internal ''STATE'' you may find a reading of same name (see above: Perl distinguishes lower and upper case), but equipped with a timestamp. Check reading ''state'' for updating at value and timestamp.<br />
<br />
== Event monitor ==<br />
<br />
Please, open in your browser another window with FHEM and in FHEM its '''[[Event monitor]]'''. The shortest way is to right-click on ''Event monitor'' and to select from the local menu "Open in new window". Place Windows in such a way, that you can follow event monitor and operate your "mySwitch1" at once. Using Windows 7 or newer simply activate one window and press {{Taste|Windows}}+{{Taste|Pfeil rechts}}, followed by activating second window and pressing {{Taste|Windows}}+{{Taste|Pfeil links}}.<br />
<br />
[[Datei:ErsteSchritteInFhem08.png]]<br />
<br />
Devices communicate via events. One device sends an event to FHEM and FHEM distributes this event to all devices. Devices decide whether to react or not and if yes - how. Let's have a closer look at this.<br />
<br />
Switching ''mySwitch1'' FHEM generates an event. With every actuation of the switch yet another event appears in ''Event monitor''. Please look what happens when you consecutively click twice on ''on''.<br />
<br />
Events always consist of a timestamp followed by the type of the triggering device (in this case: ''dummy''), name of the triggering device (in this case: ''mySwitch1'') as well as triggered command (in this case: ''on'' or ''off''). <br />
<br />
FHEM devices like remotes or remote-controlled wall switches, which trigger physical events, generate events in FHEM with every keypress in device itself or click on associated FHEM device. <br />
<br />
Understanding events, their structure and operation is crucial - we will frequently need them below.<br />
<br />
== Operating devices - set ==<br />
<br />
So you have learned to switch ''mySwitch1'' clicking at ''on'' or ''off''. Alternatively you can use command line entering instructions there.<br />
<br />
So please, enter in command line field <code>set mySwitch1 on</code> or <code>set mySwitch1 off</code> and confirm this with button {{Taste|Enter}}. Switching status will change accordingly as well and an Event will be triggered. By the way, we will frequently use command ''set'' in future.<br />
<br />
Preparing further tests we now create a new device '''''myLamp1''''' that we later on want to control with '''''mySwitch1'''''.<br />
define myLamp1 dummy<br />
<br />
Since ''myLamp1'' is a lamp - an actor - it won't get buttons for ''on'' or ''off''. <br />
<br />
Lamp should be located in room ''Training''. You might set this assignment via command line, like shown above. But this time we will use computer mouse...<br />
<br />
Until now ''myLamp1'' has no room assignment, so it appears in room ''Unsorted''. Change over in this room and click at name ''myLamp1'' getting so detail view.<br />
<br />
In the lower part we can set attribute assignments.<br />
<br />
Attribute ''room'' is already selected (as default). When you click at text field next to ''room'', a dialog box opens that contains all rooms FHEM knows so far. You may select one ore more checkboxes and assign this or these rooms to device. Now select only room ''Training'' and confirm selection with button {{Taste|OK}}. Selected room will be transferred into text field and it remains only to click at button {{Taste|attr}} to activate assingment. <br />
<br />
[[Datei:ErsteSchritteInFhem09.png]]<br />
<br />
Now change back to room ''Training'' and you will see both devices:<br />
<br />
[[Datei:ErsteSchritteInFhem10.png]]<br />
<br />
== Event trigger - notify ==<br />
Now we will enable FHEM to react to an event of ''mySwitch1'': Every time ''mySwitch1'' is triggering event with command ''on'' we want to switch on ''myLamp1''.<br />
<br />
For it FHEM uses a "notify". Defining syntax looks like<br />
define <NAME> notify <REGEXP> <command><br />
<br />
* Name '''<NAME>''' will help us to find this FHEM device and display its properties. This time we name the device ''n_mySwitch1_on'' - ''n_'' for marking es a notify, following by the name of triggering device and triggering command. Such a name may seem too complicated but it is very useful when working with a whole bunch ov notifies. You may name it if desired ''n1'' or ''John Doe''. Device names may consist of characters '''a-z''', '''A-Z''', '''0-9''', '''_ (underscore)''' and '''. (period)''' with a period not at first position. In perl and therefore in FHEM period has a special meaning, so avoid if possible periods in device names.<br />
*'''<REGEXP>''' stands for "regular expression" and describes a condition for raising notify. We will meet regular expressions in perl and FHEM frequently. They are used to describe syntactical characteristics of strings, e. g. whether a string contains a given word or not, whether digits are in our string and much more. When ever in FHEM a event raises for every notify runs a check for regexp matching. In our case ''mySwitch1'' raises an event with command ''on''. To "catch" this event and react to it we have notation <code>mySwitch1:on</code>. In future you will have much more moments to deal with regexps in detail. :)<br />
*'''<command>''' tells what to do. In our case: <code>set myLamp1 on</code>.<br />
<br />
So our notify looks like <br />
define n_mySwitch1_on notify mySwitch1:on set myLamp1 on<br />
<br />
After you have entered this in command field followed by {{Taste|Enter}}, you will see again detail view of the new FHEM notify device (see TYPE).<br />
<br />
[[Datei:ErsteSchritteInFhem11.png]]<br />
<br />
In block ''Internals'' you can find definition '''DEF'''. Here you see all text you have entered in event definition after the word "notify" (device type). So you can see ''<regexp>'' and ''<command>''.<br />
{{Hinweis|In Block '''''Probably associated with''''' you can find all FHEM devices associated with this notify. Devices are listed as clickable device names, so you can jump over with only one click to detail view of the respective device.}}<br />
<br />
Please assign notify to room ''Training'' (find in the lower part attribute ''room'' and choose correct room followed by a click at ''attr'').<br />
<br />
So clicking in FHEM's main menu at ''Training'' you will get our three FHEM devices.<br />
<br />
[[Datei:ErsteSchritteInFhem12.png]]<br />
<br />
{{Hinweis|Usally a notify wouldn't be assigned to a room since it shouldn't be visible for user later on. We will do it anyway for our training purposes.}}<br />
<br />
Now switch ''mySwitch1'' to ''on'' - ''myLamp1'' will be switched too. It seems that it works only at first time, but checking event monitor or looking in ''myLamp1'''s detail view at timestamp of last state change you can notice that it executes every time.<br />
<br />
To get it working for switching off too we define a second notify:<br />
define n_mySwitch1_off notify mySwitch1:off set myLamp1 off<br />
<br />
Does it work like expected?<br />
<br />
Doubtless you dislike defining an own notify for every command a device should raise. You can get it easier.<br />
<br />
Instead of <br />
define n_mySwitch1_on notify mySwitch1:on set myLamp1 on<br />
define n_mySwitch1_off notify mySwitch1:off set myLamp1 off<br />
we define<br />
define n_mySwitch1 notify mySwitch1 set myLamp1 '''$EVENT'''<br />
We see that this time regexp doesn't differ events ''on'' and ''off'' of ''mySwitch1''. With an absent regexp declaration notify raises for any event with whatsoever command. In executing set command we use FHEM variable '''$EVENT''' (follow the capital notation!). This is a placeholder for the command taken over from the raising event. Having from ''mySwitch1'' an ''on'', '''$EVENT''' will stand for value ''on'' too, accordingly for ''off'' and any other command.<br />
<br />
== Deleting or disabling devices – delete, disable ==<br />
Looking at Event Monitor you see that after activation of ''mySwitch1'' command for ''myLamp1'' is executed twice. The reason is, that any event of ''mySwitch1'' is catched by two notifies - by the "old" notify as well as by the new one. To avoid this we should get rid of the old. For that purpose we have two choices.<br />
<br />
#'''Delete''' a notify with command <code>delete <name></code>, e. g. with <code>delete n_mySwitch1_on</code>. By the way, command <code>delete</code> works with any object in FHEM. So you can delete this way "real" devices too.<br />
#'''Deactivate''' a notify, using attribute ''disable''. You can assign it in detail view of the related notify (find attribute ''disable'' in lower part and choose value ''1'' with a following click at {{Taste|attr}}), or enter in command line: <code>attr n_mySwitch1_off disable 1</code>.<br />
<br />
== Save Config ==<br />
Whenever you are satisfied with the current state of your FHEM configuration, click on '''''Save config''''' in the top left corner of the FHEM menu or enter the command <code>save</code> in the command field followed by {{Taste|Enter}}. Your configuration is now saved. If you do not do this, all changes will be lost after the next FHEM restart. FHEM therefore reminds you of unsaved changes with a red question mark next to '''''Save config'''''.<br />
<br />
== Modifying existing – modify ==<br />
== Switching a couple of devices at once ==<br />
== Renaming devices ==<br />
== Scheduler - at ==<br />
== Event-driven timer start - notify und at ==<br />
== How do we go on? ==<br />
<br />
[[Kategorie:HOWTOS]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=First_steps_in_FHEM&diff=23045First steps in FHEM2017-10-24T21:23:45Z<p>Amenomade: /* First attempt */ Improvement</p>
<hr />
<div>{{Baustelle}}<br />
----<br />
----<br />
Hier entsteht die englische Fassung von [[Erste Schritte in FHEM]]...<br />
<br />
* Letzte Änderung der dt. Fassung: {{REVISIONDAY2: Erste Schritte in FHEM}}.{{REVISIONMONTH: Erste Schritte in FHEM}}.{{REVISIONYEAR: Erste Schritte in FHEM}} <br />
* Letzte Änderung der engl. Fassung: {{REVISIONDAY2: First steps in FHEM}}.{{REVISIONMONTH: First steps in FHEM}}.{{REVISIONYEAR: First steps in FHEM}}<br />
* '''Neuere''' Version ist: '''{{#ifexpr: {{REVISIONTIMESTAMP: Erste Schritte in FHEM}} > {{REVISIONTIMESTAMP: First steps in FHEM}}| dt. Version|engl. Version}}'''<br />
<br />
----<br />
----<br />
<br />
This a beginners course for those starting to work with FHEM. After you have installed FHEM on your server you may reproduce all steps without any additional smart home hardware.<br />
<br />
This guide was primarily published by Ulrich Maass who permitted the use in FHEM wiki.<br />
<br />
Note to editors: Everybody is called to improve orthography, grammar and style. Content changes and extentions should be discussed with the author (e. g. on associated [[Diskussion:First_steps_in_FHEM|discussion page]]).<br />
<br />
== First attempt ==<br />
To start FHEM for the first time, enter in your browsers address field:<br />
<nowiki>http://<ip-address>:8083</nowiki><br />
e. g. <nowiki>http://192.168.1.1:8083</nowiki>.<br />
<br />
The FHEM homepage is displayed:<br />
<br />
[[Datei:ErsteSchritteInFhem01.png|border]]<br />
<br />
* At the top of the screen you can see the white ''command line'' where you can enter commands.<br />
* The first menu item is the ''Save config'' button, which saves changes so that they are still available even after a restart.<br />
* Furthermore, there are already the rooms ''Unsorted'' and ''Everything'' that we will soon get to know<br />
* In the lower block there are further links, which we will also discuss later.<br />
<br />
The ''Security Check'' note indicates that you have not yet set a password for FHEM. To set up password protection, see the FHEM command reference [http://fhem.de/commandref.html#basicAuth commandref], which contains a description of all FHEM functions and modules. To suppress this message for now, enter the following in the command line: <br />
attr global motd none<br />
and confirm this change with {{Taste|Enter}}.<br />
<br />
[[Datei:ErsteSchritteInFhem02.png|border]]<br />
<br />
== Creating device - define ==<br />
The main component type in FHEM is called ''device''.Typical devices are e.g. remote controlled outlets, roller shutter motors, temperature sensors, solenoid valves etc.<br />
<br />
But there are other kinds of devices too, where at first view you wouldn't expect it: FHEM's user interface (''"FHEMWEB"'') is a device, there are devices without a physical equipment used to store a variable's value. <br />
<br />
Now we will create a very simple device, called ''dummy''.<br />
<br />
A device of type ''dummy'' is a special object, inasmuch as it nonessential needs corresponding physical equipment (physical lamp, roller shutter, solenoid valve). So we can proceed in this guide without a real hardware system, or rather we don't need to concider differences between differrent hardware. A dummy device is generally represented on FHEM's user interface like a FHEM device with a physical equivalent. <br />
<br />
Lets begin with a switch. It is designed to simulate a light switch on the wall. Please, enter command in command field:<br />
define mySwitch1 dummy<br />
<br />
"define" is the needed FHEM command, "mySwitch1" the future name of our device, "dummy" describes its type. Words "define" and "dummy" are part of FHEM'S command syntax and are unalterable, "mySwitch1" is (more or less) arbitrary. After pressing button {{Taste|Enter}} detail view of our new FHEM device ''mySwitch1'' appears.<br />
<br />
[[Datei:ErsteSchritteInFhem03.png|border]]<br />
<br />
{{Hinweis|Each device is of exactly one "type". This type determines Perl program file (more precisly called: "module"), with certain routines and properties coded. Since our device is of type ''dummy'', FHEM can find routines and properties in module 98_dummy.pm. (Figure ''98'' formerly bore a meaning, now it doesn't no longer - for historical reason it is further used.)}}<br />
<br />
Devices have a "state", changing in time and recorded by FHEM. E.g., some window is open, a shutter is closed, an outlet is under voltage. A state not necessary consists of exactly one value (window: "open" or "closed"), state can be described by a bunch of values (state of a Raspberry system - device type ''sysmon'' - contains CPU frequency, CPU temperature, load and much more).<br />
<br />
Device status in FHEM consists of overall three blocks of values, called ''Internals'', ''Attributes'' and ''Readings''. It's early days yet to discuss in-depth meaning of these terms, but some remarks are important for our next steps:<br />
* ''Internals'' store very basic informationen about a device. Only in rare cases users will edit directly internals (mostly during define step).<br />
* ''Attributs'' control device behavior. Typically they can be changed (or even defined) by users.<br />
* ''Readings'' have in contrast to the values of the other two blocks a timestamp. Usually they are measured values of your device.<br />
<br />
It may be confusing for beginners that there can be Internals and Readings of equal names (e.g. STATE and state). Though Perl distinguishes lower and upper case.<br />
<br />
{{Hinweis|Block '''''Internals''''' always shows basic characteristics of a FHEM device:<br />
*'''''NAME:''''' device name assigned by the user<br />
*'''''TYPE:''''' device type of FHEM device, here: ''dummy''<br />
*'''''STATE:''''' device state shown in all summaries. Since there was no assignment till now it is initially '''''???'''''.}}<br />
<br />
== Creating rooms ==<br />
<br />
Let's do a step forward and arrange our devices in rooms. You may consider reasonable to put together devices physically (really) located in one room into a FHEM room. So you can find in "''bedroom''" appropriate devices like "''shutter''", "''time switch''" and "''radio set''". You may decide other assignments: put all measuring devices like thermometers, electric meters and hygrometers in one (possibly only virtually and not physically existing) room "''measuring devices''". Name of a room is arbitrary.<br />
<br />
To achieve this you have to add to all devices your room should contain an "Attribute" (see above). Name of the attribute is "room" and it should get as its value the room name. Let's try it with our room ''dummy''. Use command<br />
attr mySwitch1 room Training<br />
and finish input with {{Taste|Enter}}).<br />
<br />
With this command you have added to device ''mySwitch1'' Attribute ''room'' with value ''Training''. Again, ''attr'', ''mySwitch1'' (while referencing to an existing object's name) and ''room'' are part of FHEM's command syntax and are unalterable, ''Training'' is arbitrary.<br />
<br />
Now ''mySwitch1'' belongs to room ''Training''. Due to this assignment room appears in navigation bar on the left hand side in room's block. Try to click at room ''Training''.<br />
<br />
[[Datei:ErsteSchritteInFhem04.png]]<br />
<br />
FHEM will show all devices belonging to this room. Until now we have only one device: ''mySwitch1'' - our dummy.<br />
<br />
Beside device name always device status is on display, we still get ''???''. Clicking at name ''mySwitch1'' you will return to its detailed view.<br />
<br />
Our dummy is shown in a block with (type) label ''dummy''. You may change label as well introducing a further attribute "''group''" and assigning to it (arbitrary as well) name: groups order devices inside a room.<br />
<br />
'''Note''':<br />If you want to delete a room, you may do so removing all devices from this room. In our example of room ''Training'' you have to delete in all devices of room ''Training'' attribute room. Room ''Training'' will dispear by itself.<br />
<br />
== Creating switching commands ==<br />
Now we want to add on/off-buttons to "mySwitch1": <br />
attr mySwitch1 webCmd on:off<br />
<br />
Again we use an attribute named webCmd with values on:off, we want to add to device "mySwitch1". Instead of entering mentioned above command into command line field you may choose desired attribute (in this case: '''''webCmd''''') in lower part of detail view and enter needed values into text field right next, in this case '''''on:off'''''. Complete your input with a click on button {{Taste|attr}}.<br />
<br />
[[Datei:ErsteSchritteInFhem05.png]]<br />
<br />
Now let's click again on room ''Training''.<br />
<br />
You may see, that due to atribute added in last step in room view switch buttons for ''on'' and ''off'' have appeared.<br />
<br />
[[Datei:ErsteSchritteInFhem06.png]]<br />
<br />
Click experimentally on ''on'' and ''off'': instead of ''???'' you got so far you may find a bulb symbol showing current state.<br />
<br />
Clicking on device name ''mySwitch1'' you change back to detail view and may see in block ''Internals'' current state ''STATE'' - being shown in room view as an icon (bulb).<br />
<br />
[[Datei:ErsteSchritteInFhem07.png]]<br />
<br />
In detail view you can see a new block ''Readings'' as well.<br />
<br />
Please switch off ''mySwitch1'' once again. Pay attention to readings: next to internal ''STATE'' you may find a reading of same name (see above: Perl distinguishes lower and upper case), but equipped with a timestamp. Check reading ''state'' for updating at value and timestamp.<br />
<br />
== Event monitor ==<br />
<br />
Please, open in your browser another window with FHEM and in FHEM its '''[[Event monitor]]'''. The shortest way is to right-click on ''Event monitor'' and to select from the local menu "Open in new window". Place Windows in such a way, that you can follow event monitor and operate your "mySwitch1" at once. Using Windows 7 or newer simply activate one window and press {{Taste|Windows}}+{{Taste|Pfeil rechts}}, followed by activating second window and pressing {{Taste|Windows}}+{{Taste|Pfeil links}}.<br />
<br />
[[Datei:ErsteSchritteInFhem08.png]]<br />
<br />
Devices communicate via events. One device sends an event to FHEM and FHEM distributes this event to all devices. Devices decide whether to react or not and if yes - how. Let's have a closer look at this.<br />
<br />
Switching ''mySwitch1'' FHEM generates an event. With every actuation of the switch yet another event appears in ''Event monitor''. Please look what happens when you consecutively click twice on ''on''.<br />
<br />
Events always consist of a timestamp followed by the type of the triggering device (in this case: ''dummy''), name of the triggering device (in this case: ''mySwitch1'') as well as triggered command (in this case: ''on'' or ''off''). <br />
<br />
FHEM devices like remotes or remote-controlled wall switches, which trigger physical events, generate events in FHEM with every keypress in device itself or click on associated FHEM device. <br />
<br />
Understanding events, their structure and operation is crucial - we will frequently need them below.<br />
<br />
== Operating devices - set ==<br />
<br />
So you have learned to switch ''mySwitch1'' clicking at ''on'' or ''off''. Alternatively you can use command line entering instructions there.<br />
<br />
So please, enter in command line field <code>set mySwitch1 on</code> or <code>set mySwitch1 off</code> and confirm this with button {{Taste|Enter}}. Switching status will change accordingly as well and an Event will be triggered. By the way, we will frequently use command ''set'' in future.<br />
<br />
Preparing further tests we now create a new device '''''myLamp1''''' that we later on want to control with '''''mySwitch1'''''.<br />
define myLamp1 dummy<br />
<br />
Since ''myLamp1'' is a lamp - an actor - it won't get buttons for ''on'' or ''off''. <br />
<br />
Lamp should be located in room ''Training''. You might set this assignment via command line, like shown above. But this time we will use computer mouse...<br />
<br />
Until now ''myLamp1'' has no room assignment, so it appears in room ''Unsorted''. Change over in this room and click at name ''myLamp1'' getting so detail view.<br />
<br />
In the lower part we can set attribute assignments.<br />
<br />
Attribute ''room'' is already selected (as default). When you click at text field next to ''room'', a dialog box opens that contains all rooms FHEM knows so far. You may select one ore more checkboxes and assign this or these rooms to device. Now select only room ''Training'' and confirm selection with button {{Taste|OK}}. Selected room will be transferred into text field and it remains only to click at button {{Taste|attr}} to activate assingment. <br />
<br />
[[Datei:ErsteSchritteInFhem09.png]]<br />
<br />
Now change back to room ''Training'' and you will see both devices:<br />
<br />
[[Datei:ErsteSchritteInFhem10.png]]<br />
<br />
== Event trigger - notify ==<br />
Now we will enable FHEM to react to an event of ''mySwitch1'': Every time ''mySwitch1'' is triggering event with command ''on'' we want to switch on ''myLamp1''.<br />
<br />
For it FHEM uses a "notify". Defining syntax looks like<br />
define <NAME> notify <REGEXP> <command><br />
<br />
* Name '''<NAME>''' will help us to find this FHEM device and display its properties. This time we name the device ''n_mySwitch1_on'' - ''n_'' for marking es a notify, following by the name of triggering device and triggering command. Such a name may seem too complicated but it is very useful when working with a whole bunch ov notifies. You may name it if desired ''n1'' or ''John Doe''. Device names may consist of characters '''a-z''', '''A-Z''', '''0-9''', '''_ (underscore)''' and '''. (period)''' with a period not at first position. In perl and therefore in FHEM period has a special meaning, so avoid if possible periods in device names.<br />
*'''<REGEXP>''' stands for "regular expression" and describes a condition for raising notify. We will meet regular expressions in perl and FHEM frequently. They are used to describe syntactical characteristics of strings, e. g. whether a string contains a given word or not, whether digits are in our string and much more. When ever in FHEM a event raises for every notify runs a check for regexp matching. In our case ''mySwitch1'' raises an event with command ''on''. To "catch" this event and react to it we have notation <code>mySwitch1:on</code>. In future you will have much more moments to deal with regexps in detail. :)<br />
*'''<command>''' tells what to do. In our case: <code>set myLamp1 on</code>.<br />
<br />
So our notify looks like <br />
define n_mySwitch1_on notify mySwitch1:on set myLamp1 on<br />
<br />
After you have entered this in command field followed by {{Taste|Enter}}, you will see again detail view of the new FHEM notify device (see TYPE).<br />
<br />
[[Datei:ErsteSchritteInFhem11.png]]<br />
<br />
In block ''Internals'' you can find definition '''DEF'''. Here you see all text you have entered in event definition after the word "notify" (device type). So you can see ''<regexp>'' and ''<command>''.<br />
{{Hinweis|In Block '''''Probably associated with''''' you can find all FHEM devices associated with this notify. Devices are listed as clickable device names, so you can jump over with only one click to detail view of the respective device.}}<br />
<br />
Please assign notify to room ''Training'' (find in the lower part attribute ''room'' and choose correct room followed by a click at ''attr'').<br />
<br />
So clicking in FHEM's main menu at ''Training'' you will get our three FHEM devices.<br />
<br />
[[Datei:ErsteSchritteInFhem12.png]]<br />
<br />
{{Hinweis|Usally a notify wouldn't be assigned to a room since it shouldn't be visible for user later on. We will do it anyway for our training purposes.}}<br />
<br />
Now switch ''mySwitch1'' to ''on'' - ''myLamp1'' will be switched too. It seems that it works only at first time, but checking event monitor or looking in ''myLamp1'''s detail view at timestamp of last state change you can notice that it executes every time.<br />
<br />
To get it working for switching off too we define a second notify:<br />
define n_mySwitch1_off notify mySwitch1:off set myLamp1 off<br />
<br />
Does it work like expected?<br />
<br />
Doubtless you dislike defining an own notify for every command a device should raise. You can get it easier.<br />
<br />
Instead of <br />
define n_mySwitch1_on notify mySwitch1:on set myLamp1 on<br />
define n_mySwitch1_off notify mySwitch1:off set myLamp1 off<br />
we define<br />
define n_mySwitch1 notify mySwitch1 set myLamp1 '''$EVENT'''<br />
We see that this time regexp doesn't differ events ''on'' and ''off'' of ''mySwitch1''. With an absent regexp declaration notify raises for any event with whatsoever command. In executing set command we use FHEM variable '''$EVENT''' (follow the capital notation!). This is a placeholder for the command taken over from the raising event. Having from ''mySwitch1'' an ''on'', '''$EVENT''' will stand for value ''on'' too, accordingly for ''off'' and any other command.<br />
<br />
== Deleting or disabling devices – delete, disable ==<br />
Looking at Event Monitor you see that after activation of ''mySwitch1'' command for ''myLamp1'' is executed twice. The reason is, that any event of ''mySwitch1'' is catched by two notifies - by the "old" notify as well as by the new one. To avoid this we should get rid of the old. For that purpose we have two choices.<br />
<br />
#'''Delete''' a notify with command <code>delete <name></code>, e. g. with <code>delete n_mySwitch1_on</code>. By the way, command <code>delete</code> works with any object in FHEM. So you can delete this way "real" devices too.<br />
#'''Deactivate''' a notify, using attribute ''disable''. You can assign it in detail view of the related notify (find attribute ''disable'' in lower part and choose value ''1'' with a following click at {{Taste|attr}}), or enter in command line: <code>attr n_mySwitch1_off disable 1</code>.<br />
<br />
== Save Config ==<br />
Whenever you are satisfied with the current state of your FHEM configuration, click on '''''Save config''''' in the top left corner of the FHEM menu or enter the command <code>save</code> in the command field followed by {{Taste|Enter}}. Your configuration is now saved. If you do not do this, all changes will be lost after the next FHEM restart. FHEM therefore reminds you of unsaved changes with a red question mark next to '''''Save config'''''.<br />
<br />
== Modifying existing – modify ==<br />
== Switching a couple of devices at once ==<br />
== Renaming devices ==<br />
== Scheduler - at ==<br />
== Event-driven timer start - notify und at ==<br />
== How do we go on? ==<br />
<br />
[[Kategorie:HOWTOS]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=PRESENCE&diff=22912PRESENCE2017-10-13T23:45:16Z<p>Amenomade: /* Problemlösungen */ Deep standby Problem</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Anwesenheitserkennung<br />
|ModType=h<br />
<!-- |ModCmdRef= --><br />
|ModTechName=73_PRESENCE.pm<br />
|ModOwner=markusbloch<br />
}}<br />
<br />
Das [[PRESENCE]] Modul bietet für die Anwesenheitserkennung mehrere Varianten an: <br />
<br />
* '''lan-ping''' - Das Überwachen via PING Checks, die durch den FHEM Server versandt werden.<br />
* '''fritzbox''' - Das Überwachen von Geräten auf einer FritzBox via ctlmgr_ctl (Nur auf einer FritzBox möglich)<br />
* ''' Bluetooth'''<br />
:- '''local-bluetooth''' - Das Überwachen via Bluetooth Checks, die vom FHEM Server direkt durchgeführt werden (angeschlossener Bluetooth-Stick und die Software bluez voraussgesetzt)<br />
:- '''lan-bluetooth''' - Das Überwachen von Bluetoothgeräten, über Netzwerk. Auf einer oder mehreren Maschinen im Netzwerk (z.B. [[:Kategorie:Raspberry Pi|Raspberry Pi]]) läuft ein Presence-Daemon, der nach Bluetooth-Geräten sucht. Um mehrere Presence-Daemon mit FHEM zu verbinden, gibt es den Collector-Daemon, der sich zu allen Presence-Damons im Netzwerk verbindet und das Ergebnis von allen zusammenfasst.<br />
* '''function''' - Das Überwachen mithilfe einer selbst geschrieben Perl-Funktion, die den Anwesenheitsstatus zurückgibt (0 oder 1)<br />
* '''shell-script''' - Das Überwachen mithilfe eines selbst geschriebenen Shell-Programms/Skript, das eine 0 oder 1 ausgibt, um den Anwesenheitsstatus mitzuteilen.<br />
<br />
<br />
= Überwachen mittels Ping im WLAN/LAN =<br />
{{Randnotiz|RNText=Um diese Methode auf einer FritzBox nutzen zu können, muss FHEM mit root-Rechten laufen. Dies ist standardmäßig nicht der Fall. Bitte dazu den Wiki Artikel [[FritzBox: fhem unter root starten]] beachten.}}<br />
Um ein Gerät via Ping zu überwachen, muss folgende Definition durchgeführt werden:<br />
:<code>define Handy PRESENCE lan-ping 192.168.0.30</code><br />
<br />
Dadurch wird die IP-Addresse 192.168.0.30 alle 30&nbsp;Sekunden geprüft, ob sie erreichbar ist. Wenn sie erreichbar ist, ist der Status "present" (anwesend), ansonsten "absent" (abwesend).<br />
<br />
Der Timeout kann verändert werden, indem ein Wert (in Sekunden) an das Define anhängt wird:<br />
:<code>define Handy PRESENCE lan-ping 192.168.0.30 '''60'''</code><br />
<br />
Nun würde das Handy alle 60 Sekunden geprüft werden.<br />
<br />
Nur wenn bei einem iPhone/iPad die Funktion "über WLAN synchronisieren" aktiviert ist, ist es auch im Standby zuverlässig pingbar. Standardmäßig deaktivieren Apple-Geräte ihr WLAN im Standby-Betrieb um die Akkulaufzeit zu verlängern.<br />
<br />
Sollte die Fehlermeldung <br />
:<code> PRESENCE (Handy) - ping command returned with output: ping: icmp open socket: Operation not permitted </code> <br />
im Log auftauchen und lan-ping dadurch nicht funktionieren, liegt ein Berechtigungsproblem vor. Kein Grund den User fhem zu root zu machen!<br />
Prüfe zu erst als User root ob die Capabilities gesetzt sind.<br />
:<code>getcap /bin/ping</code><br />
Sollte folgendes Ergeben zu Tage fördern.<br />
:<code>/bin/ping = cap_net_raw+ep</code><br />
Ist dem nicht so, setzen wir die benötigten Capabilities<br />
:<code>setcap cap_net_raw+ep /bin/ping</code><br />
Mehr Informationen zum Thema Capabilities [https://manpages.debian.org/jessie/manpages-de/capabilities.7.de.html].<br />
<br />
<br />
= FritzBox: direktes Abfragen der Aktivität via ctlmgr_ctl =<br />
{{Randnotiz|RNText=Um diese Methode auf einer FritzBox nutzen zu können, muss FHEM mit root-Rechten laufen. Dies ist standardmäßig nicht der Fall. Bitte dazu den Wiki Artikel [[FritzBox: fhem unter root starten]] beachten.}}<br />
Eine sehr häufige und auch zuverlässige Methode ist auf einer FritzBox die Abfrage mittels ctlmgr_ctl Befehl. Über diesen lassen sich alle Geräte abfragen ob sie aktiv sind. Ist ein Gerät aktiv, so gilt es als anwesend.<br />
<br />
Dieser Modus kann allerdings nur in FHEM Installationen direkt auf einer FritzBox verwendet werden. Des weiteren muss FHEM unter dem User root laufen. Um ein Gerät zu überwachen, wird lediglich der Gerätename benötigt, so wie er unter dem Menüpunkt "Heimnetz" auftaucht. <br />
<br />
Die erforderliche Definition:<br />
:<code>define Handy PRESENCE fritzbox iPhone-4S</code><br />
<br />
<br />
= Überwachung mittels Perl-Code =<br />
Es ist möglich zum Überwachen von Geräten eine eigene Perl-Funktion zu verwenden die dann vom PRESENCE Modul im Hintergrund aufgerufen wird.<br />
<br />
define <name> PRESENCE function {...} [ <check-interval> [ <present-check-interval> ] ]<br />
<br />
Sobald die Funktion den Rückgabewert 1 hat, ist das Gerät anwesend, bei 0 abwesend.<br />
<br />
== Beispiel DHCP Überwachung auf Airport Basestation ==<br />
Die hier vorgestellte Überwachung der DHCP Lease auf Airport Basestations per SNMP ist absolut robust gegenüber dem Ruhezustand von iOS und setzt keine weitere Konfiguration auf dem iPhone voraus. Das Abmelden beim Verlassen des Empfangsbereiches der Basestation geschieht mit etwa 5-10 Minuten Verzögerung und ist somit auch vor kurzzeitigen Empfangsproblemen sicher. Das nebenstehende Bild (???) verdeutlicht noch mal die Unterschiede zwischen einer IP-Basierten Ping-Überwachung und der Überwachung auf Ebene der Basestation oder FritzBox.<br />
<br />
Bevor der folgende Code verwendet werden kann ist das Perl Modul Net:SNMP zu installieren (z.&nbsp;B. mit: <code>cpan install use Net::SNMP</code>).<br />
<br />
Zuerst ist folgender Code in 99_myUtils.pm einzufügen, sollte diese noch nicht vorhanden sein muss diese aus dem Template welches unter Edit Files zu finden ist erzeugt werden.<br />
'''Achtung, das ist nicht der komplette Inhalt der 99_myUtils!''' Das ist nur die einzelne Routine<br />
<br />
<pre><br />
use Net::SNMP;<br />
sub<br />
snmpCheck($$)<br />
{<br />
my ($airport,$client)= @_;<br />
<br />
my $community = "public";<br />
my $host = $airport;<br />
my $oid = ".1.3.6.1.2.1.3.1.1.2";<br />
#my $oid = ".1.3.6.1.2.1.3.1.1.2.25.1.10.0.1";<br />
<br />
my ( $session, $error ) = Net::SNMP->session(<br />
-hostname => $host,<br />
-community => $community,<br />
-port => 161,<br />
-version => 1<br />
);<br />
<br />
if( !defined($session) ) {<br />
return 0;<br />
return "Can't connect to host $host.";<br />
}<br />
<br />
my @snmpoids = ();<br />
<br />
my $response = $session->get_next_request($oid);<br />
my @nextid = keys %$response;<br />
while ( @nextid && $nextid[0] && $nextid[0] =~ m/^$oid/ ) {<br />
push( @snmpoids, $nextid[0] );<br />
<br />
$response = $session->get_next_request( $nextid[0] );<br />
@nextid = keys %$response;<br />
}<br />
<br />
if( !defined($response = $session->get_request( @snmpoids ) ) ) {<br />
return 0;<br />
}<br />
<br />
foreach my $value (values %$response) {<br />
return 1 if( $value eq $client )<br />
}<br />
<br />
return 0;<br />
}<br />
</pre><br />
<br />
Danach lässt sich das Mobilgerät so überwachen:<br />
:<code>define iPhone PRESENCE function {snmpCheck("10.0.1.1","0x44d77429f35c")} 30 30</code><br />
<br />
wobei 10.0.1.1 durch die IP-Adresse der Basestation und 0x44d77429f35c durch die MAC Adresse des Geräts als HEX-Zahl ersetzt werden muss.<br />
<br />
== Beispiel Anwesenheitserkennung mittels UniFi Controller ==<br />
<br />
Die Anwesenheitserkennung bei Geräten in Verbindung mit UniFi-Produkten funktioniert selbst dann, wenn sich die Geräte im PowerSave-Modus befinden. <br />
<br />
Beachte: Die Geräte werden erst ungefähr nach 5 Minuten, nachdem das Gerät das WLAN verlassen hat als disconnected angezeigt.<br />
<br />
<code>define <NAME> PRESENCE function {ReadingsVal("<UniFi>","<NamedDevice>","") eq "connected" ? 1:0}</code><br />
<br />
<br />
= Überwachen mittels Events =<br />
Der Vorteil gegenüber der Function-Variante ist, dass diese Variante ohne Blocking.pm-Overhead direkt ausgeführt werden kann und in "Echtzeit" abläuft (siehe {{Link2Forum|Topic=40287|Message=562823}}).<br />
<br />
<code>define <NAME> PRESENCE event UniFi:NamedDevice:.disconnected UniFi:NamedDevice:.connected</code><br />
<br />
<br />
= Überwachen mittels Bluetooth =<br />
== Vorbereitung und Informationen ==<br />
=== Getestete Hardware/Software ===<br />
* '''Raspbian System''' - wheezy, Jessie (interner BT-Controller)<br />
* '''BT-Dongle''' - CSL NET BT USB2.0 Stick, Bluetooth V4.0, Nano <br />'''Achtung''': Es muss ein BT V4.0 oder höher verwendet werden. Nur dieser unterstützt ''LowEnergy''<br />
* '''BT-TAG''' - Gtag von Gigaset, TrackR, UDOO Neo, PebbleBee, iTag von Unitec, X4-LIFE Multifunkti BL-Anhänger, iTag Wireless Anti, Trackr bravo<br />
<br />
=== BT Dongel am PI installieren ===<br />
Um den BT Dongle ''(hier: CSL NET BT USB2.0)'' am PI verwenden zu können, müssen die notwendigen Pakete über die Paketverwaltung von debain nachinstalliert werden.<br />
Wer bereits ein BT-Dongle installiert hat, kann diesen Schritt überspringen.<br />
<pre><br />
apt-get install bluetooth<br />
</pre><br />
Nach erfolgreicher Installation der Pakete sollte der RaspberryPI neu gestartet werden.<br />
<pre><br />
sudo reboot<br />
</pre><br />
<br />
Nach dem erfolgten Reboot bitte das Log des Raspberry auf folgende Einträge prüfen:<br />
<pre><br />
Feb 12 19:52:55 fhem kernel: [ 4.773600] Bluetooth: Core ver 2.20<br />
Feb 12 19:52:55 fhem kernel: [ 4.773748] NET: Registered protocol family 31<br />
Feb 12 19:52:55 fhem kernel: [ 4.773765] Bluetooth: HCI device and connection manager initialized<br />
Feb 12 19:52:55 fhem kernel: [ 4.773797] Bluetooth: HCI socket layer initialized<br />
Feb 12 19:52:55 fhem kernel: [ 4.773821] Bluetooth: L2CAP socket layer initialized<br />
Feb 12 19:52:55 fhem kernel: [ 4.773890] Bluetooth: SCO socket layer initialized<br />
Feb 12 19:52:55 fhem kernel: [ 4.797531] usbcore: registered new interface driver btusb<br />
</pre><br />
Sobald der BT-Dongle erkannt wurde ''leuchtet'' (wenn vorhanden) auch die ''blaue/gelbe'' LED am Dongle auf.<br />
<br />
=== BT-Tags aktivieren ===<br />
Jetzt kann der BT-Tag aktiviert werden. Bei einigen Tags muss dafür die '''Batteriesicherung''' gezogen werden.<br />
<br />
Einen Tag wird mit folgendem Befehl auf der Konsole gesucht:<br />
<syntaxhighlight lang="bash"><br />
sudo hcitool lescan<br />
<br />
Ausgabe z.B.:<br />
LE Scan ...<br />
7C:2F:80:A1:XA:XD (unknown)<br />
7C:2F:80:A1:XA:XD Gigaset G-tag<br />
7C:2F:80:A1:X4:X1 (unknown)</syntaxhighlight><br />
Eine Übersicht über die möglichen Befehle von hcitool gibt es mit der Eingabe von:<br />
<pre><br />
sudo hcitool<br />
<br />
Ausgabe z.B.:<br />
hcitool - HCI Tool ver 5.23<br />
Usage:<br />
hcitool [options] <command> [command parameters]<br />
Options:<br />
--help Display help<br />
-i dev HCI device<br />
Commands:<br />
dev Display local devices<br />
inq Inquire remote devices<br />
scan Scan for remote devices<br />
name Get name from remote device<br />
info Get information from remote device<br />
spinq Start periodic inquiry<br />
epinq Exit periodic inquiry<br />
cmd Submit arbitrary HCI commands<br />
con Display active connections<br />
cc Create connection to remote device<br />
dc Disconnect from remote device<br />
sr Switch master/slave role<br />
cpt Change connection packet type<br />
rssi Display connection RSSI<br />
lq Display link quality<br />
tpl Display transmit power level<br />
afh Display AFH channel map<br />
lp Set/display link policy settings<br />
lst Set/display link supervision timeout<br />
auth Request authentication<br />
enc Set connection encryption<br />
key Change connection link key<br />
clkoff Read clock offset<br />
clock Read local or remote clock<br />
lescan Start LE scan<br />
lewladd Add device to LE White List<br />
lewlrm Remove device from LE White List<br />
lewlsz Read size of LE White List<br />
lewlclr Clear LE White list<br />
lecc Create a LE Connection<br />
ledc Disconnect a LE Connection<br />
lecup LE Connection Update <br />
</pre><br />
<br />
Falls beim SCAN kein Tag gefunden wird, sollte das BT Interface neu gestartet werden. Dazu ist kein Reboot des PI notwendig.<br />
<syntaxhighlight lang="bash"><br />
sudo hciconfig hci0 down<br />
sudo hciconfig hci0 up<br />
sudo hcitool dev<br />
</syntaxhighlight><br />
<br />
== Überwachung durch den FHEM Server direkt ==<br />
[[Datei:Bluetooth-Adresse-iPhone.png|thumb|Bluetooth-Adresse eines iPhones]]<br />
Jenach Aufstellungsort des FHEM Servers kann es sinnvoll sein, eine Bluetooth-Überwachung direkt durch den FHEM Server durchzuführen. Hierbei gilt allerdings zu beachten, dass Bluetooth nicht für große Reichweiten gedacht ist und in den meisten Fällen keine Wände überwinden kann. Das heisst, dass in den meisten Fällen damit nur ein Raum überwacht werden kann.<br />
<br />
Je nach Einsatzzweck kann das auch so gewollt sein. Bluetooth USB Sticks, die bereits Bluetooth 4.0 unterstützen, können höhere Reichweiten über Zimmerwände hinaus erreichen. Vorausgesetzt, das Mobilgerät unterstützt Bluetooth 4.0.<br />
<br />
Um eine Überwachung per Bluetooth durchführen zu können, benötigt man die Bluetooth-Adresse eines Gerätes. Diese ähnelt vom Aufbau einer MAC-Adresse. Generell wird die Adresse in den Telefon-Informationen bei Smartphones angezeigt.<br />
<br />
Um eine Anwesenheitserkennung via Bluetooth durchzuführen, wird folgende Definition in der [[Konfiguration]] benötigt:<br />
:<code>define Handy PRESENCE local-bluetooth XX:XX:XX:XX:XX:XX</code><br />
<br />
== Überwachung durch verteilte Agenten in der Wohnung (presenced/lepresenced/collectord) ==<br />
[[Datei:Raspberry-Pi-mit-WLAN-und-Bluetooth-Stick.jpg|thumb|left|Raspberry Pi mit Bluetooth- und WLAN-USB-Stick]]<br />
Um eine zuverlässige und flächendeckende Bluetooth-Anwesenheitserkennung durchzuführen, ist es unerlässlich, mehrere Bluetooth-Empfänger zu verwenden, die auf mehrere oder alle Räume verteilt sind.<br />
<br />
Hierfür bietet sich zum Beispiel ein [[Raspberry Pi]] mit einem Mini-Bluetooth-USB-Stick und evtl. einem WLAN-USB-Stick an. Jeder Raum wird mit solch einem Raspberry ausgestattet und ist im WLAN Netz verfügbar.<br />
<br />
Dieses Netz aus Raspberrys wird mit dem presenced / lepresenced Progamm ausgestattet. Beide Programme sind Perl-Skripte, die als Daemon im Hintergrund laufen und auf Anfragen via Netzwerk warten. Es wird lediglich eine vollständige Perl-Grundinstallation mit Standardmodulen benötigt.<br />
<br />
=== Unterschied presenced / lepresenced / collectored ===<br />
presenced und lepresenced sind Programme, welche in regelmäßigen Abständen nach Bluetooth-Geräten suchen. Sobald ein Gerät, welches vorab definiert wurde, gefunden wird, wechselt der Status des Geräts in FHEM auf Anwesend. Der Unterschied zwischen presenced und lepresenced ist, dass lepresenced insbesondere für [https://de.wikipedia.org/wiki/Bluetooth_Low_Energy|Bluetooth-LE-Device] ist und presenced für "normale" Bluetooth-Geräte. <br />
<br />
collectored wiederum ist ein Programm, welches mehrere Pis verbindet und auf allen den aktuellen Status von presenced/lepresenced abfragt. Ist das gesuchte Bluetooth-Gerät auf einem der Pi anwesend, so wird es auch in der definierten Hauptinstanz auf anwesend gesetzt. Zusätzlich wird der Pi auf dem das Gerät gefunden wurde als Reading angegeben. <br />
<br />
<br />
<br />
<br />
=== Installation von (le)presenced ===<br />
Diese Anleitung ist sowohl für presenced, als auch für lepresenced gültig. Einfachheitshalber wird nur lepresenced erwähnt, sämtliche Schritt gehen jedoch auf mit presenced, wobei einfach die genannten Daten durch presenced ersetzt werden müssen.<br />
<br />
Die Software lepresenced kann aktuell über drei Varianten installiert werden. Dabei ist die bevorzugte Variante (Variante 1) die Installation über das bereitgestellte .deb-Paket.<br />
Die Variante 2 setzt voraus, dass im FHEM contrib Verzeichnis (/opt/fhem/contrib) die aktuelle Version des .deb-Pakets liegt. Die Variante 3 ist dafür gedacht, wenn man keine .deb-Pakete installieren kann/will oder es aus anderen Gründen nicht funktioniert. Es wird davon abgeraten die Variante 3 zu verwenden. Vollständigkeithalber wird sie aber aufgeführt.<br />
<br />
===== Installation per .deb-Paket =====<br />
<br />
Die bevorzugte Variante ist die Installation von lepresenced durch die passenden .deb Pakete.<br />
{{Randnotiz|RNText=Bei einem Upgrade einer älteren Version reicht es, das neue .deb Paket mit<br />
:<code>sudo dpkg -i lepresenced-X.XX-X.deb</code><br />
zu aktualisieren}} <br />
<br />
'''1.Variante:'''<br />
Herunterladen der aktuellen lepresenced-0.83-3.deb (Stand August 2017) Datei über den Webbrowser <br />
[https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/PRESENCE/deb/ SVN-Repository]. Im SVN die passende Datei auswählen und in der folgende Webseite den Link unter:<br />
<pre><br />
Download in other formats:<br />
Original Format <br />
</pre><br />
anklicken und die Datei herunterladen.<br />
Die Datei kann jetzt auf den RPi kopiert und mit folgenden Befehlen ausgeführt werden (ggf. Berechtigungen anpassen). <br />
<br />
Alternativ per wget Befehl direkt auf den RPi (aktuelle Versionsnummer beachten)<br />
https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/PRESENCE/deb/lepresenced-0.83-3.deb<br />
<br />
'''2.Variante:''' (zu Verwenden, wenn es Probleme bei Variante 1 gibt)<br />
Herunterladen aus dem fhem contrib Verzeichnis:<br />
Hierzu muss das contrib auf dem aktuellen Stand sein. Dazu wird die Installation von subversion (normal bereits vorhanden) benötigt.<br />
<br />
sudo apt-get install subversion<br />
<br />
Danach kann per <br />
sudo svn checkout https://svn.fhem.de/fhem/trunk/fhem/contrib svnrepo<br />
<br />
Das aktuelle Repository auf den Pi heruntergeladen werden. Danach sollte im gewählten Verzeichnis die eingecheckten Dateien verfügbar sein.<br />
/opt/fhem/svnrepo/PRESENCE/deb <br />
<br />
<br />
''' Installation der Variante 1 oder 2 '''<br />
<br />
Egal welche Variante gewählt wurde, kann nun mit folgenden Befehlen das Paket installiert werden. Bitte Pfade ggf. anpassen.<br />
<br />
'''Wichtig''': Das '''Paket''' hat eine ca. Größe von '''6,5Kb'''. Ab und an gibt es wohl Probleme mit der Installation, wodurch die Datei 11,5kb groß wird.<br />
Diese Datei lässt sich nicht Installieren. In diesem Fall das Paket bitte mit der Variante 1 und dem Bereich "Download in other formats" herunterladen.<br />
<br />
sudo dpkg -i lepresenced-0.83-3.deb<br />
<br />
sudo apt-get -f install<br />
<br />
Die Ausgabe der Installation sollte am Ende ein [ ok ] Starting lepresenced (via systemctl): lepresenced.service. ausgeben.<br />
<br />
<pre><br />
Paketlisten werden gelesen... Fertig<br />
Abhängigkeitsbaum wird aufgebaut. <br />
Statusinformationen werden eingelesen.... Fertig<br />
Abhängigkeiten werden korrigiert ... Fertig<br />
Die folgenden zusätzlichen Pakete werden installiert:<br />
bluez-hcidump<br />
Die folgenden NEUEN Pakete werden installiert:<br />
bluez-hcidump<br />
0 aktualisiert, 1 neu installiert, 0 zu entfernen und 0 nicht aktualisiert.<br />
1 nicht vollständig installiert oder entfernt.<br />
Es müssen 157 kB an Archiven heruntergeladen werden.<br />
Nach dieser Operation werden 490 kB Plattenplatz zusätzlich benutzt.<br />
Möchten Sie fortfahren? [J/n]<br />
Holen: 1 http://archive.raspberrypi.org/debian/ jessie/main bluez-hcidump armhf 5.23-2+rpi2 [157 kB]<br />
Es wurden 157 kB in 0 s geholt (921 kB/s).<br />
Vormals nicht ausgewähltes Paket bluez-hcidump wird gewählt.<br />
(Lese Datenbank ... 42033 Dateien und Verzeichnisse sind derzeit installiert.)<br />
Vorbereitung zum Entpacken von .../bluez-hcidump_5.23-2+rpi2_armhf.deb ...<br />
Entpacken von bluez-hcidump (5.23-2+rpi2) ...<br />
Trigger für man-db (2.7.0.2-5) werden verarbeitet ...<br />
bluez-hcidump (5.23-2+rpi2) wird eingerichtet ...<br />
lepresenced (0.82-1) wird eingerichtet ...<br />
[ ok ] Starting lepresenced (via systemctl): lepresenced.service.<br />
</pre><br />
<br />
<br />
'''3.Variante:'''<br />
<br />
Bei dieser Variante wird das aktuellste lepresenced Skript aus github heruntergeladen. Das bedeutet, dass jegliche Konfiguration wie automatischer Start, Berechtigungen etc. <br />
manuell konfiguriert werden muss. Diese Variante eignet sich nur für diejenigen, die keine .deb-Pakete installieren wollen/können oder die genau Wissen, was sie tun!<br />
<pre><br />
https://github.com/mhop/fhem-mirror/blob/master/fhem/contrib/PRESENCE/lepresenced<br />
</pre><br />
<br />
Zur "Installation" des Skripts folgendermaßen vorgehen:<br />
Unter /fhem manuell den Ordner „script“ anlegen:<br />
<pre><br />
mkdir script<br />
</pre><br />
Datei lepresenced reinkopieren und ausführbar machen:<br />
<pre><br />
sudo chmod +x /opt/fhem/script/lepresenced<br />
sudo chgrp -cR dialout lepresenced<br />
</pre><br />
Skript erstmalig starten:<br />
<pre><br />
sudo ./lepresenced --loglevel LOG_EMERG -d<br />
</pre><br />
Kommt beim Starten des Skript eine Fehlermeldung, müssen die Abhängigkeiten aufgelöst werden.<br />
<pre><br />
Can't locate Net/Server/Daemonize.pm in @INC (@INC contains: /etc/perl /usr/local/lib/perl/5.14.2 /usr/local/share/perl/5.14.2 /usr/lib/perl5 /usr/share/perl5 / usr/lib/perl/5.14 /usr/share/perl/5.14 /usr/local/lib/site_perl .) at /opt/fhem/lepresenced line 17.<br />
BEGIN failed--compilation aborted at /opt/fhem/lepresenced line 17.<br />
</pre><br />
Um die Abhängigkeiten aufzulösen muss folgendes nachinstalliert werden und anschließend ein Reboot durchgeführt werden.<br />
<pre><br />
sudo apt-get install libnet-server-*<br />
</pre><br />
<br />
===== Einrichtung eines Bluetooth-Geräts über FHEM =====<br />
<br />
Nach dem letzten Schritt sind alle Bedingungen für eine abschließende Konfiguration eines BT-Geräts in FHEM abgeschlossen worden.<br />
Jetzt kann der zum Beispiel ein G-Tag dem FHEM-Server bekannt gemacht werden:<br />
<pre><br />
-- Name Modul Modus MAC vom Gtag IP vom PI Port Abfragezeit in Sekunden<br />
define MeinGtAG PRESENCE lan-bluetooth xx:xx:xx:xx:xx:xx 127.0.0.1:5333 120<br />
</pre><br />
<br />
'''Wichtig ist den angegeben Port zu unterscheiden. Für presenced muss der Port 5111 genommen werden, für lepresenced der Port 5333.'''<br />
Den absent und present Mode kann man einfach testen, in dem man den Gtag mit Alufolie einwickelt.<br />
<br />
Diese Variante sollte eingesetzt werden, wenn nur ein Pi nach Bluetooth-Geräten sucht. Möchte man mehr als ein Gerät nutzen um zum Beispiel eine größere Fläche abzudecken so muss mit collectored gearbeitet werden.<br />
<br />
<br />
=== Alle Räume gemeinsam ansprechen mittels collectord ===<br />
Um zwei Presence.- oder lepresenced Installationen zu verbinden wird der collectored Daemon von Markus Bloch benötigt. Dieser kennt alle presenced-Installationen im Netzwerk und führt eine koordinierte Suche nach den gewünschten Geräten durch. Sobald ein Gerät in einem Raum erkannt wurde, meldet der collectord den Status einschließlich der Angabe des Raumes, in dem das Gerät erkannt wurde.<br />
<br />
<br />
[[Datei:Presence_Collectord_Uebersicht.jpg|200px|thumb|left|Schematische Darstellung Presence und Collectord, Danke an dtavb]]<br />
Auf Basis folgender Skizze wird die Einrichtung und der Betrieb der Anwesenheitserkennung und Überwachung <p></p><br />
mit dem PRESENCE-Modul sowie dem Skript (.deb-Paket) lepresenced beschrieben. Zusätzlich wird für die Verbindung <p></p><br />
mehrere lepresenced Instanzen der collectord verwendet.<p></p><br />
Diese Skizze dient als Basis für alle genannten Konfigurationen innerhalb dieses Artikels.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
==== Aufbau ====<br />
; RPi1 (Hautpinstanz): <br />
: FHEM Installation<br />
: presence/lepresenced Installation <br />
: collectord installation<br />
: Sämtliche Bluetooth-Geräte in FHEM definiert<br />
; RPi2 (Zweitsystem): <br />
: FHEM installation<br />
: presence/lepresenced Installation<br />
: Sämtliche Bluetooth-Geräte in FHEM definiert<br />
<br />
<br />
==== Installation per .deb-Paket ====<br />
collectord wird heruntergeladen und installiert:<br />
https://svn.fhem.de/trac/export/HEAD/trunk/fhem/contrib/PRESENCE/deb/collectord-1.7.deb (Stand Januar 2017)<br />
<pre><br />
sudo dpkg -i collectord-1.7.deb<br />
</pre><br />
<br />
Nach der Installation befindet sich im Verzeichnis: /etc/collectord.conf die Konfigurationsdatei für das collectord.<br />
<br />
==== Konfiguration auf Shellebene ==== <br />
<pre><br />
sudo vi /etc/collectord.conf<br />
</pre><br />
<br />
Diese Datei muss jetzt nach folgender Vorlage angepasst werden.<br />
<pre><br />
# room definition<br />
#[room-name] # name of the room<br />
#address=192.168.0.10 # ip-address or hostname<br />
#port=5111 # tcp port which should be used (5111 is default)<br />
#presence_timeout=120 # timeout in seconds for each check when devices are present<br />
#absence_timeout=20 # timeout in secondsfor each check when devices are absent<br />
<br />
[RPi1] # Name (wird als Reading room bei den BT-Tags angezeigt) der presence Instanze<br />
address=127.0.0.1 # Lokale Adresse RPi1 , da hier das Collectord später laufen soll!<br />
port=5333 # Port der Presence Installation <br />
presence_timeout=60 # Selbstgewaelte Pruefintervalle<br />
absence_timeout=60 # Selbstgewaelte Pruefintervalle<br />
<br />
[RPi2] # Name (wird als Reading room bei den BT-Tags angezeigt) der presence Instanze<br />
address=192.168.178.127 # IP-Adresse der Instanz, wo nur das Presence laueft, also RPi2<br />
port=5333 # Port der Presence Installation <br />
presence_timeout=60 # Selbstgewaelte Pruefintervalle<br />
absence_timeout=60 # Selbstgewaelte Pruefintervalle<br />
</pre><br />
<br />
Hinweis: <br />
* Es dürfen keine [Namen] mit Leerzeichen verwendet werden<br />
* Der angegebene Port richtet sich danach, ob auf dem Pi presenced (Port 5111) oder lepresenced (Port 5333) nach dem Bluetooth-Gerät sucht<br />
<br />
<br />
==== Konfiguration in FHEM ==== <br />
;RPi1<br />
:define Gtag PRESENCE lan-bluetooth XX:XX:XX:XX:XX:XX 127.0.0.1:5222 60 Hinweis: (Der Port ist der, des Collectord!! Standard 5222)<br />
;RPi2<br />
:define Gtag PRESENCE lan-bluetooth XX:XX:XX:XX:XX:XX 192.168.178.127:5222 60 Hinweis: (Der Port ist der, des Collectord!! Standard 5222 - die IP-Adresse von die von RPi1)<br />
<br />
<br />
Nach der Konfiguration kann der Daemon gestartet werden.<br />
Sobald das Bluetoothgerät irgendwo in der Wohnung erkannt wurde, meldet der Collectord dies sofort <br />
an FHEM und teilt den Raum mit in dem es erkannt worden ist. Diese Information wird im Reading "rooms" des jeweiligen BT-Gerätes dargestellt.<br />
<br />
Zum testen sollte collectored einmalig manuell gestartet werden. Dies hat den Vorteil, dass man nochmal den Port des collectored prüfen kann, dieser steht in der Zeile <pre>created socket on 0.0.0.0 with port 5333</pre> und man sehen kann, ob der collectored richtig startet, oder Fehler auswirft. Gestartet wird mit folgendem Kommando:<br />
<pre><br />
sudo /usr/bin/perl /usr/sbin/collectord -vv -c /etc/collectord.conf<br />
</pre><br />
Die Ausgabe sieht wie folgt aus:<br />
<pre><br />
2017-04-02 17:52:55 - =================================================<br />
2017-04-02 17:52:55 - started with PID 15554<br />
2017-04-02 17:52:55 - reading configuration file<br />
2017-04-02 17:52:55 - no config errors found<br />
2017-04-02 17:52:55 - forked with PID 15556<br />
2017-04-02 17:52:56 - created socket on 0.0.0.0 with port 5333<br />
2017-04-02 17:53:20 - new connection from 127.0.0.1:48656<br />
2017-04-02 17:53:20 - created thread 1 for processing device 7C:2F:80:E1:14:31 in room RPi2 for peer 127.0.0.1 (UUID: d0beb79dd4771532eb5e207c7bf31788)<br />
2017-04-02 17:53:20 - created thread 2 for processing device 7C:2F:80:E1:14:31 in room RPi1 for peer 127.0.0.1 (UUID: d0beb79dd4771532eb5e207c7bf31788)<br />
2017-04-02 17:53:20 - new connection from 127.0.0.1:48662<br />
2017-04-02 17:53:20 - new connection from 127.0.0.1:48664<br />
2017-04-02 17:53:20 - created thread 3 for processing device 7C:2F:80:ED:BC:F7 in room RPi2 for peer 127.0.0.1 (UUID: 7495a112063d5db45e6335d3fe305e36)<br />
2017-04-02 17:53:20 - created thread 4 for processing device 7C:2F:80:ED:BC:F7 in room RPi1 for peer 127.0.0.1 (UUID: 7495a112063d5db45e6335d3fe305e36)<br />
2017-04-02 17:53:20 - created thread 5 for processing device 7C:2F:80:E1:2A:4D in room RPi2 for peer 127.0.0.1 (UUID: c228f8d4d33b06787f995c7903c02760)<br />
2017-04-02 17:53:20 - created thread 6 for processing device 7C:2F:80:E1:2A:4D in room RPi1 for peer 127.0.0.1 (UUID: c228f8d4d33b06787f995c7903c02760)<br />
2017-04-02 17:53:22 - new connection from 192.168.xxx.xxx:51638<br />
2017-04-02 17:53:22 - created thread 7 for processing device 7C:2F:80:E1:14:31 in room RPi2 for peer 192.168.xxx.xxx (UUID: 5db7012e709d6dc2fcd8159fc0344e40)<br />
2017-04-02 17:53:22 - created thread 8 for processing device 7C:2F:80:E1:14:31 in room RPi1 for peer 192.168.xxx.xxx (UUID: 5db7012e709d6dc2fcd8159fc0344e40)<br />
2017-04-02 17:53:22 - new connection from 192.168.xxx.xxx:51640<br />
2017-04-02 17:53:22 - created thread 9 for processing device 7C:2F:80:ED:BC:F7 in room RPi2 for peer 192.168.xxx.xxx (UUID: c4b4d7c654132cf88e8c1fec3a956d3d)<br />
2017-04-02 17:53:23 - created thread 10 for processing device 7C:2F:80:ED:BC:F7 in room RPi1 for peer 192.168.xxx.xxx (UUID: c4b4d7c654132cf88e8c1fec3a956d3d)<br />
2017-04-02 17:53:29 - new connection from 192.168.xxx.xxx:51642<br />
2017-04-02 17:53:29 - created thread 11 for processing device 7C:2F:80:E1:2A:4D in room RPi2 for peer 192.168.xxx.xxx (UUID: ecd7081e5ae3a0d8e735c8750cb116a1)<br />
2017-04-02 17:53:29 - created thread 12 for processing device 7C:2F:80:E1:2A:4D in room RPi1 for peer 192.168.xxx.xxx (UUID: ecd7081e5ae3a0d8e735c8750cb116a1)<br />
</pre><br />
<br />
Wenn das Log wie oben abgebildet aussieht wurde alles richtig gemacht und unter dem Device in FHEM erscheint ein neues Reading "rooms" mit dem Wert der Erkannten PRESENCE Installation.<br />
<br />
'''Verhalten presence timeout im zusammenhang mit dem Attribut "absenceThreshold" der PRESENCE Konfiguration in FHEM'''<br />
<br><br />
In der collectord.conf sind presence_timeout und absence_timeout für den jeweiligen Raum konfiguriert.<br />
Das bedeutet, sobald irgendein Gerät in diesem jeweiligen Raum anwesend/abwesend ist, wird das jeweilige Timeout an den verbundenen presenced/lepresenced geschickt um damit das Check-Interval entsprechend zu ändern.<br />
<br />
In der PRESENCE-Definition kann man ebenfalls ein absence_timeout/presence_timeout setzen. Sobald sich der Zustand ändert,<br />
wird auch das jeweilige Timeout an den collectord gesandt. Dies hat aber auf die Checks in den jeweiligen Räumen und damit der collectord.conf keinen Einfluss.<br />
Der collectord schickt ein Statusupdate an PRESENCE nur, wenn das vorgegebene Timeout (von PRESENCE) erreicht ist und keine Statusänderung stattfand.<br />
Sobald eine Änderung des Status erfolgt wird natürlich sofort der Status an PRESENCE geschickt.<br />
<br />
Das Attribut absenceThreshold/presenceThreshold funktioniert nachwievor. Hier ist nur wichtig wie man die Timeouts sowohl in PRESENCE als auch collectord.conf setzt.<br />
<br />
'''Das Reading "room" bei einer PRESENCE Definition und der Zusammenhang zu collectord'''<br />
<br><br />
Wenn ein BT LE Empfänger in mehr als einem Raum detektiert wird, führt der aktuellste collectord (aus dem SVN) eine RSSI-Erkennung durch. Sofern alle Räume den Empfangspegel (RSSI) ermitteln können, wird der Raum mit dem besten Empfangspegel als Raum für das "room"-Reading ausgewählt. Der lepresenced in aktueller Version von PatrickR gibt immer den Empfangspegel aus.<br />
<br />
==== Automatischer Start ====<br />
Wenn das Collectord per .deb Paket installiert wurde, startet es automatisch bei einem Reboot mit.<br />
Manuell Starten als Daemon mit:<br />
<pre><br />
sudo /usr/bin/perl /usr/sbin/collectord -c /etc/collectord.conf -d -v -l /var/log/collectord.log<br />
</pre><br />
<br />
== Batterieüberwachung ==<br />
<br />
<br />
=== Batterieüberwachung mit dem Modul BleTagBattery ===<br />
{{Infobox Modul<br />
|ModPurpose=Anwesenheitserkennung<br />
|ModType=h<br />
<!-- |ModCmdRef= --><br />
|ModTechName=74_BleTagBattery<br />
|ModOwner=mumpitzstuff<br />
}}<br />
Mit dem Modul BleTagBattery - können die Batteriestati aller BT-LE Devices gelesen werden.<br />
Es wird das batteryLevel und battery angelegt welches als BT-LE Tags an einer PRESENCE-Installation registriert wurden.<br />
<br />
Vorraussetzung und Installation:<br />
<br />
Bluez und Gattool<br />
sudo apt-get install bluez<br />
<br />
Das Gattool ist in den Installationen von Bluez inbegriffen.<br />
<br />
<br />
Hinzufügen des githup für das Modul<br />
update add http://raw.githubusercontent.com/mumpitzstuff/fhem-BleTagBattery/master/controls_bletagbattery.txt<br />
update all<br />
restart fhem: shutdown restart<br />
BT-LE tags muss an einer PRESENCE-Installation des type "lan-bluetooth" registriert sein.<br />
<br />
<br />
Nach dem Neustart von FHEM kann das Modul definiert werden:<br />
define a new device: define <name of device> BleTagBattery<br />
<br />
Das Modul versucht in der Standardkonfiguration alle 6 Stunden die BT-LE Devices zu erreichen und das Reading batteryLevel und battery zu aktualisieren.<br />
Das Update kann auch manuell mit dem folgenden Befehl erzwungen werden<br />
<br />
set <name of device> statusRequest.<br />
<br />
Weiter Informationen und Disskussionen können dem eigentlichen [https://forum.fhem.de/index.php?topic=68104.0 Forumsbeitrag] entnommen werden,<br />
<br />
=== Batterieüberwachung (aktuell nur G-Tags) ===<br />
<br />
Leider überträgt der G-Tag nach der Einrichtung als Device in FHEM kein Reading mit seinem aktuellen Batteriestatus.<br />
Dem wurde mit Hilfe des Forum Abhilfe geschaffen.<br />
Im Folgenden wird erläutert wie die Batterieüberwachung eingerichtet werden kann.<br />
<br />
'''Voraussetzung:'''<br />
<br />
bc - Basiscalculator [https://packages.debian.org/de/sid/bc Bc-Paket]<br />
<pre> sudo apt-get install bc </pre><br />
<br />
Anlegen eines Shellskript auf dem Raspberry System. <br />
Die Parameter <<MAC-Adresse>> und <<TagName>> müssen durch die Werte des auszulesenden G-Tags ersetzt werden.<br />
<pre><br />
#!/bin/bash<br />
stringZ=$(sudo gatttool -b 5C:2B:80:C1:14:41 --char-read --handle=0x001b)<br />
stringZ=${stringZ:33:2}<br />
stringZ=$(echo "$stringZ" | tr a-f A-F)<br />
decimal=$(echo "ibase=16; $stringZ" | bc)<br />
perl /opt/fhem/fhem.pl 7072 "setreading MeinGtag Batterie $decimal"<br />
</pre><br />
<br />
Dem Device in FHEM (hier MeinGtag) ein userReading mit dem Namen '''Batterie''' hinzufügen.<br />
Das Shellskript mit folgendem Befehl starten:<br />
<pre><br />
./GtagBatterie.sh<br />
</pre><br />
'''Wichtig ist hierbei,''' dass Skript mit "./" und nicht mit "sh" aufzurufen. Beim Aufruf mit "sh GtagBatterie.sh" produziert es einen Fehler<br />
<pre>GtagBatterie.sh: 3: GtagBatterie.sh: Bad substitution </pre><br />
<br />
Das Reading wird auf den ausgelesenen Wert der Batterie gesetzt. <br />
<br />
Hinweis: Es sollte für jeden G-Tag ein eigenes Skript abgelegt werden. Das Skript kann per crontab oder fhem Kommando (system) regelmäßig aufgerufen werden.<br />
<br />
=== Batterieüberwachung (alle Devices vom Typ "MODE=lan-bluetooth") ===<br />
<br />
Es gibt eine weitere Möglichkeit um den Batteriestatus von LE Devices abzurufen und in FHEM als Reading darzustellen.<br />
Dabei wird der Batteriezustand für alle LE Devices, die bereits in FHEM konfiguriert sind und per lepresenced überwacht werden, automatisch in einem shell-Script ermittelt.<br />
Näheres dazu im Forumartikel {{Link2Forum|Topic=56960|LinkText=Erweiterung: Anwesenheitserkennung/Batterieüberwachung}}.<br />
<br />
Vorteile:<br />
* Automatische Ermittlung aller in FHEM konfigurierten LE Devices<br />
* Möglichkeit, diese Devices alternativ manuell im Script einzutragen<br />
* Es werden nur Devices abgefragt, die im Status "present" sind, also mit ziemlicher Sicherheit auch verfügbar sind<br />
* Ein eventuell auf dem FHEM telnet-Port gesetztes Passwort kann im Script hinterlegt werden<br />
<br />
'''Voraussetzung:'''<br />
<br />
'''Funktionierendes lepresenced''' - siehe [[Anwesenheitserkennung#Anleitung_f.C3.BCr_ein_LE_Device_.28z.B._Gtags.2CPebbles_etc..29|Anleitung für ein LE Device (z.B. Gtags,Pebbles etc.)]]<br />
<br />
'''socat''' - TCP port forwarder<br />
<pre><br />
sudo apt-get update && sudo apt-get install socat<br />
</pre><br />
<br />
<br />
'''gawk''' - Zum extrahieren der Daten<br />
<pre><br />
sudo apt-get update && sudo apt-get install gawk<br />
</pre><br />
<br />
'''gatttool''' - Bestandteil von bluez <br />
<br />
gatttool ist auf den meisten Distributionen im bluez-Paket, allerdings nicht bei Opensuse. Dort muss man das Sourcepaket von bluez installieren und selbst kompilieren.<br />
gatttool sollte dann nach /usr/bin oder /usr/local/bin kopiert werden,<br />
<br />
<br />
Zusätzlich zu den notwendigen Erweiterungen werden für die Ausführung von gatttool '''Root-Rechte benötigt'''!<br />
<br />
Das Script selbst gibt es hier: [https://raw.githubusercontent.com/micky0867/lebattery/master/lebattery lebattery]<br />
<br />
Am Besten unter /opt/fhem/script/lebattery speichern und ausführbar machen:<br />
<syntaxhighlight lang="bash"><br />
sudo su -<br />
mkdir /opt/fhem/script<br />
cd /opt/fhem/script<br />
wget https://raw.githubusercontent.com/micky0867/lebattery/master/lebattery<br />
chmod 755 lebattery<br />
</syntaxhighlight><br />
<br />
Je nach Bedarf können im Script noch die folgenden 3 Parameter angepasst werden:<br />
<syntaxhighlight lang="bash"><br />
# If allowed_telnetPort is protected by a password, add the password here<br />
TELNETPASSWORD=""<br />
# Attribute for batterylevel in FHEM<br />
ATTRIBUT="batterylevel"<br />
# Use this, if you dont want the script to determine the tags on its own<br />
LETAGS=""<br />
</syntaxhighlight><br />
<br />
Das Skript wird dann unter root folgendermaßen gestartet:<br />
<pre><br />
/opt/fhem/script/lebattery -v<br />
</pre><br />
<br />
Ausgabe des Skripts, wenn es mit dem Verbose Parameter -v gestartet wird.<br />
<br />
Beide Devices sind vom Typ NUT mini, das Device mit dem FHEM-Namen '''nut_Micky''' ist im Status '''absent'''. Das zweite Device ist im Status '''present'''.<br />
<pre><br />
Determining address for nut_Micky ...<br />
nut_Micky is in state absent, no further action required<br />
<br />
Determining address for nut_Test ...<br />
Fetching batterylevel for nut_Test (F3:44:04:81:54:89) ...<br />
Setting batterylevel for nut_Test to 100%<br />
</pre><br />
<br />
Mein crontab-Eintrag (User root) sieht so aus:<br />
<pre><br />
3 3 * * * /opt/fhem/script/lebattery -v >/opt/fhem/script/lebattery.log 2>&1<br />
</pre><br />
Damit wird jeden Morgen um 3 Minuten nach 3 Uhr der Zustand der Batterien aller Devices ermittelt und in FHEM abgespeichert.<br> <br />
Bevor man das mit crontab macht, sollte man allerdings zunächst sicher stellen, dass es auch ohne crontab funktioniert....<br />
<br />
Bei Problemen kann man auch erstmal schauen, ob das mit dem gattool überhaupt funktioniert:<br />
<pre><br />
gatttool -t <Typ> -b <MAC-Adresse> --char-read --uuid 0x2a19<br />
<br />
handle: 0x0017 value: 64<br />
</pre><br />
In diesem Fall hat die Batterie noch 100% (hex 64).<br><br />
Der Typ ist abhängig vom Hersteller und kann public (G-Tags) bzw. random (Nut) sein. Im Zweifelsfall beides ausprobieren.<br />
<br />
= Beispiele =<br />
== Anwesenheitserkennung / Anwesenheitsbenachrichtigung mit G-Tags ==<br />
Ein Skript zur Nutzung der Gigaset G-TAGs zur Alarmierung bei öffnen und schließen von Türen und zur Anwesenheitserkennung, um die Alarmierung zu aktivieren bzw. deaktivieren. <br />
Es kann verwendet werden um die Anwesenheit von mehrern Personen im Haushalt zu erkennen. Dabei wird eingeschränkt, dass nur bestimmte Personen die Alarmierung aktivieren können ( Eltern/Kind -Beziehung ).<br />
Des Weiteren werden im Beispiel die Eltern benachrichtigt wenn eins der Kinder das Haus verlässt und die Eltern nicht anwesend sind.<br />
<br />
{{Randnotiz|RNText=Namen der G-Tags in den Skripten bitte anpassen!}}<br />
<br />
Für die ''Notify'' und die ''RESIDENTS-Erweiterung'' wird ein Dummy benötigt.<br />
<pre><br />
define Alarm dummy<br />
attr Alarm devStateIcon aktiv:secur_locked@red inaktiv:secur_open@lightgreen<br />
attr Alarm eventMap on:aktiv off:inaktiv<br />
attr Alarm setList on off<br />
attr Alarm webCmd aktiv:inaktiv<br />
attr Alarm room Alarm<br />
</pre><br />
<br />
<br />
=== Mit Notify ===<br />
<pre><br />
gtag.*.presence:.* {Anwesenheit_check("$EVTPART1", "$NAME")}<br />
</pre><br />
<br />
Code für die 99_myUtils.pm<br />
<pre><br />
### GTAG ANWESENHEITS CHECK<br />
sub Anwesenheit_check($$) {<br />
my ($EVENT, $NAME) = @_;<br />
<br />
# gtag_rot - Alias Marco<br />
# gtag_schwarz - Alias Ulli<br />
# gtag_gruen - Alias Frida<br />
# gtag_orange - Alias Hannah<br />
<br />
my $RESIDENT = "rr_"; # Alle GTAGs sind Standardmäßig Residents Roommate<br />
# $RESIDENT = "rg_" if (($NAME eq "gtag_orange") xor ($NAME eq "gtag_weis")); # Hier nur Gäste (Roomguest) Auskommentiert, da ich es so nicht brauche<br />
my $ROOMMATE = ("$RESIDENT" . "$NAME"); # Residentsname zusammenbauen<br />
my $ALIASNAME = AttrVal($ROOMMATE,'alias',$ROOMMATE); # ALIAS des Roommates auslesen<br />
<br />
my $GTAG1 = Value('gtag_rot'); # ELTERN<br />
my $GTAG2 = Value('gtag_schwarz'); # ELTERN<br />
<br />
my $STATUS = "wahrscheinlich gerade los";<br />
$STATUS = "anwesend" if ($EVENT eq "present"); # Status: anwesend<br />
$STATUS = "unterwegs" if ($EVENT eq "absent"); # Status: unterwegs<br />
<br />
Log 1, "$ALIASNAME ist $STATUS."; # LOG Eintrag erzeugen<br />
<br />
if (($EVENT eq "present" && Value("Alarm") eq "aktiv") && ($NAME eq "gtag_gruen" xor $NAME eq "gtag_orange")) {<br />
fhem("set teleBot send ALARMIERUNG BLEIBT AKTIV: $ALIASNAME ist da..."); # Telegram<br />
# fhem("set Infopush msg 'ALARMIERUNG BLEIBT AKTIV' '$ALIASNAME ist da...'"); # Pushover<br />
}<br />
elsif (($EVENT eq "present" && Value("Alarm") eq "aktiv") && ($NAME eq "gtag_rot" xor $NAME eq "gtag_schwarz")) {<br />
fhem("set teleBot send ALARMIERUNG INAKTIV: $ALIASNAME ist da...; set Alarm inaktiv"); # Telegram<br />
# fhem("set Infopush msg 'ALARMIERUNG INAKTIV' '$ALIASNAME ist da...'; set Alarm inaktiv"); # Pushover<br />
}<br />
elsif (($EVENT eq "absent" && Value("Alarm") eq "aktiv") && ($NAME eq "gtag_gruen" xor $NAME eq "gtag_orange")) {<br />
fhem("set teleBot send ALARMIERUNG BLEIBT AKTIV: $ALIASNAME hat das Haus verlassen."); # Telegram<br />
# fhem("set Infopush msg 'ALARMIERUNG BLEIBT AKTIV' '$ALIASNAME hat das Haus verlassen.'"); # Pushover<br />
} <br />
elsif (($EVENT eq "absent" && Value("Alarm") eq "inaktiv") && ($GTAG1 eq "absent" && $GTAG2 eq "absent")) {<br />
fhem("set Alarm aktiv; set teleBot send ALARMIERUNG AKTIV: $ALIASNAME hat das Haus verlassen."); # Telegram<br />
# fhem("set Alarm aktiv; set Infopush msg 'ALARMIERUNG AKTIV' '$ALIASNAME hat das Haus verlassen.' '' 0 ''"); # Pushover<br />
}<br />
}<br />
</pre><br />
<br />
<br><br />
<br />
=== Mit Notify und Integration des RESIDENTS-MODUL ===<br />
<br />
Der hier beschriebene Code erweitert die Funktionen unter dem Punkt 5.93.<br />
Das Notify muss daher mit der folgenden Zeile erweitert werden.<br />
<br />
<pre><br />
define Alarm_AnwesenheitCheck notify gtag.*.presence:.* { Anwesenheit_check("$EVTPART1", "$NAME"), Anwesenheit_check_resi("$NAME") }<br />
</pre><br />
<br />
Zusätzlicher Code für die 99_myUtils.pm um die RESIDENTS Funktion nutzen zu können:<br />
<pre><br />
### RESIDENTS<br />
sub Anwesenheit_check_resi($) {<br />
my ($NAME) = @_;<br />
my $ALIASNAME = AttrVal($NAME,'alias',$NAME); # ALIASNAME des GTAGs auslesen<br />
<br />
my $RESIDENT = "rr_"; # Als Standard sind alle GTAGs Roommates<br />
$RESIDENT = "rg_" if (($NAME eq "gtag_orange") xor ($NAME eq "gtag_weis")); # Hier nur GTAG Namen der Gäste (Roomguest)<br />
my $ROOMMATE = ("$RESIDENT" . "$ALIASNAME"); # Residentsname zusammenbauen<br />
<br />
if (ReadingsVal($NAME,'presence',$NAME) eq "absent") {<br />
fhem("set $ROOMMATE absent"); # Resisents Status von Roommates setzen<br />
}<br />
elsif(ReadingsVal($NAME,'presence',$NAME) eq "present") {<br />
fhem("set $ROOMMATE home"); # Resisents Status von Roommates setzen<br />
}<br />
}<br />
</pre><br />
<br><br />
<br />
=== Mit Notify und Fenster/Tür. -Kontakt Überwachung ===<br />
<br />
Erweiterung für die Überwachung von Fenster/Tür. -Kontakten. Dazu sind zwei weitere Notifys notwendig die auf die Trigger der Kontakte regagieren<br />
und so eine weitere Funktion in der 99_myUtils.pm ansprechen. Die Notifys triggern auf Kontakte die mit dem Namen Kontakt* beginnen.<br />
Sollten die eigenen Fenster/Tür. -Kontakt anderen Namen besitzen, müssen die Skripte dementsprechend angepasst werden.<br />
<pre><br />
define Alarm_Kontaktmeldung notify Kontakt.*:contact:.* {Kontakt_Meldung("$EVTPART1", "$NAME")}<br />
</pre><br />
<pre><br />
define Alarm_Sabotagealarm notify Kontakt.*.sabotageError:.on {Kontakt_Sabotage("$EVTPART1", "$NAME")}<br />
</pre><br />
<br />
Zusätzlicher Code für die 99_myUtils.pm um die TÜRKONTAKTE-Meldung nutzen zu können:<br />
<pre><br />
### TÜRKONTAKTE-Meldung/Zustand<br />
sub Kontakt_Meldung($$) {<br />
my ($EVENT, $NAME) = @_;<br />
my $ALIASNAME = AttrVal($NAME,'alias',$NAME);<br />
Log 1, "$ALIASNAME wurde $EVENT";<br />
if (ReadingsVal("Alarm", "state", "on") eq "on") {<br />
fhem("set teleBot send $ALIASNAME wurde $EVENT"); # Nachricht über Telegram<br />
# fhem("set Infopush msg '$ALIASNAME' '$ALIASNAME wurde $EVENT'"); # Nachricht über Pushover<br />
}<br />
}<br />
<br />
### TÜRKONTAKTE-Sabotagealarm<br />
<br />
sub Kontakt_Sabotage($$) {<br />
my ($EVENT, $NAME) = @_;<br />
my $ALIASNAME = AttrVal($NAME,'alias',$NAME);<br />
Log 1, "$ALIASNAME meldet Sabotagealarm";<br />
fhem("set teleBot send Alarm: $ALIASNAME meldet Sabotagealarm"); # Nachricht über Telegram<br />
# fhem("set Infopush msg 'Alarmanlage' '$ALIASNAME meldet Sabotagealarm' '' 2 ' ' 60 600 "); # Nachricht über Pushover<br />
}<br />
</pre><br />
<br><br />
<br />
=== Hinweis zur Benutzung / Fehlerhandling ===<br />
<br />
Der Alarm dummy hat den Zustand on:off. Die Bezeichnungen und Namen müssen 1:1 übernommen werden damit das Script funktioniert.<br />
Andernfalls müssen die Bezeichnungen für z.B. absent:unterwegs und present:anwesend - angepasst werden.<br />
Die Benachrichtigung kann aktuell per ''Telegram'' sowie ''Pushover'' ('''Achtung mit zweiterem sind Abokosten verbunden!''') realisiert werden.<br />
Diskussion zum Thema im Forum unter: {{Link2Forum|Topic=64080}}<br />
<br><br />
<br />
<br />
= Problemlösungen =<br />
Falls es '''Probleme beim Starten des Skripts''' gibt bzw. man das Skript ohne Reboot des Systems neustarten möchte, kann man dies per kill Befehl erledigen.<br />
<syntaxhighlight lang="bash"><br />
ps -ef | grep lepresenced<br />
sudo kill <pid><br />
</syntaxhighlight><br />
<br />
Debuglevel lepresenced setzen:<br />
{{Randnotiz|RNText=Um Debug-Meldungen zu bekommen (Vorsicht bei SD-Karten-Systemen wie dem RPi) - Hierbei werden die Schreibzyklen auf die SD-Karte erhöht.}}<br />
<br />
Der Log Level muss im lepresenced-Skript selbst verändert werden. Um den Log-Level auf INFO/WARNING/DEBUG zu setzen, dass Skript lepresenced mit einem Editor öffnen und die Stellen, wo LOG_WARNING zu finden sind durch den nötigen LOG-Eintrag ersetzen.<br />
<br />
<pre><br />
lepresenced --loglevel LOG_DEBUG<br />
</pre><br />
Nur das wichtigste Loggen:<br />
<pre><br />
lepresenced --loglevel LOG_WARNING<br />
</pre><br />
Keinerlei LOG-Einträge<br />
<pre><br />
lepresenced --loglevel LOG_EMERG<br />
</pre><br />
<br />
Bei '''Problemen mit der Batterieüberwachung''' der Tags kann die Pi Firmeware mit folgenden Befehl auf eine ältere Version zurückgesetzt werden.<br />
Fehlermeldung beim Aufruf des lebattery oder anderen Batterietestskripten:<br />
<pre>connect: Connection refused (111)</pre><br />
<br />
Lösung (vorübergehend) <br />
<pre><br />
sudo rpi-update 8521fd34c8f66b6d109acce943f6e25ec93ec005<br />
</pre><br />
<br />
Mehr dazu unter: {{Link2Forum|Topic=56960|Message=589165}}<br />
<br />
'''Das BT-Device ist ständig "absent"'''<br><br />
Eine Mögliche Lösung kann sein, dass Paket bluez-hcidump zu installieren. Das Werkzeug hcidump erlaubt die Beobachtung von Bluetooth-Aktivität.<br />
Dies ist nicht notwendig, wenn bereits bluez installiert ist, da dies Teil des bluez Paketes ist<br />
<pre><br />
sudo apt-get install bluez-hcidump<br />
</pre><br />
<br />
'''Fehler in Logdateien /var/log/syslog und /var/log/kernel'''<br />
Jul 29 15:08:11 raspberrypi kernel: [ 4905.634211] bt_err_ratelimited: 1 callbacks suppressed<br />
Jul 29 15:08:11 raspberrypi kernel: [ 4905.634231] Bluetooth: hci0 advertising data length corrected<br />
Jul 29 15:08:12 raspberrypi kernel: [ 4906.647350] Bluetooth: hci0 advertising data length corrected<br />
Jul 29 15:08:13 raspberrypi kernel: [ 4907.532081] Bluetooth: hci0 advertising data length corrected<br />
Jul 29 15:08:13 raspberrypi kernel: [ 4907.655564] Bluetooth: hci0 advertising data length corrected<br />
<br />
<br />
Die Ursache des Problems ist noch nicht ergründet, allerdings betrifft dies aktuell nur den RPi3. Die Fehlermeldungen werden in verschiedene log's geschrieben. Darunter maßgeblich "syslog" und "kern.log". <br />
<br />
Lösung (vorübergehend)<br />
Unterbinden der Einträge durch Anlage eines blocklist Eintrag:<br />
<br />
1. Unter "/etc/rsyslog.d" eine Datei erzeugen mit dem Namen "01-blocklist.conf"<br />
2. Inhalt: (Die Ausdrücke in den "" sind diejenigen, die aus dem log verschwinden sollen. - bei mir waren es die unten stehenden")<br />
:msg,contains,"Bluetooth: hci0 advertising data length corrected" stop<br />
:msg,contains,"bt_err_ratelimited:" stop<br />
3. Dienst neu starten "sudo service rsyslog restart"<br />
<br />
Weiter Infos werden im offiziellen Thema {{Link2Forum|Topic=28753|Message=499184|LinkText=hier}} diskutiert.<br />
<br />
Seit Version 0.82 kann es beim Start zu folgenden Meldungen im Log kommen. <br />
Sep 06 16:13:45 raspberrypi systemd[1]: Started lepresenced.<br />
Sep 06 16:13:45 raspberrypi lepresenced[16010]: [tid:1] main::bluetooth_scan_thread: Received 'Set scan parameters failed: Input/output error', ...tting...<br />
Sep 06 16:13:46 raspberrypi lepresenced[16010]: [tid:1] main::bluetooth_scan_thread: hcitool exited, retrying...<br />
<br />
Diese Meldungen können ignoriert werden. Abhilfe schafft sich lepresenced selbst indem es sich resettet.<br />
<br />
'''Moderne iPhones und Android Geräte wechseln zum "deep standby" Modus''', und werden dann als "abwesend" gemeldet.<br />
Mittels einer Funktion, die via hping3 Packete an den Geräte senden, um die "wach" zu halten, und dann die MacAdresse ausliest, kann man dieses Problem umgehen. Mehr im Forum [https://forum.fhem.de/index.php/topic,76342.0.html]<br />
<br />
= Versionsänderungen lepresenced =<br />
<pre><br />
--Version 0.81 (BasisVersion)<br />
--Version 0.82 (stable 08/2017)<br />
-Neue Kommandozeilenoption "--debug": Startet lepresenced im Vordergrund und gibt ausführliche Debug-Informationen auf STDOUT aus.<br />
-Sanity Check: lepresenced prüft beim Starten die Verfügbarkeit von hciconfig, hcitool und hcidump.<br />
-Model: lepresenced übermittelt das Reading model nun als lan-lepresenced. Das erlaubt die Erkennung von lepresenced in der FHEM-Statistik (sofern aktiviert).<br />
--Version 0.83 (stable 09/2017)<br />
- Behebung von Systemstart Fehlern<br />
- Weitere Debug-Möglichkeiten. U. a. wird nun mitgezählt, ob hcitool lescan ("legacy") und hcidump eine identische Zahl an Beacons empfangen<br />
</pre><br />
<br />
= Ansprechpartner =<br />
# {{Link2FU|117|markusbloch }} (Markus) für das PRESENCE-Modul und collectord<br />
# {{Link2FU|5068|PatrikR}} (Patrick) für lepresenced <br />
# [[Benutzer Diskussion:Devender|Devender]] ({{Link2FU|20043|Dirk}}) für Wiki und Doku</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=Anwesenheitserkennung&diff=22911Anwesenheitserkennung2017-10-13T23:38:05Z<p>Amenomade: /* PRESENCE-Modul */</p>
<hr />
<div>Viele Benutzer führen bereits eine eigene '''Anwesenheitserkennung''' durch. Diese basiert in den meisten Fällen auf Ping Checks oder bei [[AVM Fritz!Box|FritzBoxen]] auf dem Befehl ''ctlmgr_ctl''. Diese Lösungen können aber je nach Aufbau und Funktion FHEM massiv beeinträchtigen. Aufgrund des Aufbaus vom FHEM kann dieses dadurch für mehrere Sekunden zum völligen Stillstand gebracht werden.<br />
<br />
In FHEM gibt es mittlerweile mehrere Module, die eine zuverlässige Anwesenheitserkennung bieten, ohne dabei FHEM bei der Ausführung zu beeinträchtigen.<br />
<br />
Eine erweiterte Funktion der Anwesenheitserkennung ist die Standortverfolgung, die sich nicht nur auf ein oder sehr wenige mit (eigenem) WLAN versorgte Gebiete beschränkt.<br />
<br />
== Vorüberlegungen ==<br />
Generell gibt es mehrere Ansätze um Anwesenheitserkennung mit Handys/Smartphones durchzuführen.<br />
<br />
* via PING Checks im gesamten WLAN<br />
* Aktivitätsprüfung auf einer FritzBox<br />
* Bluetooth Checks in der gesamten Wohnung<br />
* eigene Perl-Funktion<br />
* aktive Benachrichtigung des Smartphones, ausgelöst z.B. über Geo-Lokation/Geofence<br />
<br />
Dabei gilt bei der Auswahl der Art darauf zu achten wie sich das jeweilige Device verhält. Aufgrund der Vielfältigkeit kann man hier keine allgemeine Vorgehensweise empfehlen. Als einfacher Start (zumindest für Nicht-Apfel Telefone) eignet sich die Ping-Überprüfung und die FritzBox-Abfrage sehr gut.<br />
<br />
=== Randbedingungen ===<br />
Es gibt Geräte, die ihr WLAN/Bluetooth auch im Standby ständig aktiv haben und auf Anfragen antworten können (fast alle Android-Geräte). Gerade bei Tests über WLAN kann sich das aber signifikant auf die Akku Leistung auswirken.<br />
<br />
Andere Geräte wiederum schalten WLAN im Standby Betrieb aus, um Akkukapazität zu sparen. Bluetooth hingegen bleibt weiterhin aktiviert und kann auf Anfragen reagieren. (iPhone)<br />
<br />
Wenn man bei einem iPhone die Funktion "über WLAN synchronisieren" aktiviert hat, so ist dies auch im Standby jederzeit pingbar, wenn der Recher auf dem iTunes zum synchroniseren läuft auch an ist. Ansonsten ist bei iPhone Geräten nur die Aktivitätsprüfung mit einer FritzBox oder das überwachen der DHCP Lease auf einer Airport Basestation wirklich zuverlässig.<br />
<br />
Auch wenn Bluetooth aktiviert ist, so bleiben einige Mobiltelefone erst dann empfangsbereit, wenn sie bereits zu irgend einem Bluetoothgerät gekoppelt wurden. Sind diese Geräte noch nie gekoppelt worden, deaktivieren diese ihren Bluetooth Empfänger beim verlassen des Bluetooth-Menüs im Gerät (iPhone).<br />
<br />
Hier gilt es vor allem auszuprobieren, wie stark der Akku durch eine Anwesenheitserkennung belastet wird. Entscheidend ist hier, in welchem Abstand man eine Anwesenheitserkennung durchführt. Viele Abfragen wirken sich stärker auf den Akku aus als wenige. Wenige Abfragen bieten aber keine zuverlässige und zeitnahe Erkennung.<br />
<br />
Als Alternative, unabhängig vom WLAN und der Erkennung, ob ein Gerät dort eingebucht ist oder nicht, bzw. unabhängig von Bluetooth kann zumindest bei einem iPhone die seit iOS 7 nochmals stark verbesserte Geo-Lokation (Geofencing) genutzt werden. Die iPhone Apps [http://geofency.com/ Geofency] oder [http://geofancy.com/ Geofancy] werden über das FHEM-Modul GEOFANCY angebunden und übertragen ihren Status immer dann, wenn ein definierter Standort betreten oder verlassen wird. Gekoppelt mit entsprechenden Notify und/oder Watchdog Kommandos ist so ebenfalls eine sehr zuverlässige Anwesenheitserkennung möglich (und das nicht nur für das eigene Zuhause).<br />
<br />
== PRESENCE-Modul ==<br />
Das [[PRESENCE]] Modul bietet für die Anwesenheitserkennung mehrere Varianten an. Diese sind aktuell folgende:<br />
<br />
* '''lan-ping''' - Das Überwachen via PING Checks, die durch den FHEM Server versandt werden.<br />
* '''fritzbox''' - Das Überwachen von Geräten auf einer FritzBox via ctlmgr_ctl (Nur auf einer FritzBox möglich)<br />
* ''' Bluetooth'''<br />
:- '''local-bluetooth''' - Das Überwachen via Bluetooth Checks, die vom FHEM Server direkt durchgeführt werden (angeschlossener Bluetooth-Stick und die Software bluez voraussgesetzt)<br />
:- '''lan-bluetooth''' - Das Überwachen von Bluetoothgeräten, über Netzwerk. Auf einer oder mehreren Maschinen im Netzwerk (z.B. [[:Kategorie:Raspberry Pi|Raspberry Pi]]) läuft ein Presence-Daemon, der nach Bluetooth-Geräten sucht. Um mehrere Presence-Daemon mit FHEM zu verbinden, gibt es den Collector-Daemon, der sich zu allen Presence-Damons im Netzwerk verbindet und das Ergebnis von allen zusammenfasst.<br />
* '''function''' - Das Überwachen mithilfe einer selbst geschrieben Perl-Funktion, die den Anwesenheitsstatus zurückgibt (0 oder 1)<br />
* '''shell-script''' - Das Überwachen mithilfe eines selbst geschriebenen Shell-Programms/Skript, das eine 0 oder 1 ausgibt, um den Anwesenheitsstatus mitzuteilen.<br />
<br />
Für eine bessere Übersicht befinden sich die '''Details''' zur '''Einrichtung''' und '''Benutzung''' von PRESENCE auf folgende '''Seite''' [[PRESENCE|PRESENCE]]<br />
<br />
Im Forum [https://forum.fhem.de/index.php/topic,76342.0.html] findet man eine Lösung zum Problem des "deep standby" Modus von den neuen iPhones und Android Geräte. Mittels hping3 werden Packete an das Gerät geschickt, damit die "wach" bleiben. Dann werden die Mac-Adressen via 'arp' gelesen.<br />
<br />
== GEOFANCY-Modul ==<br />
Das Modul ermöglicht über einen sogenannten Webhook Mechanismus (umgangssprachlich oft auch als "Push" benannt) das aktive Melden des aktuellen Standortes. Die iPhone Apps [http://geofency.com/ Geofency] und [http://geofancy.com/ Geofancy] können dann aktiv und quasi in dem Moment, wo man den Wohnbereich betritt oder verlässt, benachrichtigen. Android Nutzern können [https://play.google.com/store/apps/details?id=de.egi.geofence.geozone&hl=de EgiGeoZone Geofence] nutzen. Das geht nochmals um einiges schneller, als die Erkennung im WLAN, bei der die Anwesenheit nur in (engen) Zyklen aktiv geprüft werden muss. Gleichzeitig werden Ressourcen in FHEM geschont. Die aktuelle Implementierung im iPhone 5S mit dediziert für das Tracking zuständigem Chip ist so gut, dass der Akku ebenfalls sehr geschont wird.<br />
<br />
Für eine bessere Übersicht befinden sich die '''Details''' zur '''Einrichtung''' und '''Benutzung''' von GEOFANCY auf folgende '''Seite''' [[GEOFANCY|GEOFANCY]]<br />
<br />
== Beispiele für die Nutzung der Anwesenheitserkennung ==<br />
Hier sollen Beispiele für den Nutzen von Anwesenheitserkennung aufgezeigt werden.<br />
<br />
=== Abschalten aller Verbraucher (Licht, Musikanlage) beim Verlassen der Wohnung ===<br />
Typisches Szenario: Man geht ausser Haus, aber hat vergessen im Bad das Licht aus zu machen. Allerdings geht man heutzutage fast garnicht mehr ohne Handy aus dem Haus.<br />
<br />
Nun soll FHEM in der gesamten Wohnung das Licht, sowie sonstige Verbraucher ausschalten, wenn ich länger als 15 Minuten ausser Haus bin. Dazu benötigt man zuerst eine structure, die alle Verbraucher und sonstigen Devices, die das betrifft, zusammenfasst.<br />
<br />
<pre><br />
define Gesamte_Wohnung structure Gesamtes_Licht Licht_Wohnzimmer Licht_Kueche LED_Kueche Licht_Bad Licht_Schlafzimmer AV_Receiver TV_Steckdose<br />
attr Gesamte_Wohnung room Wohnung<br />
</pre><br />
<br />
Nun kann man mittels eines watchdogs eine Überwachung für sein Handy anlegen:<br />
<br />
<pre><br />
# Überwachen der gesamten Wohnung mittels collectord sowie presenced in jedem Raum<br />
define Handy PRESENCE lan-bluetooth XX:XX:XX:XX:XX:XX 127.0.0.1:5222<br />
attr Handy event-on-change-reading state # Ein Event soll nur bei der Änderung des Anwesenheitsstatus (Reading: status) erfolgen. Wichtig für den watchdog!!!<br />
<br />
# Nach 15 Minuten Abwesenheit (Handy im Status "absent") soll die gesamte Wohnung ausgeschaltet werden.<br />
define watchdog_Anwesenheit watchdog Handy:absent 00:15 Handy:present set Gesamte_Wohnung off ; trigger watchdog_Anwesenheit .<br />
attr watchdog_Anwesenheit regexp1WontReactivate 1<br />
</pre><br />
<br />
=== Benachrichtigung bei Batteriewechsel ===<br />
Mit Hilfe des PRESENCE-Moduls kann man auch bei batteriebetriebenen Geräten eine Meldung ausgeben, sobald ein Batteriewechsel ansteht. Hier im Beispiel wird der Eve-Room-Sensor von Elgato eingebunden und anschließend mit einer DOIF-Nachricht ausgestattet.<br />
Die Bluetooth-Adresse des Sensors kann mittels eines BLE-Scanners ermittelt werden.<br />
<br />
<pre><br />
# PRESENCE-Modul für Elgato Eve Room Sensor mit Aktualisierung aller 6 Minuten<br />
define Eve_Room_BLE lan-bluetooth <Bluetooth-Adresse> 127.0.0.1:5333 360<br />
</pre><br />
<br />
Anschließend wird eine DOIF-Regel definiert, die eine Nachricht an die installiere [[FHEM_APP|FHEM App]] absendet:<br />
<pre><br />
define Eve_Room_BLE_Battery_Msg DOIF ([Eve_Room_BLE] eq "absent") (set Msg_iPhone message 'Batteriewechsel beim Eve Room Sensor im Wohnzimmer.')<br />
attr Eve_Room_BLE_Battery_Msg wait 600<br />
</pre><br />
<br />
Die Aktualisierung des PRESENCE-Eintrages sollte nicht größer sein als das WAIT-Attribut der DOIF-Regel. Ansonsten könnte eine kurze Systemstörung zum Fehlalarm führen.<br />
[[Kategorie:Code Snippets]]<br />
[[Kategorie:Glossary]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=Anwesenheitserkennung&diff=22910Anwesenheitserkennung2017-10-13T23:37:24Z<p>Amenomade: /* PRESENCE-Modul */ Deep standby Lösung</p>
<hr />
<div>Viele Benutzer führen bereits eine eigene '''Anwesenheitserkennung''' durch. Diese basiert in den meisten Fällen auf Ping Checks oder bei [[AVM Fritz!Box|FritzBoxen]] auf dem Befehl ''ctlmgr_ctl''. Diese Lösungen können aber je nach Aufbau und Funktion FHEM massiv beeinträchtigen. Aufgrund des Aufbaus vom FHEM kann dieses dadurch für mehrere Sekunden zum völligen Stillstand gebracht werden.<br />
<br />
In FHEM gibt es mittlerweile mehrere Module, die eine zuverlässige Anwesenheitserkennung bieten, ohne dabei FHEM bei der Ausführung zu beeinträchtigen.<br />
<br />
Eine erweiterte Funktion der Anwesenheitserkennung ist die Standortverfolgung, die sich nicht nur auf ein oder sehr wenige mit (eigenem) WLAN versorgte Gebiete beschränkt.<br />
<br />
== Vorüberlegungen ==<br />
Generell gibt es mehrere Ansätze um Anwesenheitserkennung mit Handys/Smartphones durchzuführen.<br />
<br />
* via PING Checks im gesamten WLAN<br />
* Aktivitätsprüfung auf einer FritzBox<br />
* Bluetooth Checks in der gesamten Wohnung<br />
* eigene Perl-Funktion<br />
* aktive Benachrichtigung des Smartphones, ausgelöst z.B. über Geo-Lokation/Geofence<br />
<br />
Dabei gilt bei der Auswahl der Art darauf zu achten wie sich das jeweilige Device verhält. Aufgrund der Vielfältigkeit kann man hier keine allgemeine Vorgehensweise empfehlen. Als einfacher Start (zumindest für Nicht-Apfel Telefone) eignet sich die Ping-Überprüfung und die FritzBox-Abfrage sehr gut.<br />
<br />
=== Randbedingungen ===<br />
Es gibt Geräte, die ihr WLAN/Bluetooth auch im Standby ständig aktiv haben und auf Anfragen antworten können (fast alle Android-Geräte). Gerade bei Tests über WLAN kann sich das aber signifikant auf die Akku Leistung auswirken.<br />
<br />
Andere Geräte wiederum schalten WLAN im Standby Betrieb aus, um Akkukapazität zu sparen. Bluetooth hingegen bleibt weiterhin aktiviert und kann auf Anfragen reagieren. (iPhone)<br />
<br />
Wenn man bei einem iPhone die Funktion "über WLAN synchronisieren" aktiviert hat, so ist dies auch im Standby jederzeit pingbar, wenn der Recher auf dem iTunes zum synchroniseren läuft auch an ist. Ansonsten ist bei iPhone Geräten nur die Aktivitätsprüfung mit einer FritzBox oder das überwachen der DHCP Lease auf einer Airport Basestation wirklich zuverlässig.<br />
<br />
Auch wenn Bluetooth aktiviert ist, so bleiben einige Mobiltelefone erst dann empfangsbereit, wenn sie bereits zu irgend einem Bluetoothgerät gekoppelt wurden. Sind diese Geräte noch nie gekoppelt worden, deaktivieren diese ihren Bluetooth Empfänger beim verlassen des Bluetooth-Menüs im Gerät (iPhone).<br />
<br />
Hier gilt es vor allem auszuprobieren, wie stark der Akku durch eine Anwesenheitserkennung belastet wird. Entscheidend ist hier, in welchem Abstand man eine Anwesenheitserkennung durchführt. Viele Abfragen wirken sich stärker auf den Akku aus als wenige. Wenige Abfragen bieten aber keine zuverlässige und zeitnahe Erkennung.<br />
<br />
Als Alternative, unabhängig vom WLAN und der Erkennung, ob ein Gerät dort eingebucht ist oder nicht, bzw. unabhängig von Bluetooth kann zumindest bei einem iPhone die seit iOS 7 nochmals stark verbesserte Geo-Lokation (Geofencing) genutzt werden. Die iPhone Apps [http://geofency.com/ Geofency] oder [http://geofancy.com/ Geofancy] werden über das FHEM-Modul GEOFANCY angebunden und übertragen ihren Status immer dann, wenn ein definierter Standort betreten oder verlassen wird. Gekoppelt mit entsprechenden Notify und/oder Watchdog Kommandos ist so ebenfalls eine sehr zuverlässige Anwesenheitserkennung möglich (und das nicht nur für das eigene Zuhause).<br />
<br />
== PRESENCE-Modul ==<br />
Das [[PRESENCE]] Modul bietet für die Anwesenheitserkennung mehrere Varianten an. Diese sind aktuell folgende:<br />
<br />
* '''lan-ping''' - Das Überwachen via PING Checks, die durch den FHEM Server versandt werden.<br />
* '''fritzbox''' - Das Überwachen von Geräten auf einer FritzBox via ctlmgr_ctl (Nur auf einer FritzBox möglich)<br />
* ''' Bluetooth'''<br />
:- '''local-bluetooth''' - Das Überwachen via Bluetooth Checks, die vom FHEM Server direkt durchgeführt werden (angeschlossener Bluetooth-Stick und die Software bluez voraussgesetzt)<br />
:- '''lan-bluetooth''' - Das Überwachen von Bluetoothgeräten, über Netzwerk. Auf einer oder mehreren Maschinen im Netzwerk (z.B. [[:Kategorie:Raspberry Pi|Raspberry Pi]]) läuft ein Presence-Daemon, der nach Bluetooth-Geräten sucht. Um mehrere Presence-Daemon mit FHEM zu verbinden, gibt es den Collector-Daemon, der sich zu allen Presence-Damons im Netzwerk verbindet und das Ergebnis von allen zusammenfasst.<br />
* '''function''' - Das Überwachen mithilfe einer selbst geschrieben Perl-Funktion, die den Anwesenheitsstatus zurückgibt (0 oder 1)<br />
* '''shell-script''' - Das Überwachen mithilfe eines selbst geschriebenen Shell-Programms/Skript, das eine 0 oder 1 ausgibt, um den Anwesenheitsstatus mitzuteilen.<br />
<br />
Für eine bessere Übersicht befinden sich die '''Details''' zur '''Einrichtung''' und '''Benutzung''' von PRESENCE auf folgende '''Seite''' [[PRESENCE|PRESENCE]]<br />
<br />
Im Forum [https://forum.fhem.de/index.php/topic,76342.0.html] findet man eine Lösung zum Problem des "deep standby" Modus von den neuen iPhones und Android Geräte. Mittles hping3 werden Packete an das Gerät geschickt, damit die "wach" bleiben. Dann werden die Mac-Adressen via 'arp' gelesen.<br />
<br />
== GEOFANCY-Modul ==<br />
Das Modul ermöglicht über einen sogenannten Webhook Mechanismus (umgangssprachlich oft auch als "Push" benannt) das aktive Melden des aktuellen Standortes. Die iPhone Apps [http://geofency.com/ Geofency] und [http://geofancy.com/ Geofancy] können dann aktiv und quasi in dem Moment, wo man den Wohnbereich betritt oder verlässt, benachrichtigen. Android Nutzern können [https://play.google.com/store/apps/details?id=de.egi.geofence.geozone&hl=de EgiGeoZone Geofence] nutzen. Das geht nochmals um einiges schneller, als die Erkennung im WLAN, bei der die Anwesenheit nur in (engen) Zyklen aktiv geprüft werden muss. Gleichzeitig werden Ressourcen in FHEM geschont. Die aktuelle Implementierung im iPhone 5S mit dediziert für das Tracking zuständigem Chip ist so gut, dass der Akku ebenfalls sehr geschont wird.<br />
<br />
Für eine bessere Übersicht befinden sich die '''Details''' zur '''Einrichtung''' und '''Benutzung''' von GEOFANCY auf folgende '''Seite''' [[GEOFANCY|GEOFANCY]]<br />
<br />
== Beispiele für die Nutzung der Anwesenheitserkennung ==<br />
Hier sollen Beispiele für den Nutzen von Anwesenheitserkennung aufgezeigt werden.<br />
<br />
=== Abschalten aller Verbraucher (Licht, Musikanlage) beim Verlassen der Wohnung ===<br />
Typisches Szenario: Man geht ausser Haus, aber hat vergessen im Bad das Licht aus zu machen. Allerdings geht man heutzutage fast garnicht mehr ohne Handy aus dem Haus.<br />
<br />
Nun soll FHEM in der gesamten Wohnung das Licht, sowie sonstige Verbraucher ausschalten, wenn ich länger als 15 Minuten ausser Haus bin. Dazu benötigt man zuerst eine structure, die alle Verbraucher und sonstigen Devices, die das betrifft, zusammenfasst.<br />
<br />
<pre><br />
define Gesamte_Wohnung structure Gesamtes_Licht Licht_Wohnzimmer Licht_Kueche LED_Kueche Licht_Bad Licht_Schlafzimmer AV_Receiver TV_Steckdose<br />
attr Gesamte_Wohnung room Wohnung<br />
</pre><br />
<br />
Nun kann man mittels eines watchdogs eine Überwachung für sein Handy anlegen:<br />
<br />
<pre><br />
# Überwachen der gesamten Wohnung mittels collectord sowie presenced in jedem Raum<br />
define Handy PRESENCE lan-bluetooth XX:XX:XX:XX:XX:XX 127.0.0.1:5222<br />
attr Handy event-on-change-reading state # Ein Event soll nur bei der Änderung des Anwesenheitsstatus (Reading: status) erfolgen. Wichtig für den watchdog!!!<br />
<br />
# Nach 15 Minuten Abwesenheit (Handy im Status "absent") soll die gesamte Wohnung ausgeschaltet werden.<br />
define watchdog_Anwesenheit watchdog Handy:absent 00:15 Handy:present set Gesamte_Wohnung off ; trigger watchdog_Anwesenheit .<br />
attr watchdog_Anwesenheit regexp1WontReactivate 1<br />
</pre><br />
<br />
=== Benachrichtigung bei Batteriewechsel ===<br />
Mit Hilfe des PRESENCE-Moduls kann man auch bei batteriebetriebenen Geräten eine Meldung ausgeben, sobald ein Batteriewechsel ansteht. Hier im Beispiel wird der Eve-Room-Sensor von Elgato eingebunden und anschließend mit einer DOIF-Nachricht ausgestattet.<br />
Die Bluetooth-Adresse des Sensors kann mittels eines BLE-Scanners ermittelt werden.<br />
<br />
<pre><br />
# PRESENCE-Modul für Elgato Eve Room Sensor mit Aktualisierung aller 6 Minuten<br />
define Eve_Room_BLE lan-bluetooth <Bluetooth-Adresse> 127.0.0.1:5333 360<br />
</pre><br />
<br />
Anschließend wird eine DOIF-Regel definiert, die eine Nachricht an die installiere [[FHEM_APP|FHEM App]] absendet:<br />
<pre><br />
define Eve_Room_BLE_Battery_Msg DOIF ([Eve_Room_BLE] eq "absent") (set Msg_iPhone message 'Batteriewechsel beim Eve Room Sensor im Wohnzimmer.')<br />
attr Eve_Room_BLE_Battery_Msg wait 600<br />
</pre><br />
<br />
Die Aktualisierung des PRESENCE-Eintrages sollte nicht größer sein als das WAIT-Attribut der DOIF-Regel. Ansonsten könnte eine kurze Systemstörung zum Fehlalarm führen.<br />
[[Kategorie:Code Snippets]]<br />
[[Kategorie:Glossary]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=Alexa-Fhem&diff=22606Alexa-Fhem2017-09-18T12:18:01Z<p>Amenomade: /* Was ist zu tun, wenn Alexa zwar Geräte findet, diese aber nicht angesprochen werden können? */ Add Howto Cloudwatch Logs</p>
<hr />
<div>'''Alexa-Fhem''' ist eine in JavaScript geschriebene und auf NodeJS basierende Software, welche es ermöglicht, der digitalen Amazon Assistentin Alexa zusätzliche Skills für die Heimautomatisierung via FHEM beizubringen. Eine erste funktionierende Version wurde von [https://forum.fhem.de/index.php?action=profile;u=430 justme1968] im {{Link2Forum|Topic=60244|LinkText=Forum}} veröffentlicht.<br />
Das ist eine erste Version der Dokumentation zur Installation und Einrichtung, eine Erweiterung wird sicherlich in nächster Zeit noch folgen.<br />
{{Infobox Modul<br />
|ModPurpose=Anbindung von FHEM an Amazon Assistent Alexa<br />
|ModType=x<br />
|ModTechName=<br />
|ModForumArea=Frontends/Sprachsteuerung<br />
|ModOwner=justme1968<br />
}} <br />
<br />
<br />
==Einführung==<br />
===Glossar===<br />
*Echo bzw. Echo Dot (im Folgenden maskulin bezeichnet) sind die derzeit verfügbaren Geräte des Alexa-Systems '''BILDER EINSTELLEN - Achtung Urheberrecht'''<br />
*AVS ist der Amazon Voice Service, d.h. die Spracherkennungskomponente des Systems.{{Randnotiz|RNTyp=r|RNText=Für die Nutzung der Amazon AWS-Dienste müssen zwingend die Daten einer Kreditkarte angegeben werden. Nach gegenwärtigem Kenntnisstand sollen jedoch keine Kosten für die Nutzung der im Rahmen dieses How To beschriebenen Dienste anfallen, sofern diese in einem Rahmen genutzt werden, der selbst eine intensive private Nutzung nicht überschreitet. Der Benutzer sei an dieser Stelle auf die von Amazon veröffentlichten Preislisten verwiesen. Die Autoren dieser Anleitung und der darin beschriebenen Module übernehmen keine Haftung für eventuelle Kosten, die aus der Nutzung der AWS entstehen. }}<br />
*AWS sind die Amazon Web Services, also per URL erreichbare Dienste zur Ausführung von Berechnungen etc. Im Rahmen von Alexa-Fhem wird bei AWS eine eigene JavaScript-Funktion hinterlegt, die zur Kommunikation mit dem FHEM-Server dient. Im Jargon von Amazon ist dies eine so genannte Lambda-Funktion '''WARUM ? Nachlesen bei Amazon'''.<br />
*Card bezeichnet einen Eintrag in der Alexa-App, der die erkannte Sprachnachricht sowie weiter gehenden Informationen über die Reaktion von Alexa enzthält und Rückmeldung an Amazon erlaubt.<br />
*Skill (engl. für Fähigkeit) ist die Bezeichnung für eine per Spracherkennung bediente Funktionalität des Alexa-Systems, z.B. zur Nachrichtenansage, zur Wettervorhersage oder zur Steuerung von FHEM<br />
<br />
===Arbeitsweise und Datenfluss===<br />
[[Datei:2gpXyLN.jpg|200px|thumb|right|Grafische Darstellung der beteiligten Komponenten]]<br />
Echo -> AVS -> AWS Lambda -> alexa-fhem -> AWS Lambda -> AVS -> Echo<br />
<br />
*Der Echo (oder ein anderes Alexa/AVS fähiges Gerät) nimmt Audiodaten auf und schickt diese an AVS (Amazon Voice Service) zur Erkennung<br />
*AVS führt die Spracherkennung durch und erzeugt ein Event mit Informationen zu den erkannten Daten<br />
:*Beim Alexa SmartHome Skill sind die möglichen Sätze für die Spracherkennung relativ fest vorgegeben <br />
:*Beim Alexa Custom Skill kommen die dazu nötigen Informationen aus dem ''Interaction Model'' der Alexa Skills Configuration<br />
*Das Event wird an den unter ''Configuration'' in der Alexa Skills Configuration hinterlegten Endpoint geschickt<br />
:*Beim Alexa SmartHome Skill ist das zwingend eine AWS Lambda Routine<br />
:*Beim Alexa Custom Skill kann das im Prinzip auch ein eigener Web Service sein<br />
*Das Event wird vom <code>lambda.js</code> code an alexa-fhem weitergeleitet<br />
*alexa-fhem steuert FHEM und sendet ein Antwort-Event zurück<br />
*<code>lambda.js</code> nimmt diese Antwort entgegen und gibt sie an AVS zurück<br />
*AVS sogt dafür das der Echo 'antwortet' und dass die Card in der Alexa App erscheint<br />
<br />
===Anmerkungen===<br />
*Ein Skill hat keinen Zugriff auf die Audiodaten<br />
*Mit dem Skill API kann ein Skill zu zu keiner Zeit von sich aus aktiv werden und 'einfach' Daten an den Echo schicken oder ihn dazu bringen irgendetwas zu tun.<br />
*Wenn man berücksichtigt welchen Weg die Daten insgesamt gehen, ist es erstaunlich, wie schnell die Reaktion auf einen gesprochenen Satz erfolgt.<br />
<br />
=== Abgrenzung des '''Alexa Smart Home Skills''' und des '''Alexa Custom Skills''' ===<br />
<br />
Der [[Alexa-Fhem#Smart_Home|Alexa Smart Home Skill]] ist ein Amazon-Alexa-Standard-Skill, der wesentliche Basisfunktionalitäten bereitstellt. Zu diesen gehört im Wesentlichen die Funktionalität, durch Alexa-FHEM bereitgestellte Devices im Alexa-Account des Benutzers anzulegen. Der Alexa Smart Home Skill reagiert auf gesprochene Interaktion in einem beschränkten Umfang. Beispielsweise genügt ein "Alexa, schalte die Wohnzimmerlampe an" um eine Interaktion zwischen Alexa Smart Home Skill und FHEM-Alexa auszulösen. Nach erfolgreicher Einrichtung wird dieser Skill in der Alexa-App bzw. im Web in der Rubrik "Smart Home" als Skill angezeigt.<br />
<br />
Der [[Alexa-Fhem#Custom|Alexa Custom Skill]] ist kein Standard-Smart-Home-Skill, sondern ein individuell entwickelter Skill, so wie alle anderen Skills auch. Er wird daher auch nicht in der Alexa-App unter der Rubrik "Smart Home" angezeigt. Gesprochene Interaktion mit diesem Skill erfolgt dadurch, dass entweder der Skill explizit gestartet wird (z.B. "Alexa, starte [Name des Skills]") oder direkt angesprochen wird (z.B. "Alexa, frage [Name des Skills] wie ist der Status von [Device] "). Der Alexa Custom Skill befindet sich in Entwicklung und wird hinsichtlich seiner Funktionalitäten laufend weiterentwickelt. Die Einrichtung dieses Skills ist grundsätzlich optional, jedoch werden anspruchsvollere Steuerungsmöglichkeiten nur mit diesem realisiert werden können.<br />
<br />
==Installation==<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Da die einzelnen Schritte der Anleitung an verschiedenen Stellen unterbrochen und später fortgesetzt werden müssen, empfiehlt es sich, die Anleitung einmal vollständig gelesen zu haben. Während der Konfiguration sollten alle nachfolgenden Abschnitte parallel in gleichzeitig geöffneten Browserfenstern durchgeführt werden, die jeweils bis zum Abschluss geöffnet bleiben müssen. }}<br />
Grundvoraussetzung für alle folgenden Schritte ist das Vorhandensein eines Amazon-Accounts. Es wird davon ausgegangen, dass die Konten für alle im Folgenden genutzten Amazon-Dienste eingerichtet wurden.<br />
<br />
===node.js installieren===<br />
Zunächst wird das Betriebssystem (in diesem Falle Debian oder Ubuntu) auf den aktuellen Stand gebracht:<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
sudo apt-get update<br />
sudo apt-get upgrade<br />
sudo apt-get install build-essential libssl-dev</syntaxhighlight><br />
<br />
Nun muss NodeJS installiert werden. Leider ist die Version im Debian Repository deutlich zu alt, daher wird mit den folgenden Befehlen das Node Repository hinzugefügt und NodeJS (in der LTS Version) entsprechend installiert:<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -<br />
sudo apt-get install -y nodejs<br />
</syntaxhighlight><br />
<br />
=== Alexa-Fhem installieren ===<br />
'''Aus gegebenem Anlass: Dies ist weder eine Einführung in Linux, noch eine Anfängerdokumentation für FHEM.''' Also erst die Grundlagen lernen, und dann mit Alexa beginnen !<br />
<br />
Die aktuelle Version ist jeweils {{Link2Forum|Topic=60244|Message=540117|LinkText=hier}} zu finden.<br />
<br />
====Erstinstallation====<br />
Hier wird die Erstinstallation von Alexa-Fhem beschrieben.<br />
===== Linux =====<br />
# Die tgz-Datei unter Linux im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) entpacken (''nicht'' unter Windows, das zerstört die Rechteeinstellungen).<syntaxhighlight lang="bash" style="width:50%;">tar -xvzf dateiname.tgz</syntaxhighlight><br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen <syntaxhighlight lang="bash" style="width:50%;">mv package alexa-fhem</syntaxhighlight><br />
# Durch <syntaxhighlight lang="bash" style="width:50%;">cd alexa-fhem</syntaxhighlight> in das Verzeichnis wechseln<br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren (kein sudo!).<br />
# SSL Zertifikat erzeugen durch Aufruf von <syntaxhighlight lang="bash" style="width:50%;">./createKey.sh</syntaxhighlight> (kein sudo!). Hierbei beachten, dass ein Kennwort vergeben werden muss, das mindestens aus 4 Zeichen besteht, dieses Kennwort bitte merken.<br />
# Das Verzeichnis ''.alexa'' anlegen, ''und zwar im Home-Verzeichnis desjenigen Benutzers, unter dem Alexa-Fhem laufen soll.'' Insbesondere ist zu beachten, dass dieser Nutzer u.U. im Startskript explizit gesetzt wird. Mit dem untenstehenden Skript ist das ''nicht'' der User fhem, sondern der User ''pi''. Das Symbol ''~/'' verweist auf das Home-Verzeichnis des Benutzers, der gerade die Installation vornimmt.<br />
# Die Datei ''config-sample.json'' nach ''.alexa/config.json'' kopieren. Achtung: Installiert man alexa-fhem als root-user, zeigt das Symbol ''~/'' auf ''/root'' - und die Konfigurationsdatei wird ggf. bei einem manuellen Start von Alexa-Fhem nicht gefunden.<br />
# Achtung: Ggf. müssen auch die Dateien key.pem und cert.pem ins entsprechende Verzeichnis kopiert werden.<br />
===== Windows =====<br />
''Vor'' der Installation von Alexa-Fhem muss man folgende Anwendungen installieren:<br />
* Node.js (die aktuelle Version findet man unter https://nodejs.org/en/download/)<br />
* OpenSSL (http://slproweb.com/products/Win32OpenSSL.html oder https://www.heise.de/download/product/win32-openssl-47316/download)<br />
Erst dann fängt man mit Alexa-Fhem an.<br />
<br />
<br />
# Die tgz-Datei im Hauptverzeichnis von FHEM (z.B. <code>С:\Program Files (x86)\fhem</code>) entpacken.<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen<br />
# Windows-Shell (Kommandozeile, Eingabeaufforderung usw.) öffnen. "Start" -> "Ausführen" (oder [Windows-Taste]+[R]) -> cmd -> Ok. Durch <syntaxhighlight lang="bash" style="width:50%;">cd "<FHEM-Hauptverzeichis>\alexa-fhem"</syntaxhighlight> in das Verzeichnis wechseln. <br/>Dabei ist natürlich das <FHEM-Hauptverzeichis> durch den entsprechenden Pfad aus dem Schritt 1 zu ersetzen. Im o.g. Beispiel wäre es <code>cd "С:\Program Files (x86)\fhem\alexa-fhem"</code><br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren.<br/> Bei der Fehlermeldung wie "Der Befehl "npm" ist entweder falsch geschrieben oder konnte nicht gefunden werden." ist die Installation von Node.js zu überprüfen.<br />
# SSL Zertifikat erzeugen. Dafür muss man alle Befehle aus dem Skript ''createKey.sh'' nacheinander manuell ausführen. Hierbei beachten, dass ein Kennwort vergeben werden muss, das mindestens aus 4 Zeichen besteht, dieses Kennwort bitte merken. Der Windows-Welt unbekannter Befehl <code>mv</code> ist durch <code>move /y</code> zu ersetzen:<syntaxhighlight lang="bash" style="width:50%;">openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;">openssl rsa -in key.pem -out newkey.pem</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;">move /y newkey.pem key.pem</syntaxhighlight> Eventuelle Fehlermeldung "can't open config file: /usr/local/ssl/openssl.cnf" o.Ä. lässt sich durch Befehl <code>set OPENSSL_CONF=<OpenSSL-Verzeichnis>\bin\openssl.cfg</code> beheben, wobei <OpenSSL-Verzeichnis> durch den entsprechenden Installationspfad (typischerweise <code>c:\OpenSSL-Win32</code>) zu ersetzen ist.<br />
# Das Verzeichnis ''.alexa'' anlegen, ''und zwar im Benutzerverzeichnis desjenigen Benutzers, unter dem Alexa-Fhem laufen soll.'' In aktuellen Versionen von Windows (ab Windows 7 bzw. ab Windows Server 2008 R2) liegt das Verzeichnis unter <code>C:\Users\<Benutzername></code>, also z.B. für Benutzer "Administrator" - unter <code>C:\Users\Administrator</code>.<br/>Falls Windows sich weigert das Verzichniss mit dem Punkt am Anfang zu erstellen, kann man das aus der Kommandozeile machen:<syntaxhighlight lang="bash" style="width:50%;">cd "C:\Users\<Benutzername>"</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;"><br />
mkdir ".alexa"</syntaxhighlight><br />
# Die Datei ''config-sample.json'' nach ''C:\Users\<Benutzername>\.alexa\config.json'' kopieren.<br />
# Achtung: Ggf. müssen auch die Dateien key.pem und cert.pem ins entsprechende Verzeichnis (<code>"<FHEM-Hauptverzeichis>\alexa-fhem\bin</code>) kopiert werden.<br />
<br />
====Update====<br />
Hier wir das Update auf eine neue Version von Alexa-Fhem beschrieben<br />
===== Linux =====<br />
# Das Verzeichnis ''alexa-fhem'' im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) umbenennen in ''alexa-fhem.old''.<br />
# Die tgz-Datei der neuen Alexa-Fhem-Version unter Linux im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) entpacken (''nicht'' unter Windows, das zerstört die Rechteeinstellungen).<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen, in das Verzeichnis wechseln<br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren (kein sudo!).<br />
# Die Zertifikatsdateien key.pem und cert.pem aus dem alten Verzeichnis ''alexa-fhem.old'' ins neue Verzeichnis ''alexa-fhem'' kopieren.<br />
Natürlich dann den Dienst neu starten, auch müssen selbstredend irgendwelche Modifikationen an der Datei server.js in der neuen Version nachgezogen werden. Wenn alles läuft, kann das alte Verzeichnis ''alexa-fhem.old'' gelöscht werden.<br />
===== Windows =====<br />
# Das Verzeichnis ''alexa-fhem'' im Hauptverzeichnis von FHEM (z.B. <code>С:\Program Files (x86)\fhem</code>) umbenennen in ''alexa-fhem.old''.<br />
# Die tgz-Datei der neuen Alexa-Fhem-Version im Hauptverzeichnis von FHEM entpacken.<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen<br />
# Windows-Shell (Kommandozeile, Eingabeaufforderung usw.) öffnen. "Start" -> "Ausführen" (oder [Windows-Taste]+[R]) -> cmd -> Ok. Durch <syntaxhighlight lang="bash" style="width:50%;">cd "<FHEM-Hauptverzeichis>\alexa-fhem"</syntaxhighlight> in das Verzeichnis wechseln. <br/>Dabei ist natürlich das <FHEM-Hauptverzeichis> durch den entsprechenden Pfad aus dem Schritt 1 zu ersetzen. Im o.g. Beispiel wäre es <code>cd "С:\Program Files (x86)\fhem\alexa-fhem"</code><br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren.<br />
# Die Zertifikatsdateien key.pem und cert.pem aus dem alten Verzeichnis ''alexa-fhem.old'' ins neue Verzeichnis ''alexa-fhem'' kopieren.<br />
Natürlich dann den Dienst neu starten, auch müssen selbstredend irgendwelche Modifikationen an der Datei server.js in der neuen Version nachgezogen werden. Wenn alles läuft, kann das alte Verzeichnis ''alexa-fhem.old'' gelöscht werden.<br />
<br />
==== Alexa-Fhem konfigurieren ====<br />
Der Inhalt der Datei ''~/.alexa/config.json'' muss an die eigene Umgebung angepasst werden. <br />
# ''nat-pmp'' -> wenn nat-pmp verwendet werden soll: die ip des eigenen routers,<br />
# ''nat-upnp'' -> wenn nat-upnp verwendet werden soll: ''true'',<br />
# ''applicationId'' <br />
#:* Wenn man nur den SmartHome-Skill verwenden möchte, kann dieser Eintrag leer bleiben.<br />
#:* Ansonsten ist er mit der SkillID des Alexa Custom Skills zu belegen, siehe Abschnitt [[#Skill_Id_bestimmen | Skill Id bestimmen]]<br />
# ''oauthClientID'' -> ''Client ID'' dem Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
# ''server'' -> IP-Adresse des eigenen FHEM-Servers<br />
# ''port'' -> Portnummer des eigenen FHEM-Servers<br />
Beispiel:<br />
{<br />
"alexa": {<br />
"name": "Alexa TEST",<br />
"keyFile": "./key.pem",<br />
"certFile": "./cert.pem",<br />
"applicationId": "amzn1.ask.skill.xxxxxxxxxxxxxxxxxxxxxxxxxxxx",<br />
"oauthClientID": "amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"<br />
},<br />
"connections": [<br />
{<br />
"name": "FHEM",<br />
"server": "192.168.0.xxx.xxx",<br />
"port": "8083",<br />
"filter": "room=AlexaRoom"<br />
}<br />
]<br />
}<br />
<br />
Mehrere Custom Skills lassen sich mit der folgenden Syntax eintragen<br />
"applicationId": [ "amzn1.ask.skill.1" , "amzn1.ask.skill.2" ],<br />
"oauthClientID": [ "amzn1.application-oa2-client.1" , "amzn1.application-oa2-client.1" ]<br />
<br />
Danach durch Aufruf von <syntaxhighlight lang="bash" style="width:50%;">./bin/alexa</syntaxhighlight> den Dienst starten (kein sudo!)<br />
<br />
<br />
Unter Windows startet man Alexa-Dienst durch <syntaxhighlight lang="bash" style="width:50%;">node alexa</syntaxhighlight> aus der <code>alex-fhem/bin</code> (also erst z.B. durch <code>cd "<FHEM-Hauptverzeichis>\alexa-fhem\bin"</code> ins richtige Verzeichnis kommen)<br />
<br />
Der Start des Alexa-Dienstes auf der Console ist immer dann zu empfehlen, wenn man auf die Ausgaben des Dienstes angewiesen ist und beispielsweise sehen möchte, welche Devices durch den Dienst bereitgestellt werden oder ob Fehler auftreten. Beendet man die Console-Session wird auch der Dienst wieder beendet. Insofern ist die vorgenannte Vorgehensweise nur für ein Debugging zu empfehlen und nicht im Regelbetrieb. Nachfolgend ist beschrieben, wie man den Alexa-Dienst aus FHEM heraus starten / stoppen und neu starten kann.<br />
<br />
==== Alexa-Fhem aus FHEM heraus starten ====<br />
Zunächst das Start-up-Skript aus diesem Post herunterladen {{Link2Forum|Topic=60244|Message=517271|LinkText=https://forum.fhem.de/index.php/topic,60244.msg517271.html#msg517271}} und unter /etc/init.d/alexa speichern.<br />
<br />
Das Script geht davon aus, das der alexa-fhem script unter /opt/fhem/alexa-fhem liegt, und die logfiles später unter /opt/fhem/log. Sollte das nicht der Fall sein, muss das Skript angepasst werden.<br />
<br />
Nun folgende Kommandos ausführen:<br />
<syntaxhighlight lang="bash" style="width:50%;">sudo chmod 755 /etc/init.d/alexa<br />
sudo update-rc.d alexa defaults</syntaxhighlight><br />
<br />
In der Datei <code>/etc/sudoers</code> den User fhem für die Nutzung von sudo zulassen (<code>sudo nano /etc/sudoers</code>), z.B. durch Anfügen der nachfolgenden Zeile:<br />
<code>fhem ALL=(ALL) NOPASSWD: ALL</code><br />
<br />
Nun folgende Devices anlegen (ggf. einem Raum zuordnen, z.B. AlexaControl):<br />
<syntaxhighlight lang="bash" style="width:75%;">define FHEM.Alexa.Status dummy<br />
<br />
define FHEM.Alexa dummy<br />
attr FHEM.Alexa event-on-change-reading state<br />
attr FHEM.Alexa webCmd status:start:stop:restart<br />
<br />
define FHEM.Alexa.DOIF DOIF ([FHEM.Alexa] eq "start") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa start > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "stop")<br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa stop > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "restart") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa restart > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "status") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa status > /dev/null 2>&1 &")})</syntaxhighlight><br />
<br />
==== Alexa-Fhem als Service (systemd) installieren ====<br />
Auf neueren Installationen (z.B. RPi Jessie) wird init.d durch systemd ersetzt. Folgend die Anleitung um alexa-fhem als Service zu installieren auf einem Raspberry Pi mit Jessie.<br />
<br />
Zunächst einen neuen Benutzer anlegen unter dem alexa-fhem laufen soll, falls man nicht möchtet dass alexa-fhem z.B. mit dem fhem User ausgeführt wird:<br />
<br />
<code lang="bash" style="width:75%;"><br />
sudo useradd -M --system alexa<br />
</code><br />
<br />
Eigentlich braucht der Benutzer keine Gruppen, aber man kann den Benutzer auch der Gruppe <code>dialout</code> hinzufügen (<code>sudo usermod -a -G dialout alexa</code>)<br />
<br />
Datei "alexa.service" unter <code>/etc/systemd/system</code> anlegen:<br />
<br />
[Unit]<br />
Description=Node.js Alexa Server <br />
After=syslog.target network-online.target<br />
<br />
[Service]<br />
Type=simple<br />
User=alexa <br />
WorkingDirectory=/opt/alexa/alexa-fhem<br />
ExecStart=/opt/fhem/alexa-fhem/bin/alexa -U /home/alexa/.alexa<br />
Restart=on-failure<br />
RestartSec=10<br />
KillMode=process<br />
<br />
[Install]<br />
WantedBy=multi-user.target <br />
<br />
Den Pfad <code>/home/alexa/.alexa</code> an die Systemgegebenheiten anpassen. Letztendlich kann die config.json irgendwo liegen, hauptsache alexa-fhem weiß wo. <br />
<br />
Im WorkingDirectory wird der alexa Dienst die Zertifikate suchen.<br />
<br />
Achtung: Natürlich muss der Benutzer auch Zugriff sowohl auf das Verzeichnis mit der config als auch das alexa-fhem Verzeichnis und das WorkingDirectory haben.<br />
<br />
Um den Service zu aktiveren und zu starten helfen folgende Befehle:<br />
sudo systemctl daemon-reload<br />
sudo systemctl enable alexa<br />
sudo systemctl start alexa<br />
<br />
Status abfragen mit<br />
sudo systemctl status alexa<br />
<br />
Log einsehen?<br />
sudo journalctl -u alexa<br />
<br />
(mit <code>-f</code> kann man den follow Modus aktivieren, wie <code>tail -f</code>).<br />
Bei einen reboot startet alexa-fhem jetzt automatisch.<br />
<br />
==== Alexa-Fhem testen ====<br />
Node.Js stellt einen Web-Server am Port 3000 bereit, das oben erzeugte Zertifikat sichert diesen Zugang per SSL ab. Durch Aufruf der Adresse<br />
<code>https://<IP-Adresse des Servers>:3000</code> kann man testen, ob der Alexa-Fhem Service läuft - der Seitenaufruf liefert eine Zeile JSON-Code, beginnend mit<br />
<code>{"header":{"name":"UnsupportedOperationError"...</code><br />
<br />
=== Alexa Device anlegen ===<br />
Das Modul 39_alexa.pm stellt innerhalb von FHEM verschiedene Attribute z.B. alexaName oder alexaRoom zur Verfügung. Manche dieser Attribute (wie z.b. alexaName) werden in beiden Skills verwendet, andere werden ausschließlich bei einer Nutzung des Alexa Custom Skill verwendet.<br />
<br />
Die Einrichtung des Alexa Device geschieht durch die nachfolgende Definition:<br />
<syntaxhighlight lang="bash" style="width:70%;">define MyAlexa alexa</syntaxhighlight><br />
<br />
<hr><br />
<br />
=== Alexa Skills ===<br />
Für folgende Schritte muss man unter der Adresse http://developer.amazon.com angemeldet sein<br />
# Anmeldung auswählen<br />[[Datei:Developer.amazon.com-01-login2.png|200px]]<br />
# Anmeldedaten eingeben<br />[[Datei:Developer.amazon.com-02-userpass2.png|200px]]<br />
<br />
==== Security Profile anlegen ====<br />
Die Erzeugung eines Sicherheitsprofils muss nur einmal erfolgen, es wird dann für alle weiteren Skills verwendet.<br />
# Nach der Anmeldung Auswahl von ''APPS & SERVICES''<br />[[Datei:Developer.amazon.com-03-apps_and_services.png|200px]]<br />
# Anschließend auswählen ''Security Profiles''<br />[[Datei:Developer.amazon.com-05-apps_and_services_-_security_profiles.png|200px]]<br />
# Auswählen ''Create a New Security Profile'' aus<br />[[Datei:Developer.amazon.com-06-apps_and_services_-_create_a_new_security_profile.png|200px]]<br />
# Dann einen Namen und eine Beschreibung für das Profil eingeben und mit ''Save'' bestätigen<br />[[Datei:Developer.amazon.com-07-apps_and_services_-_security_profile_management.png|200px]]<br />
<br />
===== Login with Amazon =====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Hier wird beschrieben, wo ''Client Id'' und ''Client Secret'' zu finden sind}}<br />
# Oben rechts auf ''Login with Amazon'' klicken.<br/>[[Datei:Developer.amazon.com-08-login_with_amazon.png|200px]]<br />
# Auf der neu geladenen Seite auswählen ''Sign up''<br/>[[Datei:Developer.amazon.com-09-login_with_amazon_-_sign_up.png|200px]]<br />
# Anschließend im Dropdown Menü das vorher angelegte Profil auswählen und mit ''Confirm'' bestätigen<br/>[[Datei:Developer.amazon.com-10-login_with_amazon_-_create_new_profile.png|200px]] [[Datei:Developer.amazon.com-11-login_with_amazon_-_create_new_profile2.png|200px]]<br />
# Im folgenden Fenster die Adresse [https://www.amazon.com/gp/help/customer/display.html?nodeId=468496 https://www.amazon.com/gp/help/customer/display.html?nodeId=468496] eingeben und mit ''Save'' bestätigen. '''Todo Erklärungsbedarf: WARUM diese Adresse'''<br/>[[Datei:Developer.amazon.com-12-login_with_amazon_-_enter_consent_screen_information.png|200px]]<br />
# Anschließend bei dem neu angelegten Eintrag auf der rechten Seite auf das Zahnrad klicken und ''Web Settings'' auswählen<br/>[[Datei:Developer.amazon.com-13-login_with_amazon_-_web_settings.png|200px]]<br />
# Im neu geladenen Fenster anklicken von ''Edit''<br/>[[Datei:Developer.amazon.com-14-login_with_amazon_-_edit.png|200px]]<br />
# Anschließend bei ''Allowed Return URLs'' die folgenden drei Adressen eingeben. ''xxx'' muss hierbei durch den Wert ersetzt werden, der in den beiden Abschnitten [[#SmartHome_Skill_anlegen | SmartHome Skill anlegen]] bzw. [[#Custom_Skill_anlegen | Custom Skill anlegen]] jeweils unter Punkt 4 (Seite ''Configuration'') bei ''Redirect Urls'' am Ende der URLs angezeigt wird<br />
## [https://layla.amazon.co.uk/api/skill/link/xxx https://layla.amazon.co.uk/api/skill/link/xxx]<br />
## [https://pitangui.amazon.com/api/skill/link/xxx https://pitangui.amazon.com/api/skill/link/xxx]<br />
## [https://layla.amazon.com/api/skill/link/xxx https://layla.amazon.com/api/skill/link/xxx]<br />
.<br/>[[Datei:Developer.amazon.com-15-login_with_amazon_-_allowed_return_urls.png|200px]]<br />
<br />
==== Skills bearbeiten ====<br />
# Im Menü den Punkt ''ALEXA'' auswählen<br />[[Datei:Developer.amazon.com-03-apps_and_services.png|200px]]<br />
# Anschließend im Feld ''Alexa Skills Kit'' auf ''Get started'' klicken<br />[[Datei:Developer.amazon.com-17-alexa_-_alex_skills_kit_-_get_started.png|200px]]<br />
<br />
===== SmartHome Skill anlegen =====<br />
# Oben rechts ''Add a New Skill'' auswählen<br />[[Datei:Developer.amazon.com-18-alexa_-_alex_skills_kit_-_add_a_new_skill.png|200px]]<br />
# Auf der folgenden Seite eingeben und dann mit ''Next'' bestätigen:<br />
#:* ''Skill Type'' -> ''SmartHome Skill API'' <br />
#:* ''Language'' -> ''German''<br />
#:* ''Name'' -> beliebiger Name, z.B. "MySmartHome Basic")<br />
#:* ''Payload Version'' -> ''v2 (other devices)'' <br/>[[Datei:Developer.amazon.com-19-alexa_-_alex_skills_kit_-_skill_information.png|200px]]<br />
# Die folgende Seite einfach mit ''Next'' überspringen<br />[[Datei:Developer.amazon.com-20-alexa_-_alex_skills_kit_-_interaction_model.png|200px]]<br />
# Auf der Seite ''Configuration'' Folgendes eingeben:<br />
#:* ''Service Endpoint Type'' -> ''AWS Lambda'' ist vorausgewählt und kann nicht geändert werden.<br />
#:* ''Geographical Region'' -> ''Europe'' auswählen und im Textfeld die ARN aus Abschnitt [[#ARN_der_AWS_Lambda_Funktion_bestimmen | AWS Lambda Funktion]] eintragen. <br />
#:* ''Authorization URL'' -> <code>https://www.amazon.com/ap/oa</code><br />
#:* ''Client ID'' -> ''Client ID'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
#:* ''Scope'' -> <code>profile:user_id</code> (wörtlich 1:1 eintragen)<br />
#:* ''Redirect URLs'' - sollten vorbelegt sein<br />
#:* ''Authorization Grant Type'' -> ''Auth Code Grant'' auswählen<br />
#:* ''Access Token URI'' -> <code>https://api.amazon.com/auth/o2/token</code><br />
#:* ''Client Secret'' -> ''Client Secret'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
#:* ''Client Authentication Scheme'' -> ''HTTP Basic''<br />
#:* ''Privacy Policy URL'' -> <code>https://www.amazon.com/gp/help/customer/display.html?nodeId=468496</code><br /><br /><br />
<br />[[Datei:Developer.amazon.com-21-alexa_-_alex_skills_kit_-_configuration.png|200px]] [[Datei:Developer.amazon.com-22-alexa_-_alex_skills_kit_-_test.png|200px]]<br />
<br />
===== Custom Skill anlegen =====<br />
<ol><br />
<li> Oben rechts ''Add a New Skill'' auswählen<br />[[Datei:Developer.amazon.com-18-alexa_-_alex_skills_kit_-_add_a_new_skill.png|200px]]</li><br />
<li> Auf der folgenden Seite (''Skill Information'') die nachstehenden Daten eingeben und dann mit ''Next'' bestätigen:<br />
<ul><br />
<li> ''Skill Type'' -> ''Custom Interaction Model'' </li><br />
<li> ''Language'' -> ''German''</li><br />
<li> ''Name'' -> beliebiger Name, z.B. "MySmartHome Advanced". Dieser wird in der Alexa App unter "Meine Skills" angezeigt.</li><br />
<li> ''Invocation Name'' -> Aufruf des Skills, unter dem dieser später gestartet wird. Z.B. "Alexa, starte James"<br />[[Datei:CustomSkill_2.PNG|400px]]</li><br />
</ul></li><br />
<li>Auf der Seite ''Interaction Model'' folgende Eingaben tätigen und mit ''Next'' abschließen<br />
<ul><br />
<li>In einem separaten Browserfenster FHEM aufrufen, und für das bereits definierte Alexa-Gerät das Kommando <code>get MyAlexa interactionModel</code> aufrufen. Es erscheint ein Popup-Fenster mit ziemlich vielen Zeilen.<br />
<li>In die Box ''Intent Schema'' kopiert man den ersten Teil dieser FHEM-Ausgabe hinein, also:<br/><blockquote><br />
{ <br />
"intents" : [ <br />
<hier ziemlich viele Zeilen> <br />
]<br />
}<br />
</blockquote></li><br />
<li>Nun die ''Custom Slot Types'' einrichten. Dazu muss aus dem zweiten Teil der FHEM-Ausgabe jeweils der Slot-Type (z.B. <code>FHEM_article</code>) in das Feld ''TYPE'' eingetragen werden, das nach dem Anklicken von ''Add Slot Type'' erscheint. In das darunter liegende größere Textfeld kommen die möglichen Werte für diesen Slot, so wie sie aus der FHEM-Ausgabe abzulesen sind. Dann mit ''Save'' sichern. Als Custom Slot Type erscheint dann für diesen Beispiel-Slot<br />
FHEM_article der | die | das | den<br />
d.h., die Zeilenumbrüche bei den möglichen Werten werden als "|" dargestellt.</li><br />
<li>Hier muss nun ein Bruch im Arbeitsfluss durchgeführt werden, denn bei der Erstellung des Custom Skills kommt es auf die Reihenfolge der Einträge an. Deshalb zunächst diese FHEM-Ausgabe schließen, und für dasselbe FHEM-Device <code>get MyAlexa customSlotTypes</code> ausführen. Auch diese Ausgabe wird, wie oben beschriebeen, in Custom Slot Types eingetragen (erst der TYPE, dann die möglichen Werte)<br />
<li>Anschließend erneut die FHEM-Ausgabe schließen und erneut für das bereits definierte Alexa-Gerät das Kommando <code>get MyAlexa interactionModel</code> aufrufen.<br />
<li>Unter ''Sample Utterances'' nun den Text aus dem dritten Teil dieser FHEM-Ausgabe hineinkopieren<br />[[Datei:CustomSkill_5.PNG|400px]]</li><br />
</ul></li><br />
<li>Auf der Seite ''Configuration'' Folgendes eingeben und mit ''Next'' bestätigen:<br />
<ul><br />
<li>''Service Endpoint Type'' -> ''AWS Lambda'' auswählen</li><br />
<li>''Geographical Region'' -> ''Europe'' auswählen und im Textfeld den Wert aus Abschnitt [[#AWS_Lambda_Funktion_anlegen | AWS Lambda Funktion anlegen]] (Punkt 12) eintragen. </li><br />
<li>''Do you allow users to create an account or link to an existing account with you?'' -> ''Yes''</li><br />
<li>''Authorization URL'' -> <code>https://www.amazon.com/ap/oa</code></li><br />
<li>''Client ID'' -> ''Client ID'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1</li><br />
<li>''Scope'' -> <code>profile:user_id</code> (wörtlich 1:1 eintragen)</li><br />
<li>''Redirect URLs'' - sollten vorbelegt sein</li><br />
<li>''Authorization Grant Type'' -> ''Auth Code Grant'' auswählen</li><br />
<li>''Access Token URI'' -> <code>https://api.amazon.com/auth/o2/token</code></li><br />
<li>''Client Secret'' -> ''Client Secret'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1</li><br />
<li>''Client Authentication Scheme'' -> ''HTTP Basic''</li><br />
<li>''Privacy Policy URL'' -> <code>https://www.amazon.com/gp/help/customer/display.html?nodeId=468496</code></li><br />
</ul><br />
Beim Sichern dieser Seite mit ''Next'' kann es zu einer Fehlermeldung kommen, wenn man seine Skill-Definitionen mit dem einfachen SmartHome-Skill begonnen hat. Deshalb muss noch der entsprechende Trigger für die [[#AWS_Lambda-Funktion | AWS Lambda Funktion]] nachgetragen werden, dies wird in Abschnitt [[#Trigger_f.C3.BCr_Custom_Skill_hinzuf.C3.BCgen | Trigger für Custom Skill hinzufügen]] beschrieben.<br />
<br />[[Datei:CustomSkill_6.PNG|400px]] [[Datei:CustomSkill_7.PNG|400px]]</li><br />
<br />
==== Testen ====<br />
Hat man den Custom Skill angelegt, bietet dieser auch eine komfortable Testmöglichkeit. Dazu wählt man in der Übersichtsseite ''All Skills'' den Button ''Edit'' des Alexa Custom Skill aus. Auf der nachfolgenden Seite dann links ''Test''. <br />
Die Testseite enthält <br />
* ein Feld ''Voice Simulator'', mit dem man die Sprachsausgabe testen kann, <br />
* ein Feld ''Service Simulator'', mit dem die Verarbeitung von Alexa-Kommandois getestet werden kann. Hier kann man z.B. eintragen<br />
"Alexa, sage <Custom Skill Invocation Name>: Stelle Weckzeit auf Neunzehn Siebenundzwanzig Uhr"<br />
"Alexa, frage <Custom Skill Invocation Name> nach dem Status von Weckzeit"<br />
Dabei ist natürlich der ''Custom Skill Invocation Name'' durch den Wert zu ersetzen, den man im Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]] unter Punkt 2 eingetragen hat.<br />
<br />
==== Skill Id bestimmen ====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Hier wird beschrieben, wo die ''Alexa Skill Id'' zu finden ist}}<br />
Für das [[#AWS_Lamba_Funktion_anlegen | Anlegen einer ''AWS Lambda Funktion'']] bzw für die [[#Alexa-Fhem_konfigurieren | Konfiguration von Alexa-Fhem]] wird die ''Alexa Skill Id'' benötigt. An diese kommt man wie folgt:<br />
# Anmelden wie unter [[#Alexa_Skills | Alexa Skills]] beschrieben.<br />
# Menüpunkt ''ALEXA'' auswählen, wie [[#Skills_bearbeiten | Skills bearbeiten]] erklärt.<br />
# Beim gewünschten Eintrag auf ''Edit'' klicken<br />[[Datei:Developer.amazon.com-23-alexa_-_alex_skills_kit_-_overview.png|200px]]<br />
# Die Id, die nun oben angezeigt wird, ist die gesuchte. Sie hat typischerweise das Format <code>amzn1.ask.skill.[Zahlen und Bindestriche]</code><br />[[Datei:Aws.amazon.com-06-configure_triggers2.png|200px]]<br />
<br />
<hr><br />
<br />
=== AWS Lambda Funktion ===<br />
Für folgende Schritte muss man unter der Adresse http://aws.amazon.com angemeldet sein<br />
# Anmeldung auswählen<br />[[Datei:Aws.amazon.com-01-site.png|200px]]<br />
# Anmeldedaten eingeben<br />[[Datei:Aws.amazon.com-02-login.png|200px]]<br />
# Den Punkt ''Lambda'' links auf der Startseite auswählen, bzw. im Menü ''Services'' unter ''Compute'' den Menüpunkt ''Lambda'' auswählen<br />[[Datei:Aws.amazon.com-03-lambda.png|200px]]<br />
<br />
==== AWS Lambda Funktion anlegen ====<br />
# Für eine erste Lambda-Funktion den Punkt ''Get Started Now'' auswählen<br />[[Datei:Aws.amazon.com-04-get_started_now.png|200px]]<br />
# Den Blueprint ''Blank function'' auswählen<br />[[Datei:Aws.amazon.com-05-select_blueprint.png|200px]]<br />
# Im neuen Fenster dann auf den gestrichelten Kasten klicken und ''Alexa Smart Home'' auswählen und mit ''Next'' bestätigen<br />[[Datei:Aws.amazon.com-06-configure_triggers1.png|200px]]<br />
## Achtung, es ist möglich, dass dabei ''Alexa Smart Home'' überhaupt nicht angeboten wird. Dann bitte ganz rechts oben in der Ecke nachsehen, welche Region bzw. welches Land ausgewählt ist. Empfohlen wird, ''Ireland'' auszuwählen. Dann erscheint bei den Funktionen auch ''Alexa Smart Home''.<br />
# Bei ''Application Id'' den Wert eintragen, dessen Ermittlung im Abschnitt [[#Skill_Id_bestimmen | Skill Id bestimmen]] beschrieben wird, den Haken bei ''Enable trigger'' setzen und mit ''Next'' bestätigen <br />[[Datei:Aws.amazon.com-06-configure_triggers3.png|200px]]<br />
# Auf der Konfigurationsseite eingeben:<br />
## ''Name'' -> ''FHEM''<br />
## ''Runtime'' -> Node.js 4.3. <br />
## ''Role'' -> ''Choose an existing role'' <br />
### Achtung: wenn es noch keine existing role gibt, zuerst ''Create a custom role'' -> in dem Popup dann ''lambda_basic_execution'' auswählen und auf ''Allow'' klicken sowie bei ''Existing role'' dann ''x'' wählen.<br />
# Auf der Code-Seite wird bzw. im großen Textfeld ist dann der Code aus der Datei ''lambda.js'' im Paket [[#Alexa-Fhem_installieren | Alexa-Fhem]] vollständig einzufügen. Dabei muss noch der Hostname im Quellcode an den eigenen Hostnamen angepasst werden. <br />
# Anschließend alles mit ''Next'' bestätigen.<br />[[Datei:Aws.amazon.com-07-configure_function.png|200px]]<br />
# Auf der Übersichtsseite dann ''Create function'' anklicken<br />[[Datei:Aws.amazon.com-08-review.png|200px]]<br />
<br />
==== Trigger für Custom Skill hinzufügen ====<br />
Editiert man eine Lambda-Funktion, werden auf der Seite ''Triggers'' diejenigen Dienste angezeigt, die diese Funktion aufrufen.<br />
* Hier taucht der Trigger ''Alexa Smart Home'' zusammen mit der ''Application Id'' auf, der bei der Einrichtung des SmartHome-Skills eingetragen wurde.<br />
* Zur Verbindung mit dem Custom Skill ist es nötig, einen zweiten Trigger hinzuzufügen. Durch Anklicken von ''Add Trigger'' wird eine Auswahlseite eingeblendet. Im neuen Fenster dann auf den gestrichelten Kasten klicken und ''Alexa Skills Kit' auswählen und mit ''Next'' bestätigen<br />
<br />
==== ARN der AWS Lambda Funktion bestimmen ====<br />
# Auf der Übersichtsseite oben links den Menüpunkt ''Functions'' aúswählen<br />[[Datei:Aws.amazon.com-09-go_overview.png|200px]]<br />
# Anschließend den Radiobutton der angelegten Funktion ''FHEM'' markieren und im Menü ''Action'' den Punkt ''Show ARN'' auswählen<br />[[Datei:Aws.amazon.com-10-1-show_arn.png|200px]]<br />
# Es wird nun eine ARN Adresse angezeigt, die für den Abschnitt [[#SmartHome_Skill_anlegen| SmartHome Skill anlegen]] benötigt wird<br />[[Datei:Aws.amazon.com-10-2-arn.png|200px]]<br />
<br />
=== Absichern des Zugriffs ===<br />
Natürlich muss der Zugriff auf den von Alexa-Fhem verwendeten Port (default: 3000, Bestandteil des Codes in der AWS Lambda-Funktion) durch die Firewall freigeschaltet werden (auf einer FritzBox unter "Portfreigaben").<br />
<br />
==== Absicherung direkt in Alexa-FHEM ====<br />
Die Kommunikation zwischen Amazon AWS und Alexa-FHEM ist auf die folgenden Arten gesichert:<br />
* Die Verbindung erfolgt per HTTPS<br />
* Es werden nur Verbindung angenommen auf denen ein gültiges Alexa-Event gesendet wird. <br />
* Es werden nur Verbindungen angenommen die ein gültiges und noch nicht abgelaufenes OAuth-Token enthalten. Jedes neue Token wird live bei Amazon auf Gültigkeit geprüft. <br />
* Es werden nur Verbindungen mit lokal konfigurierter Skill-ID angenommen.<br />
* Es ist nicht möglich von außen beliebige FHEM Kommandos zu senden. Die FHEM Kommandos werden nur lokal erzeugt.<br />
<br />
Wer möchte kann Alexa-FHEM natürlich noch weiter absichern. Es gilt aber, dass nicht jedes zusätzliche Glied in der Kette die Sicherheit sondern unter Umständen nur die Angriffsfläche erhöht. Ein falsch konfigurierter und nach aussen offener Apache (oder anderer ReverseProxy) ist unter Umständen ein größeres Risiko als Alexa-FHEM alleine.<br />
<br />
==== Absicherung per ReverseProxy ====<br />
<s>Die Kommunikation zwischen Amazon und FHEM ist wegen der Verwendung von SSL schon verschlüsselt - prinzipiell kann aber jeder von außen mit Alexa-Fhem kommunizieren. Man sollte sich deshalb im Klaren darüber sein, dass dies eine Sicherheitslücke darstellt:</s> Jeder offene Port verleitet zu Angriffen, und mit zunehmender Verbreitung von Alexa steigt auch das Risiko. Es wird deshalb empfohlen, vor den eigentlichen Alexa-Server zur Absicherung einen Apache-Webserver als ReverseProxy zu setzen. Nicht nur ist der Apache eine hervorragend stabile und seit Jahrzehnten getestete Software, sondern die Konfiguration als ReverseProxy erlaubt auch, den Zugriff auf den Alexa-Fhem-Rechner auf die Amazon-Maschinen zu beschränken.<br />
<br />
'''Achtung: Dies ist keine allgemeine Anleitung in Sachen Computersicherheit.''' Im Folgenden gehen wir davon aus, dass <br />
* Grundbegriffe wie Firewall, IP-Ports, SSL und Dynamic DNS vertraut sind<br />
* Ein Apache Webserver (idealerweise auf einer zweiten Maschine) bereits installiert ist und die Konfiguration verstanden wurde (wenn nicht: Es gibt im Netz ''tausende'' von Anleitungen dafür...)<br />
* Ein Servername von einem DynDNS-Anbieter - sagen wir ''myhome.is-my-castle.com'' - bereits von ''außen'' auf unser SmartHome zeigt.<br />
* Alexa-Fhem in einer der oben beschriebenen Basiskonfigurationen läuft, d.h. der Zugriff auf <code>https://myhome.is-my-castle.com:3000</code> ergibt, wie im Punkt [[#Alexa-Fhem_testen|Alexa-Fhem testen]] beschrieben, eine Antwort des Node.js Servers.<br />
<br />
Als erster Schritt zur Absicherung muss das ReverseProxy Modul für den Apache installiert und mit <code>a2enmod</code> aktiviert werden, hierzu sei auf [https://www.digitalocean.com/community/tutorials/how-to-use-apache-http-server-as-reverse-proxy-using-mod_proxy-extension diese Anleitung] verwiesen. Der zweite Schritt besteht darin, den SSL-Zugriff durch ein Passwort abzusichern. Dazu wird auf dem Apache-Rechner das Programm <br />
htpasswd <passwdfile> <username><br />
ausgeführt, das Programm fragt dann nach dem gewünschten Passwort. Wir nehmen im Folgenden an, dass das Passwortfile ''/etc/apache2/htpasswd'' ist, der gesetzte Username ''alexa'' lautet und das Passwort ''my_smarthome'' ist.<br />
<br />
Im dritten Schritt wird nun in das Apache-Konfigurationsfile die Weiterleitung auf den eigentlichen Alexa-Fhem-Rechner eingetragen. Dazu wählen wir, dass von außen der Standard-SSL-Port 443 benutzt werden soll, sowie als Verzeichnisname ''/alexa''. '''Achtung:''' Dieser Code soll '''nicht''' in die Default-Konfiguration des Apache-Webservers. Sondern in eine separate Datei (Dateiname z.B. "fhem"), die ins Unterverzeichnis /etc/apache2/conf.d gestellt wird.<br />
<br />
<VirtualHost *:443><br />
ServerName myhome.is-my-castle.com<br />
SSLEngine on<br />
SSLProxyEngine on<br />
SSLProxyCheckPeerCN off<br />
SSLProxyCheckPeerName off<br />
SSLCertificateKeyFile /etc/apache2/mycert/server.key<br />
SSLCertificateFile /etc/apache2/mycert/server.crt<br />
<Location /alexa><br />
AuthType Basic<br />
AuthName "Authentication Required"<br />
AuthUserFile "/etc/apache2/htpasswd"<br />
Require valid-user<br />
ProxyPass https://<hier IP-Adresse des Alexa-Fhem-Rechners>:3000/<br />
ProxyPassReverse https://<hier IP-Adresse des Alexa-Fhem-Rechners>:3000/<br />
Order deny,allow<br />
Allow from All<br />
</Location><br />
(... Hier eventuell weitere Umleitungen)<br />
</VirtualHost><br />
Nach einem Neustart des Apache-Servers, dem Schließen des Ports 3000 in der Firewall sowie dem Öffnen des Ports 443 ist der Alexa-Fhem-Rechner von außen nur noch erreichbar durch den Aufruf von <code>https://myhome.is-my-castle.com/alexa</code> und verlangt unmittelbar die Eingabe von Username und Passwort.<br />
<br />
Der vierte Schritt ist nun, den Code der AWS Lambda-Funktion an fünf Stellen zu verändern<br />
'''const PORT=443;'''<br />
const HOST='myhome.is-my-castle.com';<br />
'''const PATH='/alexa';'''<br />
'''const AUTH='alexa:my_smarthome';'''<br />
// entry<br />
exports.handler = function(event, context, callback) {<br />
console.log(`EVENT: ${event}`);<br />
console.log(`CONTEXT: ${context}`); <br />
var post_data = JSON.stringify(event);<br />
var options = {<br />
hostname: HOST,<br />
port: PORT,<br />
//family: 6,<br />
'''path: PATH,'''<br />
method: 'POST',<br />
'''auth: AUTH,'''<br />
rejectUnauthorized: false, // accept self-signed<br />
(etc., Rest des Codes wie gehabt)<br />
Natürlich muss der Zugriff getestet werden. Bei Beachtung aller dieser Schritte werden alle un-autorisierten Zugriffe von außen abgewehrt. Eine noch weiter gehende Sicherung ist möglich, dazu kann in der Serverkonfiguration der Zugriff auf die Amazon-Domains beschränkt werden. Das ganze Alexa-System ist aber noch in konstanter Weiterentwicklung, diese Domain-Namen können sich also noch ändern.<br />
<br />
== Einrichtung in der Alexa App==<br />
Nachdem die Alexa Skills angelegt wurden, müssen diese noch in der Alexa App eingerichtet werden.<br />
Dafür jeweils per Desktop-Browser auf [http://alexa.amazon.de alexa.amazon.de] anmelden, nicht die App unter iOS oder Android verwenden. Diese hat Probleme mit der OAuth Verknüpfung.<br />
<br />
=== Alexa Skill ===<br />
# Auf ''Skills'' klicken<br />[[Datei:Alexa.amazon.de-01-startseite.png|200px]]<br />
# Oben rechts ''Meine Skills'' bzw. ''Ihre Skills'' auswählen<br />[[Datei:Alexa.amazon.de-03-meine_skills.png|200px]]<br />
# In der Liste der Skills sollte das angelegte FHEM Skill angezeigt werden. Dieses anklicken<br />[[Datei:Alexa.amazon.de-02-liste_skills.png|200px]]<br />
# Oben Rechts in den Details des Skills auf ''Skill aktivieren'' klicken<br />[[Datei:Alexa.amazon.de-04-skill_details.png|200px]]<br />
# In dem neu geöffneten Fenster die Autorisierung bestätigen<br />[[Datei:Alexa.amazon.de-05-amazon_auth.png|200px]]<br />
# Anschließend sollte die Verbindung erfolgreich aufgebaut worden sein <br />[[Datei:Alexa.amazon.de-06-success.png|200px]]<br />
<br />
=== Geräte ===<br />
# Auf http://alexa.amazon.de anmelden<br />
# Auf ''Smart Home'' klicken<br />[[Datei:Alexa.amazon.de-01-startseite.png|200px]]<br />
# Anschließend den Punkt ''Geräte suchen'' anklicken<br />[[Datei:Alexa.amazon.de-07-Gerätesuche.png|200px]]<br />
# Wurde soweit alles korrekt eingerichtet, werden nun die gefundenen Geräte angezeigt.<br />
<br />
Tip: Es macht Sinn, unter ''Meine Gruppen'' Gruppen benannt nach den Räumen einzurichten. Hierdurch kann Alexa die Geräte besser auseinander halten, vor allem wenn die den gleichen Alias (z.B. "Licht") haben.<br />
<br />
== Einrichtung unter FHEM ==<br />
Im Folgenden werden exemplarisch ein paar Geräte beschrieben, die man nutzbringend mit FHEM einsetzen kann.<br />
<br />
Bei Verwendung des Custom Skills übersetzt die Kombination der Attribute ''alexaMapping'' und ''homebridgeMapping'' Sprachbefehle ("Intents") in gerätespezifische Kommandos. <br />
* Das Attribut alexaMapping wird am Alexa-Device gesetzt und dient dazu, erkannte Sprachkommandos in abstrakte Characteristiken zu überführen. Für den einfacheren SmartHome Skill hat darum das Attribut ''alexaMapping'' keine Bedeutung, sondern nur der ''genericDeviceType'' des zu steuernden Gerätes.<br />
* Das Attribut homebridgeMapping wird für beide Skills am zu steuernden Gerät gesetzt und übersetzt diese Charakteristiken in die konkreten Befehle, die das Gerät versteht. Der inhalt des Attributs wird von links nach rechts ausgewertet und ist wie folgt aufgebaut:<br />
** Das Attribut enthält eine durch Leerzeichen getrennte Liste aus Konfigurationen für jeweils eine Characteristik<br />
** Jede einzelne der Characteristik-Konfigurationen besteht aus dem Namen der Characteristik, gefolgt von "=" und einer kommaseparierten Liste von Parametern.<br />
attr <device> homebridgeMapping <Characteristic1>=<param1.1>,<param1.2>,... <Characteristic2>=<param2.1>,<param2.2>,...<br />
** Jeder Parameter besteht entweder aus<br />
*** <code><cmd>:<device>:<reading></code>, hier können nicht verwendete Elemente von links nach rechts weg gelassen werden.<br />
*** <code><name>=<value></code>, hier kann <code><value></code> entweder ein Wert oder semikolonseparierte Liste sein.<br />
*** Oder dem schlüsselwort <code>clear</code>, welches alle vorhandenen (default) Parameter dieser Characteristik löscht. <code>clear</code> kann auch an Stelle einer ganzen Characteristik-Konfiguration stehen<br />
Weiter führende Dokumentation zum homebridgeMapping findet sich unter https://forum.fhem.de/index.php/topic,48558.0.html<br />
<br />
=== Einfacher Schalter ===<br />
* Ein einfacher Schalter, der die set-Kommandos ''on'' und ''off'' kennt, kann direkt mit Alexa-Fhem gekoppelt werden <br />
* Für kompliziertere Aktionen, etwa das Übermitteln eines spezifischen Schaltbefehls an FHEM, ist die Einrichtung eines Dummies zu empfehlen. <br />
Ob Dummy oder nicht, wichtig sind die drei fett gedruckten Zeilen<br />
define Alexa.Party dummy<br />
'''attr Alexa.Party alexaName party'''<br />
'''attr Alexa.Party alexaRoom alexaroom'''<br />
'''attr Alexa.Party genericDeviceType switch'''<br />
attr Alexa.Party group AlexaGeräte<br />
attr Alexa.Party room AlexaRoom<br />
'''attr Alexa.Party setList on off'''<br />
Selbstverständlich kann man diesen Dummy mit einem notify oder DOIF abfangen, um die gewünschte Schaltaktion auszuführen. <br />
<br />
Ein Alternative zum Dummy ist das Anlegen eines readingsProxy, dem die entsprechenden Attribute gegeben werden.<br />
<br />
Weil es sich hierbei um eines der einfachen Geräte handelt, die Alexa selbst im SmartHome Skill bearbeiten kann, ist auch der zweite Schritt bei der Einrichtung in der Alexa App sinnvoll: Der Schalter wird dann im Bereich Smart Home der Alexa App erkannt. Wer ihn auch mit dem Custon Skill bedienen möchte, muss natürlich Sorge tragen, dass der Alexa-Name ''party'' bei den FHEM_Devices auftaucht und die entsprechenden weiteren Slot Types und Example Utterances in der Konfiguration des Custom Skills vorhanden sind (siehe Abschnitt [[##Custom_Skill_anlegen | Custom Skill Anlegen]]).<br />
<br />
=== Wecker ===<br />
Dieses Gerät kann man nur mit dem Custom Skill bedienen, es wird also '''nicht''' im Bereich Smart Home der Alexa App auftauchen. Wir richten einen Dummy ein, wichtig sind wieder die fett gedruckten Zeilen:<br />
define Alexa.Weckzeit dummy<br />
'''attr Alexa.Weckzeit alexaName weckzeit'''<br />
'''attr Alexa.Weckzeit alexaRoom alexaroom'''<br />
attr Alexa.Weckzeit genericDeviceType clock<br />
attr Alexa.Weckzeit group AlexaGeräte<br />
'''attr Alexa.Weckzeit homebridgeMapping Weckzeit=state,cmd=+'''<br />
attr Alexa.Weckzeit room AlexaRoom<br />
'''attr Alexa.Weckzeit setList Weckzeit:time'''<br />
Das Attribut ''genericDeviceTye'' ist nicht wichtig, weil es ein generisches Device dieser Art gar nicht gibt. Wichtig hingegen ist das Attribut ''homebridgeMapping'' <br />
<br />
Für das Gerät ''MyAlexa'', das in Abschnitt definiert wurde, muss im Attribut ''alexaMapping'' auftauchen<br />
Weckzeit=verb=stelle,valuePrefix=für;auf,values=AMAZON.TIME,valueSuffix=uhr<br />
Darüber hinaus muss der Alexa-Name ''weckzeit'' bei den FHEM_Devices auftauchen und die entsprechenden weiteren Slot Types und Example Utterances in der Konfiguration des Custom Skills vorhanden sein (siehe Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]]).<br />
<br />
Der Aufruf dieses Gerätes mit Alexa erfolgt dann z.B. mit den Sätzen<br />
<pre style="width:50%;"><br />
"Alexa, sage <Custom Skill Invocation Name>: Stelle Weckzeit auf Neunzehn Uhr Siebenundzwanzig"<br />
"Alexa, frage <Custom Skill Invocation Name> nach dem Status von Weckzeit"<br />
</pre><br />
Dabei ist natürlich der ''Custom Skill Invocation Name'' durch den Wert zu ersetzen, den man im Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]] unter Punkt 2 eingetragen hat.<br />
<br />
Zur weiteren Bearbeitung kann man jetzt mit einem DOIF Statusänderungen des Dummies abfangen und durch eine kleine Helperfunktion ins "echte" FHEM weiterleiten.<br />
define Alexa.Weckzeit.N DOIF (["Alexa.Weckzeit:.*"])({AlexaHelper("Alexa.Weckzeit","$EVENT")}) <br />
Die Helperfunktion (z.B. in 99_myUtils.pm) stellt aus der übergebenen Zeit (immer im Format dd:mm) eine sprachkompatible Nachricht $nc und einen mit den FHEM-Zeitangaben kompatiblen String $nt zusammen und reicht beide an eine Routine ''changeWakeTime'' weiter (dokumentiert in den [https://www.dpunkt.de/buecher/12387/9783960090120-smarthome-hacks.html Smart Home Hacks]).<br />
sub AlexaHelper($$){<br />
my ($name,$event)=@_;<br />
if( $name eq "Alexa.Weckzeit" ){ <br />
my ($nc,$nt);<br />
#-- volle Stunde----------------------------------------<br />
if( $event =~ /(\d+):00/ ){<br />
$nc=sprintf("%d Uhr",$1);<br />
$nt=sprintf("%02d:00:00",$1);<br />
#-- nicht volle Stunde---------------------------------<br />
}elsif( $event =~ /(\d+):(\d+)/ ){<br />
$nc=sprintf("%d Uhr %d",$1,$2);<br />
$nt=sprintf("%02d:%02d:00",$1,$2);<br />
}<br />
changeWakeTime(\'GalaxyTab.EG\',\'$nc\',\'$nt\');<br />
}<br />
}<br />
<br />
<hr><br />
<br />
=== Lichtszene ===<br />
Eine Lichtszene wird mit dem Modul LightScene angelegt. Wir gehen davon aus, dass in der Lichtszene die beiden Szenen Alle_An und Alle_Aus, sowie mindestens eine weitere Szene (hier: Sitzgruppe) definiert wurde.<br />
* Nachfolgend wird ein Beispiel beschrieben, wie man eine Lichtszene mit dem einfachen SmartHome Skill steuern kann. Die verwendeten Kommandos sind dann<br />
<pre><br />
"Alexa, schalte (die) Beleuchtung an" -> LightScene Alle_An wird ausgewählt<br />
"Alexa, schalte (die) Beleuchtungsitzgruppe an" -> LightScene Sitzgruppe wird ausgewählt<br />
...<br />
"Alexa, schalte (die) Beleuchtung aus" -> LightScene Alle_Aus wird ausgewählt<br />
</pre><br />
* Künftig wird man LightScene mit dem Custom Skill eventuell direkt steuern können - allerdings hat das einen geringeren WAF, als die Steuerung über den SmartHome Skill: Der Einschaltsatz muss dann mindestens lauten<br />
<pre><br />
"Alexa, sage <Custom Skill Invocation Name>: schalte (die) Beleuchtung an" -> LightScene Alle_An wird ausgewählt<br />
</pre><br />
Dafür wird es aber auch möglich sein direkt die SzenenNamen im gesprochenen Kommando zu verwenden und so auf die Umwege über dummys und ähnliches zu verzichten.<br />
<br />
<br />
Im ersten Schritt wird ein Dummy für die Gesamtbeleuchtung eingerichtet:<br />
define Alexa.Beleuchtung dummy <br />
attr Beleuchtung setList on off<br />
'''attr Alexa.Beleuchtung alexaName beleuchtung'''<br />
'''attr Alexa.Beleuchtung alexaRoom alexaroom'''<br />
'''attr Alexa.Beleuchtung genericDeviceType switch'''<br />
Anschließend wird für jede vorhandene Lichtszene (außer Alle_An und Alle_Aus) ein weiterer Dummy angelegt:<br />
define Alexa.Beleuchtung.Sitzgruppe dummy <br />
attr Beleuchtung setList on off<br />
'''attr Alexa.Beleuchtung.Sitzgruppe alexaName beleuchtungsitzgruppe'''<br />
'''attr Alexa.Beleuchtung.Sitzgruppe alexaRoom alexaroom'''<br />
'''attr Alexa.Beleuchtung.Sitzgruppe genericDeviceType switch''' <br />
Die eigentliche Steuerung übernimmt dann ein DOIF<br />
define Alexa.Beleuchtung.N DOIF<br />
(["Alexa.Beleuchtung.Sitzgruppe:on"])<br />
(set <devicename der Lichtszene> scene Sitzgruppe,<br />
set Alexa.Beleuchtung off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
DOELSIF<br />
... <weitere on-Events der anderen Szenen werden abgefangen><br />
DOELSEIF<br />
(["Alexa.Beleuchtung:on"])<br />
(set <devicename der Lichtszene> scene Alle_An,<br />
set Alexa.Beleuchtung.Sitzgruppe off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
DOELSEIF<br />
(["Alexa.Beleuchtung:off"])<br />
(set <devicename der Lichtszene> scene Alle_Aus,<br />
set Alexa.Beleuchtung.Sitzgruppe off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
Mit diesem DOIF wird ein Radiobutton simuliert, d.h. wie bei den Stationstasten vor Uralt-Radios sorgt die Auswahl einer Szene immer dafür, dass alle anderen Dummies ausgeschaltet werden.<br />
Natürlich kann man das auch mit einem kleinen Perl-Programm erreichen.<br />
<br />
<br />
Zwei andere Ansätze Lichtszenen zu schalten die ohne DOIF auskommen sind im Folgenden beschrieben:<br />
<br />
* Wenn es von Interesse ist die Steuerung mit einer Darstellung in FTUI zu verbinden: Statt der oben beschriebenen dummy Devices kann man readingsProxy Devices mit passenden setFn und valueFn analog zum [[Harmony#Button_f.C3.BCr_eine_bestimmte_Activity_im_Frontend_und_Homekit_.C3.BCber_readingsProxy|diesem Beispiel für harmony aktivitäten]] verwenden.<br />
<br />
* Für jede zu schaltende Szene wird ein dummy angelegt dessen homebridgeMapping direkt auf das LightScene Device zeigt:<br />
<br />
define <dummy> dummy<br />
attr <dummy> setList on off<br />
attr <dummy> genericDeviceType switch<br />
attr <dummy> homebridgeMapping On=<light scene>::state,valueOn=<szene>,cmdOn=scene+<szene>,cmdOff=scene+<szene aus><br />
<br />
Bei der zweiten Variante wird davon ausgegangen das der aktuelle status nicht abgefragt oder angezeigt werden soll. Deshalb gibt es keine direkte RadioButton Funktionalität.<br />
<br />
== Nutzung ==<br />
Um den Namen zu bestimmen, unter dem ein Gerät mit Alexa angesprochen wird, verwendet Alexa-Fhem mit absteigender Priorität:<br />
* das alexaName Attribut<br />
* das alias Attribut<br />
* das NAME Internal<br />
Damit Alexa ein Gerät eindeutig identifizieren kann, sollten eindeutige Gerätenamen verwendet werden, bestehed möglichst aus einem Wort und ohne Ziffern. Wenn Alexa einen Namen nicht versteht, kann man unter [http://alexa.amazon.de/spa/index.html] nachsehen was tatsächlich verstanden wurde und den Gerätenamen ggf. anpassen.<br />
<br />
=== SmartHome Skill ===<br />
Gruppen (Räume) müssen in der Alexa App konfiguriert werden. Über das API lassen sich nur der Name und die Schalteigenschaften übergeben.<br />
<br />
Nach erfolgreicher Einrichtung des SmartHome Skills sollte Alexa mit den folgenden Befehlen nutzbar sein:<br />
<pre style="width:50%;"><br />
“alexa, schalte <gerät/gruppe> ein”<br />
“alexa, schalte <gerät/gruppe> aus”<br />
“alexa, stelle <gerät/gruppe> auf <wert> prozent”<br />
“alexa, stelle <gerät/gruppe> auf <anzahl> grad”<br />
“alexa, erhöhe <gerät/gruppe> um <anzahl> prozent”<br />
“alexa, reduziere <gerät/gruppe> um <anzahl> prozent”<br />
“alexa, erhöhe <gerät/gruppe> um <anzahl> grad”<br />
“alexa, reduziere <gerät/gruppe> um <anzahl> grad”<br />
</pre><br />
<br />
=== Custom Skill ===<br />
Der Custom Skill erlaubt im Gegensatz zum SmartHome Skill eine weitreichende Konfiguration der möglichen Kommandos.<br />
<br />
Das Prinzip der Kommandokonfiguration ist {{Link2Forum|Topic=60244|Message=532513|LinkText=im Forum}} beschrieben.<br />
<br />
TODO: Abfragen, Attribute (alexaMapping, alexaTypes, fhemIntents, articles, prepositions)<br />
<br />
== Troubleshooting ==<br />
<br />
====Allgemeiner Hinweis====<br />
Besonders wichtig ist, dass man sich sehr genau an diese Anleitung hält. Ein häufiger Fehler ist, dass die einfachen Anführungszeichen in der Anleitung unter '''AWS Lambda Funktion anlegen''' Punkt 8 einfach weggelassen werden. Diese sind zwingend notwendig. Es darf auch nur der reine Hostname eingetragen werden. Also kein ''http://'' davor. Entweder eine feste IP Adresse oder den Hostnamen, um den Rechner zu erreichen, den ihr über den Port 3000 freigegeben habt. Das sollte dann so aussehen:<br />
<pre style="width:50%;"><br />
const PORT=3000;<br />
const HOST='mein.host.name';<br />
</pre><br />
<br />
====Freigabe von Port 3000====<br />
{{Randnotiz|RNTyp=Fehl|RNText=Derzeit müsst ihr über einen echten IPv4 Anschluss verfügen, damit der Amazon Lambda-Server euch erreichen kann. DS-Lite Anschlüsse wie die von <b>UnityMedia</b> z.B. funktionieren derzeit leider nicht. Eine möglicher "Workaround" wird hier beschrieben: https://forum.fhem.de/index.php/topic,60244.msg518276.html#msg518276}}<br />
<br />
Auf dem Router muss der Port 3000 Protokoll TCP freigegeben werden. D.h. von außen muss man wenn man den Port 3000 aufruft, auf dem intern laufenden node.js Alexa-Dienst zugreifen können.<br />
Je nach Router gestaltet sich das Portforwarding bzw. die Portumleitung etwas schwieriger.<br />
<br />
Bei einem Speedport Router der Telekom beispielsweise, muss der Router komplett neu gestartet werden, wenn die Portfreigabe eingerichtet wurde. <br />
<br />
Bei der Fritz!Box ist das nicht nötig, bei dieser finden die Freigabe unter ''Internet -> Freigaben -> Portfreigaben'' statt. Dort wählt man dann den Rechner aus und richtet eine neue Freigabe ein. Wichtig hierbei ist, dass man Portfreigabe auswählt und nicht MyFRITZ!-Freigabe. Bei Port von bis trägt man 3000 ein, bei Port extern ebenfalls.<br />
<br />
Um die Portweiterleitung zu testen, solltet ihr euch auch nicht im gleichen Netz befinden. Viele Router blockieren den Netzaufruf aus dem gleichen Netz. Am besten testet ihr es, wenn ihr an eurem Mobiltelefon W-LAN deaktiviert und im Browser folgende Seite aufruft: ''https://mein.hostname:3000''. Wenn ihr im Browser dann einen Quellcode von Alexa seht, funktioniert die Portumleitung.<br />
<br />
Wenn bis hier alles funktioniert und es läuft dennoch nicht rund, liegt das Problem woanders. Kommt z.B. bei der Gerätesuche kein Request rein (sichtbar auf dem Bildschirm, wenn bin/alexa gestartet wurden), kann evtl. der Lambda-Dienst falsch konfiguriert sein.<br />
<br />
====Probleme mit node.js - npm install====<br />
<br />
Falls eine Fehlermeldung auftritt, dass "npm" nicht gefunden werden kann, bitte NodeJS entsprechend der Anleitung im Homebridge-Artikel vorgehen: [[Homebridge_einrichten#NodeJS_installieren|NodeJS installieren]] sowie [[Homebridge_einrichten#Python.2C_g.2B.2B.2C_MDNS_installieren|Python, g++, MDNS installieren]], siehe auch folgenden Abschnitt.<br />
<br />
====Es kommen diverse Fehlermeldungen beim Starten von alexa-fhem und es beendet sich====<br />
Wenn man auf der Konsole angemeldet ist, den Befehl<syntaxhighlight lang="bash" style="width:50%;">node -v</syntaxhighlight>eingeben. Ist die Version niedriger als die geforderte 0.12, muss eine neuere installiert werden. Hier darf man dann im Wiki unter [[Homebridge_einrichten#NodeJS_installieren]] nachschauen. NodeJS V4 sollte hierbei schon ausreichen. Solange die node.js Version nicht passt, gar nicht groß rum experimentieren! Bitte beachtet, dass alle Voraussetzungen unter [[Alexa-Fhem#Voraussetzungen]] erfüllt sind! Keine Experimente mit Versionen die darunter liegen.<br />
<br />
====Fehlermeldung ''NAT-PMP failed: Error: timeout'' Fehler angezeigt beim Start von alexa-fhem====<br />
Wenn ihr dann alexa-fhem über die Konsole startet und bekommt folgenden Fehler: ''NAT-PMP failed: Error: timeout'', lasst euch davon nicht irritieren. Das bedeutet lediglich, dass der Port nicht automatich freigegeben wurde über uPNP. Alternativ prüft, ob die Funktion der Portfreigabe via uPNP auf eurem Router aktiviert ist.<br />
<br />
====Nach Start auf der Console beendet sich Alexa-FHEM sofort wieder====<br />
Unmittelbar nach dem Start von Alexa-FHEM werden ein paar UPNP Fehlermeldungen ausgegeben. Unmittelbar danach beendet sich Alexa-FHEM wieder. <br />
<br />
Viele scheinen ein Problem mit UPNP auf dem Raspberry Pi zu haben. Wenn dieses Problem auftritt einfach in der <code>~/.alexa/config.json</code> die folgenden Zeilen rauslöschen:<br />
<br />
<pre><br />
"nat-pmp": "10.0.1.1",<br />
"nat-upnp": true,<br />
</pre><br />
<br />
Jetzt erneut Alexa-FHEM starten. Sollte nun laufen.<br />
<br />
====Was ist zu tun, wenn alexa-fhem keine Geräte findet?====<br />
Zunächst müssen die Geräte, die angesprochen werden wollen, unter FHEM ein neues Attribut zugewiesen bekommen. Dazu das Gerät in FHEM öffnen und das Attribut ''genericDeviceType switch'' hinzufügen, wenn es ein Schalter mit der Funktiona AN/AUS sein soll. Wenn man will, kann man dem Gerät jetzt noch über das Attribut ''alias'' eine besseren Namen geben, mit dem Alexa das Gerät dann auch finden kann.<br />
Anschließend muss alexa-fhem neu gestartet werden und die definierten Geräte sollten nun gefunden werden.<br />
<br />
====Was ist zu tun, wenn Alexa zwar Geräte findet, diese aber nicht angesprochen werden können?====<br />
Zuerst die Informationen zum Datenfluss ganz oben ansehen. Dann am besten von hinten nach vorne vorgehen:<br />
* wenn nichts bei alexa-fhem ankommt: port forwarding prüfen<br />
* wenn lambda.js nichts los wird: im cloudwatch log nachsehen<br />
* wenn bei lambda.js nichts ankommt: den trigger prüfen<br />
<br />
<br />
Zunächst sollte man sich unter ''http://aws.amazon.com'' das Logfile seiner erstellten Funktion anschauen. Ist überhaupt ein Logfile vorhanden? Falls nicht, liegt es vermutlich am Trigger.<br />
Den solltet ihr überprüfen. Scheinbar kommt es hin und wieder vor, dass dieser nicht gesetzt ist. Dazu einfach auf ''Triggers'' klicken und mit ''Add trigger'' erneut einen anlegen. Hier muss, wie in der Anleitung unter '''AWS Lambda Funktion anlegen''' Punkt 7, die ''Application Id'' stehen und der Haken bei ''Enable trigger'' gesetzt sein. Dann alexa-fhem neu starten.<br />
Wenn ihr Änderugen gemacht habt und den alexa-fhem Dienst noch nicht neu gestartet habt, wäre jetzt der richtige Zeitpunkt.<br />
<br />
<br />
Es kann sein, dass immer noch keine Log im Cloudwatch ([http://docs.aws.amazon.com/de_de/lambda/latest/dg/monitoring-functions-logs.html]) zu sehen ist. In dem Fall hilft es, eine neue Role Policy anzulegen. <br />
* in der AWS Console [https://console.aws.amazon.com] oben links auf Services klicken, und in der Gruppe "Security, Identity & Compliance" auf IAM klicken<br />
* links auf Roles klicken<br />
* Auf dem Knopf "Create Role" klicken<br />
* AWS Services > Lambda auswählen, unten auf Next:Permissions klicken<br />
* im Filter / Policy Type, "log" eintragen (ohne quotes)<br />
* CloudWatchLogsFullAccess hacken, auf Next:Review unten klicken<br />
* Name vergeben und mit "Create role" bestätigen<br />
* Oben links auf Services klicken, und in der Gruppe "Compute", auf Lambda klicken<br />
* auf den Name der Funktion klicken<br />
* Reiter Configuration auswählen<br />
* in Existing Role, den neukreierten Role auswählen<br />
* oben auf Save (und Testen wenn gewünscht) klicken.<br />
Schon sollte eine neue Gruppe im Cloudwatch sichtbar sein. Die Suche von den Devices in Alexa wiederholen, und die Logs analysieren<br />
<br />
====Was ist zu tun, wenn sich der Alexa-Service nicht starten lässt?====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Der User in der User= Directive von alexa.service muss Ausführungsrecht auf dem alexa binary haben (x), so wie auch mind. Lesezugriff auf dem Verzeichnis nach -U Option in der ExecStart= Directive und auch auf dem WorkingDirectory }}<br />
Schaut bitte in das Unterverzeichnis [alexa-fhem (also dort, wo Ihr Alexa-FHEM instelliert habt]/bin. Die dort befindliche Datei ''alexa'' muss ausführbar sein. Also z.B. so:<br />
<syntaxhighlight lang="bash" style="width:70%;">2755327 4 -rwxr-xr-x 1 pi pi 339 Nov 26 23:20 alexa</syntaxhighlight><br />
Sollte dies nicht der Fall sein bitte mit:<br />
<syntaxhighlight lang="bash" style="width:70%;">chmod +x alexa</syntaxhighlight><br />
die Datei ausführbar machen. Sofern der User "pi" Eigentümer ist, ist kein sudo erforderlich.<br />
<br />
Eine lauffähige Konfiguration ist {{Link2Forum|Topic=71612|Message=668383|LinkText=hier}} zu sehen.<br />
<br />
Ein Fehler in der Rechtekonfiguration führt in der Regel zu folgendem Ergebnis nach <code>sudo systemctl status alexa</code>:<br />
<br />
<syntaxhighlight lang="bash"> Loaded: loaded (/etc/systemd/system/alexa.service; enabled)<br />
Active: activating (auto-restart) (Result: exit-code) since mer. 2017-09-06 02:33:23 CEST; 3s ago<br />
Process: 18332 ExecStart=/opt/fhem/alexa-fhem/bin/alexa -U /home/alexa/.alexa (code=exited, status=217/USER)<br />
Main PID: 18332 (code=exited, status=217/USER)</syntaxhighlight><br />
<br />
====Wie kann ich via Alexa-FHEM auf FHEM zugreifen, wenn der Port mit Benutzername/Kennwort geschützt ist?====<br />
<br />
Hierzu muss die Datei <code>~/.alexa/config.json</code> geöffnet werden und der Abschnitt "connections" um folgende Zeile ergänzt werden:<pre><br />
"auth": {"user": "fhem", "pass": "fhempassword"},</pre><br />
Bei Verwendung von SSL bei FHEM muss auch noch <pre><br />
"ssl": true,</pre> hinzugefügt werden<br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Sprachsteuerung]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=HTTPMOD&diff=22568HTTPMOD2017-09-16T12:28:20Z<p>Amenomade: /* Further replacements of URL, header or post data */ kosmetisch</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Extract information from devices with an HTTP interface (or, more generic, from any URL) or send information to such devices <br />
|ModType=d<br />
|ModCmdRef=HTTPMOD<br />
|ModForumArea=Sonstiges<br />
|ModTechName=98_HTTPMOD.pm<br />
|ModOwner=StefanStrobel ({{Link2FU|3960|Forum}} / [[Benutzer:StefanStrobel|Wiki]])<br />
}}<br />
<br />
HTTPMOD provides a generic way to retrieve information from devices with an HTTP Interface and store them in Readings or send information to such devices. It queries a given URL with Headers and data defined by attributes. <br />
<br />
From the HTTP response it extracts readings named in attributes using Regexes, JSON or XPath parsing also defined by attributes.<br />
<br />
In an advanced [[Konfiguration|configuration]] the module can also send information to devices. To do this, a generic <code>set</code> option can be configured using attributes. <br />
<br />
== Availability == <br />
The module is part of the regular FHEM distribution.<br />
<br />
== Prerequisites ==<br />
This module uses the non blocking HTTP function <code>HttpUtils_NonblockingGet</code> provided by FHEM's [[HttpUtils]] in a new version published in December 2013.<br />
If not already installed in your environment, please [[update]] FHEM or install it manually using appropriate commands from your environment.<br />
Please also note that FHEM HttpUtils need the global attribute dnsServer to be set in order to work really non blocking even when dns requests can not be answered.<br />
<br />
== Define ==<br />
<syntaxhighlight lang="perl"><br />
define <name> HTTPMOD <URL> <Interval><br />
</syntaxhighlight><br />
The module connects to the given <code>URL</code> every <code>Interval</code> seconds, sends optional headers and data and then parses the response with regular expressions, xpath or json to set readings.<br />
<br />
URL can be "none" and Interval can be 0 if you prefer to only query data with a get command and not in a defined interval.<br />
<br />
Example:<br />
<syntaxhighlight lang="perl"><br />
define PM HTTPMOD http://MyPoolManager/cgi-bin/webgui.fcgi 60<br />
</syntaxhighlight><br />
<br />
== Set-Commands ==<br />
can be defined using attributes, see advanced configuration<br />
<br />
If you set the attribute enableControlSet to 1, the following additional built in set commands are available:<br />
;interval<br />
:set new interval time in seconds and restart the timer<br />
;reread<br />
:request the defined URL and try to parse it just like the automatic update would do it every Interval seconds without modifying the running timer.<br />
;stop<br />
:stop interval timer.<br />
;start<br />
:restart interval timer to call GetUpdate after interval seconds<br />
;upgradeAttributes<br />
:convert outdated attributes for older HTTPMOD-Versions that are still defined for this device from the old syntax to the new one.<br />
:attributes with the description "this attribute should not be used anymore" or similar will be translated to the new syntax, e.g. readingsName1 to reading01Name.<br />
;storeKeyValue<br />
:stores a key value pair in an obfuscated form in the file system. Such values can then be used in replacements where the mode is "key" e.g. to avoid storing passwords in the configuration in clear text<br />
<br />
== Get-Commands ==<br />
can be defined using attributes, see advanced configuration<br />
<br />
== simple Attributes ==<br />
;do_not_notify<br />
<br />
;readingFnAttributes<br />
<br />
;requestHeader.* <br />
:Define an additional HTTP Header to set in the HTTP request<br />
<br />
;requestData<br />
:POST Data to be sent in the request. If not defined, it will be a GET request as defined in HttpUtils used by this module<br />
<br />
;reading[0-9]+(-[0-9]+)?Name<br />
:the name of a reading to extract with the corresponding readingRegex<br />
<br />
;reading[0-9]*(-[0-9]+)?OExpr<br />
:defines an expression that is used in an eval to compute the readings value. The raw value will be in the variable $val.<br />
<br />
;reading[0-9]*(-[0-9]+)?OMap<br />
:Output Map. Defines a mapping from raw to visible values like "0:mittig, 1:oberhalb, 2:unterhalb". If specified as readingOMap then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*OMap.<br />
<br />
;reading[0-9]*(-[0-9]+)?Format<br />
:Defines a format string that will be used in sprintf to format a reading value. If specified as readingFormat then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Format.<br />
<br />
;reading[0-9]*(-[0-9]+)?Decode<br />
:defines an encoding to be used in a call to the perl function decode to convert the raw data string read from the device to a reading. This can be used if the device delivers strings in an encoding like cp850 instead of utf8.<br />
<br />
;reading[0-9]*(-[0-9]+)?Encode<br />
:defines an encoding to be used in a call to the perl function encode to convert the raw data string read from the device to a reading. This can be used if the device delivers strings in an encoding like cp850 and after decoding it you want to reencode it to e.g. utf8.<br />
<br />
;reading[0-9]+Regex<br />
:defines the regex to be used for extracting the reading. The value to extract should be in a capture group / sub expression <br />
:e.g. ([\d\.]+) in the above example. Multiple capture groups will create multiple readings (see explanation above)<br />
<br />
;reading[0-9]+XPath<br />
:defines an xpath to one or more readings when parsing HTML data (see examples below)<br />
<br />
;reading[0-9]+XPath-Strict<br />
:defines an xpath to one or more readings when parsing XML data (see examples below)<br />
<br />
;reading[0-9]+JSON<br />
:defines a path to the JSON object wanted by concatenating the object names with an underscore as delimiter (see the example below)<br />
<br />
;noShutdown<br />
:pass the noshutdown flag to HTTPUtils for webservers that need it (some embedded webservers only deliver empty pages otherwise)<br />
<br />
;disable<br />
:stop doing automatic HTTP requests while this attribute is set to 1<br />
<br />
;timeout<br />
:time in seconds to wait for an answer. Default value is 2<br />
<br />
;enableControlSet<br />
:enables the built in set commands ''interval'', ''stop'', ''start'', ''reread'', ''upgradeAttributes'', ''storeKeyValue''<br />
<br />
== Simple Configuration of HTTP Devices ==<br />
If your device expects special HTTP-headers then specify them as <code>attr requestHeader1</code> to <code>attr requestHeaderX</code>.<br />
If your Device expects an HTTP POST instead of HTTP GET then the POST-data can be specified as <code>attr requestData</code>.<br />
To get the readings, specify pairs of <code>attr readingXName</code> and <code>attr readingXRegex</code>, <code>attr readingXXPath</code>, <code>attr readingXXPath-Strict</code> or <code>attr readingXJSON</code> to define which readings you want to extract from the HTTP response and how to extract them. (The old syntax <code>attr readingsNameX</code> and <code>attr readingsRegexX</code> is still supported but the new one with <code>attr readingXName</code> and <code>attr readingXRegex</code> should be preferred. The actual values to be extracted have to be sub expressions within () in the regex (see example below)<br />
<br />
=== Example for a PoolManager 5: ===<br />
The PoolManager Web GUI can be queried with HTTP POST Requests like this one:<br />
<br />
<syntaxhighlight lang="perl"><br />
POST /cgi-bin/webgui.fcgi HTTP/1.1<br />
Host: 192.168.70.90<br />
Accept: */*<br />
Content-Type: application/json;charset=UTF-8<br />
Content-Length: 60<br />
<br />
{"get" :["34.4001.value" ,"34.4008.value" ,"34.4033.value"]}<br />
</syntaxhighlight><br />
<br />
The resulting HTTP Response would look like this:<br />
<br />
<syntaxhighlight lang="perl"><br />
HTTP/1.1 200 OK<br />
Content-type: application/json; charset=UTF-8<br />
Expires: 0<br />
Cache-Control: no-cache<br />
Date: Sun, 12 Jan 2014 12:23:11 GMT<br />
Server: lighttpd/1.4.26<br />
Content-Length: 179<br />
<br />
{<br />
"data": {<br />
"34.4001.value": "7.00",<br />
"34.4008.value": "0.52",<br />
"34.4033.value": "24.8"<br />
},<br />
"status": {<br />
"code": 0<br />
},<br />
"event": {<br />
"type": 1,<br />
"data": "48.30000.0"<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
To configure HTTPMOD for a PoolManager one would first define a PoolManager device with e.g. the name PM, the URL and an interval of e.g. 60 seconds. <br />
<br />
Then the data to be sent in the request needs to be defined because in this example the device expects a POST request so the query is not contained in the URL but in the request data.<br />
<br />
Also as seen above the device expects special HTTP headers in the request so these headers also need to be defined as <code>attr PM requestHeader1</code> and <code>attr PM requestHeader2</code><br />
<br />
Then the names of the readings to be extracted would be set with attributes<br />
<br />
Then for each reading value to be extracted a regular expression needs to be set that will match the value in question within ().<br />
<br />
Example:<br />
<syntaxhighlight lang="perl"><br />
define PM HTTPMOD http://MyPoolManager/cgi-bin/webgui.fcgi 60<br />
attr PM reading01Name PH<br />
attr PM reading01Regex 34.4001.value":[ \t]+"([\d\.]+)"<br />
<br />
attr PM reading02Name CL<br />
attr PM reading02Regex 34.4008.value":[ \t]+"([\d\.]+)"<br />
<br />
attr PM reading03Name3TEMP<br />
attr PM reading03Regex 34.4033.value":[ \t]+"([\d\.]+)"<br />
<br />
attr PM requestData {"get" :["34.4001.value" ,"34.4008.value" ,"34.4033.value", "14.16601.value", "14.16602.value"]}<br />
attr PM requestHeader1 Content-Type: application/json<br />
attr PM requestHeader2 Accept: */*<br />
attr PM stateFormat {sprintf("%.1f Grad, PH %.1f, %.1f mg/l Chlor", ReadingsVal($name,"TEMP",0), ReadingsVal($name,"PH",0), ReadingsVal($name,"CL",0))}<br />
</syntaxhighlight><br />
<br />
<br />
=== Example for AmbientMonitor ===<br />
AmbientMonitor is a webbased visualisation for sensors connected to an Arduino device. Its web interface can also be queried with HTTMOD to grab the data into readings.<br />
<br />
This example was provided by locutus. The hardware configuration is an Arduino + Ethercard with ENC28J60 Controller + DHT22 Sensor and software can be downloaded from https://github.com/lucadentella/AmbientMonitor<br />
<br />
In this example an HTTP GET is sufficent, so no <code>requestData</code> is needed. The device provides temperature and humidity readings in an HTTP response that looks like:<br />
<syntaxhighlight lang="perl"><br />
HTTP/1.0 200 OK <br />
Content-Type: text/html <br />
<br />
myCB({'temperature':22.00,'humidity':46.00})<br />
</syntaxhighlight><br />
<br />
the definition could be:<br />
<syntaxhighlight lang="perl"><br />
define AmbientMonitor HTTPMOD http://192.168.1.221/?callback=? 300<br />
attr AmbientMonitor requestHeader Content-Type: application/json<br />
attr AmbientMonitor reading1Name Temperatur<br />
attr AmbientMonitor reading1Regex temperature':([\d\.]+)<br />
attr AmbientMonitor reading2Name Feuchtigkeit<br />
attr AmbientMonitor reading2Regex humidity':([\d\.]+)<br />
attr AmbientMonitor stateFormat {sprintf("Temperatur %.1f C, Feuchtigkeit %.1f %", ReadingsVal($name,"Temperatur",0), ReadingsVal($name,"Feuchtigkeit",0))}<br />
</syntaxhighlight><br />
<br />
<br />
== formatting and manipulating values / readings ==<br />
Values that are parsed from an HTTP response can be further treated or formatted with the following attributes:<br />
<br />
* <code>(reading|get)[0-9]*(-[0-9]+)?OExpr</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?OMap</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?Format</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?Decode</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?Encode</code><br />
<br />
They can all be specified for an individual reading, for all readings in one match (e.g. if a regular expression has several capture groups) or for all readings in a get command (defined by getXX) or for all readings in the main reading list (defined by readingXX):<br />
<syntaxhighlight lang="perl"><br />
reading01Format %.1f<br />
</syntaxhighlight><br />
<br />
will format the reading with the name specified by the attribute reading01Name to be numerical with one digit after the decimal point.<br />
If the attribute reading01Regex is used and contains several capture groups then the format will be applied to all readings parsed by this regex unless these readings have their own format specified by reading01-1Format, reading01-2Format and so on.<br />
<br />
<syntaxhighlight lang="perl"><br />
reading01-2Format %.1f<br />
</syntaxhighlight><br />
<br />
Can be used in cases where a regular expression specified as reading01regex contains several capture groups or an xpath specified as reading01XPath creates several readings. <br />
In this case reading01-2Format specifies the format to be applied to the second match.<br />
<br />
<syntaxhighlight lang="perl"><br />
readingFormat %.1f<br />
</syntaxhighlight><br />
<br />
applies to all readings defined by a reading-Attribute that have no more specific format.<br />
<br />
If you need to do some calculation on a raw value before it is used as a reading, you can define the attribute <code>readingOExpr</code>.<br />
It defines a Perl expression that is used in an eval to compute the readings value. The raw value will be in the variable $val.<br />
<br />
Example for an expression:<br />
<syntaxhighlight lang="perl"><br />
attr PM reading03OExpr $val * 10<br />
</syntaxhighlight><br />
Just like in the above example of the readingFormat attributes, readingOExpr and the other following attributes can be applied on several levels.<br />
<br />
To map a numerical value to a name, you can use the readingOMap attribute. <br />
It defines a mapping from raw to visible values like "0:mittig, 1:oberhalb, 2:unterhalb".<br />
<br />
Example for a map:<br />
<syntaxhighlight lang="perl"><br />
attr PM reading02-3OMap 0:kalt, 1:warm, 2:sehr warm<br />
</syntaxhighlight><br />
<br />
To convert character sets, the module can first decode a string read from the device and then encode it again. For example:<br />
<syntaxhighlight lang="perl"><br />
attr PM getDecode UTF-8<br />
</syntaxhighlight><br />
<br />
This applies to all readings defined for Get-Commands.<br />
<br />
== Some help with Regular Expressions ==<br />
If HTTPMOD seems not to work and the FHEM Logfile contains a message like <br />
:<code>HTTPMOD: Response didn't match Reading ...</code><br />
then you should check if the value you want to extract is read into the internal with the name buf. Internals are visible when you click on the defined HTTPMOD Device. buf is an internal variable that contains the HTTP Response read. If the value is there and you get the mentioned message then probably something is wrong with your regular expression. Please note that buf might contain special characters like newlines but they are not shown in fhemweb. If you are new to regular expressions then the introduction at http://perldoc.perl.org/perlretut.html might be helpful. <br />
<br />
For a typical HTTPMOD use case where you want to extract a number out of a HTTP-Response you can use something like <code>[\d\.]+</code> to match the number itself. The expression matches the number characters (<code>\d</code>) or a <code>.</code> if one of these characters occurs at least once. <br />
<br />
To tell HTTPMOD that the number is what you want to use for the reading, you have to put the expression in between <code>()</code>. A <code>([\d\.]+)</code> alone would match the longest number in the HTTP Response which is very likely not the number you are looking for so you need to add something to the expression to give it a context and define how to find the number that you are looking for.<br />
<br />
If there is a title text before the number or a special text after the number you can put this in the regex. In one of the examples above <code>humidity':([\d\.]+)</code> is looking for the number that immediately follows the text <code>humidity':</code> without any blanks in between.<br />
Be careful if the text you are getting from your device contains special characters like newline. You don't see such special characters in the fhem webinterface as contents of the internal buf but they might cause your regular expression to fail. <br />
<br />
If you have trouble defining a regular expression that matches a certain name, then many complicated characters and then a number, it might be helpful to use a negation in matching like <code>temp[^\d]+([\d\.]).*</code>. In this examle <code>[^\d]+</code> means any character that is not a numerical digit, more than once.<br />
<br />
=== Regular Expressions with multiple capture Groups ===<br />
The regular expressions used in the above example for a Poolmanager will take the value that matches one capture group. This is the part of the regular expression inside (). In the above example "([\d\.]+)" refers to numerical digits or points between double quotation marks. Only the string consiting of digits and points will match inside (). This piece is assigned to the reading.<br />
<br />
You can also use regular expressions that have several capture groups which might be helpful when parsing tables. In this case an attribute like <br />
<br />
<syntaxhighlight lang="perl"><br />
reading02Regex something[ \t]+([\d\.]+)[ \t]+([\d\.]+)<br />
</syntaxhighlight><br />
<br />
could match two numbers. When you specify only one reading02Name like <br />
<syntaxhighlight lang="perl"><br />
reading02Name Temp<br />
</syntaxhighlight><br />
<br />
the name Temp will be used with the extension -1 and -2 thus giving a reading Temp-1 for the first number and Temp-2 for the second. You can also specify individual names for several readings that get parsed from one regular expression with several capture groups by defining attributes <br />
<br />
<syntaxhighlight lang="perl"><br />
reading02-1Name<br />
reading02-2Name<br />
...<br />
</syntaxhighlight><br />
The same notation can be used for formatting attributes like readingXOMap, readingXFormat and so on.<br />
<br />
The usual way to define readings is however to have an individual regular expression with just one capture group per reading as shown in the above example.<br />
<br />
== Parsing JSON ==<br />
<br />
If a webservice delivers data in JSON format, HTTPMOD can directly parse JSON which might be easier in this case than definig regular expressions.<br />
The next example shows the data that can be requested from a Poolmanager with the following partial configuration:<br />
<br />
<syntaxhighlight lang="perl"><br />
define test2 HTTPMOD none 0<br />
attr test2 get01Name Chlor<br />
attr test2 getURL http://192.168.70.90/cgi-bin/webgui.fcgi<br />
attr test2 getHeader1 Content-Type: application/json<br />
attr test2 getHeader2 Accept: */*<br />
attr test2 getData {"get" :["34.4008.value"]}<br />
</syntaxhighlight><br />
<br />
The data in the HTTP response looks like this:<br />
<br />
<syntaxhighlight lang="perl"><br />
{<br />
"data": {<br />
"34.4008.value": "0.25"<br />
},<br />
"status": {<br />
"code": 0<br />
},<br />
"event": {<br />
"type": 1,<br />
"data": "48.30000.0"<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
the classic way to extract the value 0.25 into a reading with the name Chlor with a regex would have been<br />
<syntaxhighlight lang="perl"><br />
attr test2 get01Regex 34.4008.value":[ \t]+"([\d\.]+)"<br />
</syntaxhighlight><br />
<br />
with JSON you can write <br />
<syntaxhighlight lang="perl"><br />
attr test2 get01JSON data_34.4008.value <br />
</syntaxhighlight><br />
which will create a reading with the Name "Chlor" (as shown above) and take the value 0.25 from the JSON string.<br />
<br />
or if you don't care about the naming of your readings, you can simply extract all JSON data with <br />
<syntaxhighlight lang="perl"><br />
attr test2 extractAllJSON<br />
</syntaxhighlight><br />
<br />
which would apply to all data read from this device and create the following readings out of the HTTP response shown above:<br />
<br />
{| class="wikitable"<br />
| data_34.4008.value || 0.25<br />
|-<br />
| event_data || 48.30000.0<br />
|-<br />
| event_type || 1<br />
|-<br />
| status_code || 0<br />
|}<br />
<br />
or you can specify<br />
<syntaxhighlight lang="perl"><br />
attr test2 get01ExtractAllJSON<br />
</syntaxhighlight><br />
which would only apply to all data read as response to the get command defined as get01. <br />
<br />
It might seem very simple at first sight to use extractAllJSON but if you prefer readings with a meaningful name you should instead define these readings with readingXXName and readingXXJSON or getXXName and getXXJSON individually. Of Course it would be possible to create additional user readings outside HTTPMOD but doing calculations, naming and formatting inside HTTPMOD is more efficient.<br />
<br />
=== JSON Lists ===<br />
<br />
imagine the HTTP Response contains:<br />
<br />
<syntaxhighlight lang="perl"><br />
{ "power":"0",<br />
"modes":["Off","SimpleColor","RainbowChase"],<br />
"code1":3,<br />
"code2":4<br />
}<br />
</syntaxhighlight><br />
<br />
then a configuration like <br />
<br />
<syntaxhighlight lang="perl"><br />
attr device reading01JSON modes <br />
attr device reading01Name Mode <br />
</syntaxhighlight><br />
<br />
will create a list of Subreadings just like a regex with multiple matches can create multiple subreadings:<br />
<br />
{| class="wikitable"<br />
| Mode-1 || Off<br />
|-<br />
| Mode-2 || SimpleColor<br />
|-<br />
| Mode-3 || RainbowChase <br />
|}<br />
<br />
if you don't want several subreadings but one reading that contains the list of modes, you can specify a recombine expression:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr device reading01Name Modes <br />
attr device reading01RecombineExpr join ",", @matchlist <br />
</syntaxhighlight><br />
<br />
which will create one reading containing a list:<br />
<br />
{| class="wikitable"<br />
| Modes || Off,SimpleColor,RainbowChase<br />
|}<br />
<br />
JSON parsing specifications also don't Need to match exactly. If there is no exact match for a defined reading, the HTTPMOD will try to Interpret the specification as a regex and look for json object paths that match the specification as a regex. For example:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr device reading01Name CodeElem<br />
attr device reading01JSON code<br />
</syntaxhighlight><br />
<br />
which will create a list of readings:<br />
<br />
{| class="wikitable"<br />
| CodeElem-1|| 3<br />
|-<br />
| CodeElem-2 || 4<br />
|}<br />
<br />
and of course they could also be recombined into one reading with a RecombineExpr Attribute.<br />
<br />
== Parsing http / XML using xpath ==<br />
Another alternative to regex parsing is the use of XPath to extract values from HTTP responses.<br />
The following example shows how XML data can be parsed with XPath-Strict or HTML Data can be parsed with XPath.<br />
Both work similar and the example uses XML Data parsed with the XPath-Strict option:<br />
<br />
If The XML data in the HTTP response looks like this:<br />
<br />
<syntaxhighlight lang="xml"><br />
<root xmlns:foo="http://www.foo.org/" xmlns:bar="http://www.bar.org"><br />
<actors><br />
<actor id="1">Peter X</actor><br />
<actor id="2">Charles Y</actor><br />
<actor id="3">John Doe</actor><br />
</actor><br />
</root><br />
</syntaxhighlight><br />
<br />
with XPath you can write <br />
<syntaxhighlight lang="perl"><br />
attr htest reading01Name Actor<br />
attr htest reading01XPath-Strict //actor[2]/text()<br />
</syntaxhighlight><br />
<br />
This will create a reading with the Name "Actor" and the value "Charles Y".<br />
<br />
Since XPath specifications can define several values / matches, HTTPMOD can also interpret these and store them in multiple readings:<br />
<syntaxhighlight lang="perl"><br />
attr htest reading01Name Actor<br />
attr htest reading01XPath-Strict //actor/text()<br />
</syntaxhighlight><br />
<br />
will create the readings <br />
<br />
{| class="wikitable"<br />
| Actor-1 || Peter X<br />
|-<br />
| Actor-2 || Charles Y<br />
|-<br />
| Actor-3 || John Doe<br />
|}<br />
<br />
== Further replacements of URL, header or post data ==<br />
sometimes it might be helpful to dynamically change parts of a URL, HTTP header or post data depending on existing readings, internals or <br />
perl expressions at runtime. This might be needed to pass further variables to a server, a current date or other things. <br />
<br />
To support this HTTPMOD offers generic replacements that are applied to a request before it is sent to the server. A replacement can be defined with the attributes <br />
<br />
* <code>replacement[0-9]*Regex</code><br />
* <code>replacement[0-9]*Mode</code><br />
* <code>replacement[0-9]*Value</code><br />
* <code>[gs]et[0-9]*Replacement[0-9]*Value</code><br />
<br />
a replacement always replaces a match of a regular expression. <br />
<br />
'''replacement[0-9]*Mode:'''<br />
The way the replacement value is defined can be specified with the replacement mode.<br />
* If the <code>replacement[0-9]*Mode</code> is <code>reading</code>, then the corresponding <code>replacement[0-9]*Value</code> is interpreted as the name of a ''reading'' of the same device or as ''device:reading'' to refer to another device.<br />
* If the <code>replacement[0-9]*Mode</code> is <code>internal</code>, then the corresponding <code>replacement[0-9]*Value</code> is interpreted as the name of an ''internal'' of the same device or as ''device:internal'' to refer to another device.<br />
* If the <code>replacement[0-9]*Mode</code> is <code>text</code>, then the corresponding <code>replacement[0-9]*Value</code> is interpreted as a static text<br />
* If the <code>replacement[0-9]*Mode</code> is <code>expression</code>, then the corresponding <code>replacement[0-9]*Value</code> is evaluated as a perl expression to compute the replacement. Inside such a replacement expression it is possible to refer to capture groups of the replacement regex.<br />
* If the <code>replacement[0-9]*Mode</code> is <code>key</code>, then the module will use a value from a key / value pair that is stored in an obfuscated form in the file system with the set storeKeyValue command. This might be useful for storing passwords.<br />
<br />
<br />
Example:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr mydevice getData {"get" :["%%value%%.value"]}<br />
attr mydevice replacement01Mode text<br />
attr mydevice replacement01Regex %%value%%<br />
<br />
attr mydevice get01Name Chlor<br />
attr mydevice get01Replacement01Value 34.4008<br />
<br />
attr mydevice get02Name Something<br />
attr mydevice get02Replacement01Value 31.4024<br />
<br />
attr mydevice get05Name profile<br />
attr mydevice get05URL http://www.mydevice.local/getprofile?password=%%password%%<br />
attr mydevice replacement02Mode key<br />
attr mydevice replacement02Regex %%password%%<br />
attr mydevice get05Replacement02Value password<br />
</syntaxhighlight> <br />
<br />
defines that <code>%%value%%</code> will be replaced by a static text.<br />
<br />
All Get commands will be HTTP post requests of a similar form. Only the <code>%%value%%</code> will be different from get to get.<br />
The first get will set the reading named Chlor and for the request it will take the generic getData and replace %%value%% with 34.4008.<br />
<br />
A second get will look the same except a different name and replacement value.<br />
<br />
With the command <code>set storeKeyValue password geheim</code> you can store the password geheim in an obfuscated form in the file system. <br />
To use this password and send it in a request you can use the above replacement with mode key. The value password will then refer to the ofuscated string stored with the key password.<br />
<br />
The mode <code>expression</code> allows you to define your own replacement syntax:<br />
<syntaxhighlight lang="perl"> <br />
attr mydevice replacement01Mode expression<br />
attr mydevice replacement01Regex {{([^}]+)}}<br />
attr mydevice replacement01Value ReadingsVal("mydevice", $1, "")<br />
attr mydevice getData {"get" :["{{temp}}.value"]}<br />
</syntaxhighlight> <br />
<br />
In this example any <code><nowiki>{{name}}</nowiki></code> in a URL, header or post data will be passed on to the perl function ReadingsVal <br />
which uses the string between <code><nowiki>{{}}</nowiki></code> as second parameter. This way one defined replacement can be used for many different<br />
readings.<br />
<br />
HTTPMOD has two built in replacements: One for session Ids and another one for the input value in a set command.<br />
The placeholder $sid is always replaced with the internal <code>$hash->{sid}</code> which contains the session id after it is extracted from a previous HTTP response. <br />
If you don't like to use the placeholder $sid then you can define your own replacement for example like:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr mydevice replacement01Mode internal<br />
attr mydevice replacement01Regex %session%<br />
attr mydevice replacement01Value sid<br />
</syntaxhighlight> <br />
<br />
Now the internal <code>$hash->{sid}</code> will be used as a replacement for the placeholder %session%.<br />
<br />
In the same way a value that is passed to a set-command can be put into a request with a user defined replacement. <br />
In this case the internal <code>$hash->{value}</code> will contain the value passed to the set command. <br />
<code>$hash->{value}</code> might even be a string containing several values that could be put into several different positions in a request by using user defined replacements.<br />
<br />
'''Other example : steering a pellet stove from Rika'''<br />
<br />
The stove API of Rika on https://www.rika-firenet.com/web/ delivers a JSON string with all settings and values, and can be piloted with a data string containing all the "set" values at once.<br />
<br />
Delivered JSON on get https://www.rika-firenet.com/api/client/xxxxxxxx/status : (xxxxxxxx must be replaced with the unique stove ID)<br />
<syntaxhighlight lang="perl"><br />
{<br />
"name": "Vorzimmer",<br />
"stoveID": "xxxxxxxxx",<br />
"lastSeenMinutes": 1,<br />
"lastConfirmedRevision": 1504385700,<br />
"controls": {<br />
"revision": 1504385700,<br />
"onOff": true,<br />
"operatingMode": 2,<br />
"heatingPower": 65,<br />
"targetTemperature": 24,<br />
"heatingTimesActive": false,<br />
"heatingTimesActiveForComfort": true,<br />
"setBackTemperature": 18,<br />
"convectionFan1Active": false,<br />
"convectionFan1Level": 0,<br />
"convectionFan1Area": 0,<br />
"convectionFan2Active": false,<br />
"convectionFan2Level": 0,<br />
"convectionFan2Area": 0,<br />
"frostProtectionActive": false,<br />
"frostProtectionTemperature": 5<br />
},<br />
"sensors": {<br />
"statusError": 0,<br />
"statusWarning": 0,<br />
"statusService": 0,<br />
"statusMainState": 1,<br />
"statusSubState": 3,<br />
"statusFrostStarted": false,<br />
"inputFlameTemperature": 21,<br />
"inputRoomTemperature": 21,<br />
"inputExternalRequest": true,<br />
"outputDischargeMotor": 0,<br />
"outputInsertionMotor": 0,<br />
"outputIDFan": 0,<br />
"outputAirFlaps": 0,<br />
"outputIgnition": false,<br />
"parameterStoveTypeNumber": 13,<br />
"parameterVersionMainBoard": 223,<br />
"parameterVersionTFT": 223,<br />
"parameterRuntimePellets": 11,<br />
"parameterRuntimeLogs": 0,<br />
"parameterFeedRateTotal": 17,<br />
"parameterFeedRateService": 683,<br />
"parameterOnOffCycles": 2<br />
},<br />
"stoveType": "DOMO MultiAir",<br />
"stoveFeatures": {<br />
"multiAir1": true,<br />
"multiAir2": true,<br />
"insertionMotor": false,<br />
"airFlaps": false,<br />
"logRuntime": false<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
Data string to send to https://www.rika-firenet.com/api/client/xxxxxxxx/controls in order to set values:<br />
<syntaxhighlight lang="perl"><br />
heatingTimesActiveForComfort=true&frostProtectionTemperature=3&setBackTemperature=18&targetTemperature=24&convectionFan2Level=0&convectionFan2Active=false&convectionFan1Level=0&onOff=true&convectionFan1Active=false&convectionFan2Area=0&revision=1505550101&heatingTimesActive=false&convectionFan1Area=0&frostProtectionActive=false&operatingMode=2&heatingPower=65<br />
</syntaxhighlight><br />
<br />
Code in 99_myUtils.pm:<br />
<syntaxhighlight lang="perl"><br />
use JSON;<br />
...<br />
sub<br />
replaceJSON ($$) {<br />
my ($valToReplace, $value) = @_;<br />
<br />
#$value in the parameters is a default value<br />
#It has to be replaced through the real value nnn passed in the set command "set <device> valToset nnn"<br />
$value = InternalVal("Ofen", "value", $value);<br />
Log3 ("Ofen", 3, "replaceJSON Internalvalue: $value");<br />
<br />
#Force an update to avoid outdated revision number<br />
fhem ("get Ofen revision");<br />
<br />
#Get all the controls as json<br />
my $json = ReadingsVal("Ofen", "controlsJSON","");<br />
Log3 ("Ofen", 3, "replaceJSON configsJSON: $json");<br />
<br />
# When starting FHEM or rereading config, the reading controlsJSON is empty<br />
return if ($json eq ""); <br />
<br />
my $decoded = decode_json($json);<br />
my $result;<br />
for my $key ( keys %$decoded ) {<br />
$result .= "$key=";<br />
if ($key eq $valToReplace) {<br />
$result .= $value."&";<br />
} else {<br />
$result .= $decoded->{$key}."&";<br />
}<br />
}<br />
chop($result); #remove last &<br />
Log3("Ofen", 3, "replaceJSON Result: $result");<br />
return $result;<br />
}<br />
</syntaxhighlight><br />
<br />
Define stove in fhem:<br />
<syntaxhighlight lang="perl"><br />
defmod Ofen HTTPMOD https://www.rika-firenet.com/api/client/xxxxxxxx/status 60<br />
<br />
attr Ofen enableCookies 1<br />
attr Ofen reAuthRegex id="login"|Unauthorized<br />
attr Ofen sid01Data email=xx@xx&password=xx<br />
attr Ofen sid01URL https://www.rika-firenet.com/web/login<br />
<br />
attr Ofen reading01JSON sensors_inputRoomTemperature<br />
attr Ofen reading01Name RaumTemp<br />
attr Ofen reading02JSON controls_setBackTemperature<br />
attr Ofen reading02Name Absenkung<br />
attr Ofen reading03JSON controls_frostProtectionTemperature<br />
attr Ofen reading03Name Frostschutz<br />
attr Ofen reading10Name controlsJSON<br />
attr Ofen reading10Regex (?s)controls.*?({.*?})<br />
<br />
attr Ofen get09Name revision<br />
attr Ofen get09URL https://www.rika-firenet.com/api/client/xxxxxxxx/status<br />
<br />
attr Ofen setURL https://www.rika-firenet.com/api/client/xxxxxxxx/controls<br />
attr Ofen setData {{data}}<br />
attr Ofen replacement01Mode expression<br />
attr Ofen replacement01Regex {{data}}<br />
<br />
attr Ofen set11Name frostProtectionTemperature<br />
attr Ofen set11Replacement01Value replaceJSON("frostProtectionTemperature", 2)<br />
<br />
attr Ofen set12Name targetTemperature<br />
attr Ofen set12Replacement01Value replaceJSON("targetTemperature", 24)<br />
</syntaxhighlight><br />
<br />
A detailed explanation (in german) of the login process can be found here: [https://forum.fhem.de/index.php/topic,76220.msg682514.html#msg682514]<br />
and the explanation of the other parameters here: [https://forum.fhem.de/index.php/topic,76220.msg685710.html#msg685710]<br />
<br />
== replacing reading values when they have not been updated / the device did not respond ==<br />
If a device does not respond then the values stored in readings will keep the same and only their timestamp shows that they are outdated. <br />
If you want to modify reading values that have not been updated for a number of seconds, you can use the attributes<br />
<br />
* <code>(reading|get)[0-9]*(-[0-9]+)?MaxAge</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?MaxAgeReplacementMode</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?MaxAgeReplacement</code><br />
<br />
Every time the module tries to read from a device, it will also check if readings have not been updated <br />
for longer than the <code>MaxAge</code> attributes allow. If readings are outdated, the <code>MaxAgeReplacementMode</code> defines how the affected<br />
reading values should be replaced. <code>MaxAgeReplacementMode</code> can be <code>text</code>, <code>reading</code>, <code>internal</code>, <code>expression</code> or <code>delete</code>.<br />
<br />
<code>MaxAge</code> specifies the number of seconds that a reading should remain untouched before it is replaced. <br />
<br />
<code>MaxAgeReplacement</code> contains either a static text that is used as replacement value or a Perl expression that is evaluated to <br />
give the replacement value. This can be used for example to replace a temperature that has not bee updated for more than 5 minutes <br />
with the string "outdated - was 12": <br />
<syntaxhighlight lang="perl"><br />
attr PM readingMaxAge 300<br />
attr PM readingMaxAgeReplacement "outdated - was " . $val<br />
attr PM readingMaxAgeReplacementMode expression<br />
</syntaxhighlight><br />
The variable <code>$val</code> contains the value of the reading before it became outdated.<br />
<br />
Or to show that a device was offline:<br />
<syntaxhighlight lang="perl"><br />
attr MyLight reading01Name color<br />
attr MyLight reading01JSON result_02_color<br />
attr MyLight reading01MaxAge 300<br />
attr MyLight reading01MaxAgeReplacement "offline"<br />
attr MyLight reading01MaxAgeReplacementMode text<br />
</syntaxhighlight><br />
<br />
<br />
== Note on determining how to send requests to a special device ==<br />
If you don't know which URLs, headers or POST data your web GUI uses, you might try a local proxy like BurpSuite [http://portswigger.net/burp/ BurpSuite] to track requests and responses. This is a tedious task but probably the best way to achieve a successful result. <br />
<br />
Let us consider an example. The Telekom Speedport W724V has a login-site that is famous for being cumbersome. Burp allows to monitor each step in the login procedure. In the case of a speedport the following steps occur:<br />
<br />
First burp shows that a get command is issued<br />
################################################################################################## <br />
GET / HTTP/1.1<br />
Host: speedport.ip<br />
Cache-Control: max-age=0<br />
Upgrade-Insecure-Requests: 1<br />
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36<br />
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8<br />
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4<br />
Cookie: lang=de<br />
Connection: close <br />
In order to mimic the behavior of a real person calling the website HTTPMOD should copy all necessary steps. Host, Cookie and the GET-command are usually necessary. The same cannot be said of the User-Agent because the website can be called from any mobile or desktop computer. <br />
<br />
Then, the speedport will answer with a command that consists of several lines. By going through every line for every step in the login procedure one will finally arrive at the information that is necessary to successfully enter the login of the speedport (in case of the W724V, for example, it is necessary to copy a token called _httoken and to include the referer).<br />
<br />
== Advanced configuration to define a <code>set</code> command and send data to a device ==<br />
<br />
When a set option is defined by attributes, the module will use the value given to the set command and integrate it into an HTTP-Request that sends the value to the device. The definitions for URL, headers and post data can contain the placeholder $val which will be replaced by the value given to the set command.<br />
<br />
This can be as simple as:<br />
<syntaxhighlight lang="perl"><br />
# No cyclic requests and no main URL needed in this example<br />
define MyDevice HTTPMOD none 0<br />
<br />
attr MyDevice set01Name Licht<br />
attr MyDevice set01URL http://192.168.1.22/switch=$val<br />
</syntaxhighlight><br />
<br />
A user command <br />
<syntaxhighlight lang="perl"><br />
set MyDevice Licht 1<br />
</syntaxhighlight><br />
<br />
will be translated into the http GET request<br />
<syntaxhighlight lang="perl"><br />
http://192.168.1.22/switch=1<br />
</syntaxhighlight><br />
<br />
In this example a map would also be helpful, that translates on / off to 0 or 1 and allows the user to select on/of in fhemweb:<br />
<syntaxhighlight lang="perl"><br />
attr MyDevive set01IMap 0:off, 1:on<br />
</syntaxhighlight><br />
This also provides input validation to make sure that only on and off can be used with the set command.<br />
<br />
In more complex Scenarios you might need to login before sending a command and the Login might create a session id that has to be part of further requests either in the URL, in headers or in the post data.<br />
<br />
Extension to the above example for a PoolManager 5 where a set needs a session id in the URL and the values have to be passed in JSON strings as post data:<br />
<syntaxhighlight lang="perl"><br />
attr PM set01Name HeizungSoll<br />
attr PM set01URL http://MyPoolManager/cgi-bin/webgui.fcgi?sid=$sid<br />
attr PM set01Hint 6,10,20,30<br />
attr PM set01Min 6<br />
attr PM set01Max 30<br />
attr PM setHeader1 Content-Type: application/json<br />
attr PM set01Data {"set" :{"34.3118.value" :"$val" }}<br />
</syntaxhighlight><br />
<br />
This example defines a set option with the name HeizungSoll.<br />
By issuing <code>set PM HeizungSoll 10</code> in FHEM, the value 10 will be sent in the defined HTTP<br />
Post to URL <code>http://MyPoolManager/cgi-bin/webgui.fcgi</code> in the Post Data as<br />
<br />
<syntaxhighlight lang="html4strict"><br />
{"set" :{"34.3118.value" :"10" }}<br />
</syntaxhighlight><br />
<br />
The optional attributes set01Min and set01Max define input validations that will be checked in the set function. <br />
The optional attribute set01Hint will define a selection list for the FHEMweb GUI.<br />
<br />
The HTTP response to such a request will be ignored unless you specify the attribute <code>setParseResponse</code> <br />
for all set commands or <code>set01ParseResponse</code> for the set command with number 01.<br />
If the HTTP response to a set command is parsed then this is done like the parsing of responses to get commands and you can use the attributes ending e.g. on Format, Encode, Decode, OMap and OExpr to manipulate / format the values read.<br />
<br />
If a parameter to a set command is not numeric but should be passed on to the device as text, then you can specify the attribute setTextArg. For example: <br />
<syntaxhighlight lang="perl"><br />
attr PM set01TextArg<br />
</syntaxhighlight><br />
<br />
If a set command should not require a parameter at all, then you can specify the attribute NoArg. For example: <br />
<syntaxhighlight lang="perl"><br />
attr PM set03Name On<br />
attr PM set03NoArg<br />
</syntaxhighlight><br />
<br />
== Advanced configuration to create a valid session id that might be necessary ==<br />
In simple cases logging in works with basic authentication. In the case HTTPMOD accepts a username and password as part of the URL in the form <br />
<syntaxhighlight lang="perl"><br />
http://User:Password@192.168.1.18/something<br />
</syntaxhighlight><br />
<br />
However basic auth is seldom used. If you need to fill in a username and password in a HTML form and the session is then managed by a session id, here is how to configure this:<br />
<br />
when sending data to an HTTP-Device in a set, HTTPMOD will replace any <code>$sid</code> in the URL, Headers and Post data with the internal <code>$hash->{sid}</code>. To authenticate towards the device and give this internal a value, you can use an optional multi step login procedure defined by the following attributes: <br />
<br />
* <code>sid[0-9]*URL</code><br />
* <code>sid[0-9]*Data.*</code><br />
* <code>sid[0-9]*Header.*</code><br />
* <code>sid[0-9]*IgnoreRedirects</code><br />
* <code>idRegex</code><br />
* <code>idJSON</code><br />
* <code>idXPath</code><br />
* <code>idXPath-Strict</code><br />
* <code>(get|set|sid)[0-9]*IdRegex</code><br />
* <code>(get|set|sid)[0-9]*IdJSON</code><br />
* <code>(get|set|sid)[0-9]*IdXPath</code><br />
* <code>(get|set|sid)[0-9]*IdXPath-Strict</code><br />
<br />
Each step can have a URL, Headers, Post Data pieces and a Regex to extract a resulting Session ID into <code>$hash->{sid}</code>.<br />
HTTPMOD will create a sorted list of steps (the numbers between sid and URL / Data / Header) and the loop through these steps and send the corresponding requests to the device. For each step a $sid in a Header or Post Data will be replaced with the current content of <code>$hash->{sid}</code>.<br />
<br />
Using this feature, HTTPMOD can perform a forms based authentication and send user name, password or other necessary data to the device and save the session id for further requests.<br />
<br />
To determine when this login procedure is necessary, HTTPMOD will first try to send a request without <br />
doing the login procedure. If the result contains an error that authentication is necessary, then a login is performed. <br />
To detect such an error in the HTTP response, you can again use a regular expression, JSON or XPath, this time with the attributes <br />
<br />
* <code>reAuthRegex</code><br />
* <code>reAuthJSON</code><br />
* <code>reAuthXPath</code><br />
* <code>reAuthXPath-Strict</code><br />
* <code>(get|set)[0-9]*ReAuthRegex</code><br />
* <code>(get|set)[0-9]*ReAuthJSON</code><br />
* <code>(get|set)[0-9]*ReAuthXPath</code><br />
* <code>(get|set)[0-9]*ReAuthXPath-Strict</code><br />
<br />
reAuthJSON or reAuthXPath typically only extract one piece of data from a response. <br />
If the existence of the specified piece of data is sufficent to start a login procedure, then nothing more needs to be defined to detect this situation. <br />
If however the indicator is a status code that contains different values depending on a successful request and a failed request if a new authentication is needed, <br />
then you can combine things like reAuthJSON with reAuthRegex. In this case the regex is only matched to the data extracted by JSON (or XPath). <br />
This way you can easily extract the status code using JSON parsing and then specify the code that means "authentication needed" as a regular expression.<br />
<br />
If for one step not all of the URL, Data or Header Attributes are set, then HTTPMOD tries to use a <br />
<code>sidURL</code>, <code>sidData.*</code> or <code>sidHeader.*</code> Attribute (without the step number after sid). This way parts that are the same for all steps don't need to be defined redundantly.<br />
<br />
=== Example for a multi step login procedure: ===<br />
<syntaxhighlight lang="perl"><br />
attr PM reAuthRegex /html/dummy_login.htm <br />
attr PM sidURL http://192.168.70.90/cgi-bin/webgui.fcgi?sid=$sid<br />
attr PM sidHeader1 Content-Type: application/json<br />
attr PM sid1IDRegex wui.init\('([^']+)'<br />
attr PM sid2Data {"set" :{"9.17401.user" :"fhem" ,"9.17401.pass" :"password" }}<br />
attr PM sid3Data {"set" :{"35.5062.value" :"128" }}<br />
attr PM sid4Data {"set" :{"42.8026.code" :"pincode" }}<br />
</syntaxhighlight><br />
<br />
In this case HTTPMOD detects that a login is necessary by looking for the pattern /html/dummy_login.htm in the HTTP response. <br />
If it matches, it starts a login sequence. In the above example all steps request the same URL. In step 1 only the defined Header is sent in an HTTP get request. The response will contain a session id that is extraced with the regex wui.init\('([^']+)'.<br />
<br />
In the next step this session id is sent in a post request to the same URL where tha post data contains a username and password. The a third and a fourth request follow that set a value and a code. The result will be a valid and authorized session id that can be used in other requests where $sid is part of a URL, header or post data and will be replaced with the session id extracted above.<br />
<br />
In the special case where a session id is set as a HTTP-Cookie (with the header Set-cookie: in the HTTP response) HTTPMOD offers an even simpler way. With the attribute enableCookies a very basic cookie handling mechanism is activated that stores all cookies that the server sends to the HTTPMOD device and puts them back as cookie headers in the following requests.<br />
<br />
For such cases no sidIdRegex and no $sid in a user defined header is necessary.<br />
<br />
== Advanced configuration to define a <code>get</code> and request additional data with its own request from a device ==<br />
<br />
The normal automatic HTTP request that is done repeatedly after the defined interval has elapsed works well in cases where all required readings can be requested in one common HTTP request. If however a device needs individual requests with different URLs or different POST data for each value, then another method is necessary. <br />
For such cases a <code>get</code> option can be defined and the user can either issue FHEM <code>get</code> commands each time he needs the reading or the user can set an attribute to request the reading automatically together with the normal iteration.<br />
For each <code>get</code> option attributes define an individual URL, optional headers, and post data as well as individual regular expressions and formatting options. <br />
<br />
When a get option is defined by attributes, the module allows querying additional values from the device that require individual HTTP-Requests or special parameters to be sent<br />
<br />
Extension to the above example:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr PM get01Name MyGetValue <br><br />
attr PM get01URL http://MyPoolManager/cgi-bin/directory/webgui.fcgi?special=1?sid=$sid <br><br />
attr PM getHeader1 Content-Type: application/json <br><br />
attr PM get01Data {"get" :{"30.1234.value"}} <br><br />
</syntaxhighlight><br />
<br />
This example defines a get option with the name MyGetValue.<br />
By issuing <code>get PM MyGetValue</code> in FHEM, the defined HTTP request is sent to the device.<br />
The HTTP response is then parsed using the same readingXXName and readingXXRegex attributes as above so<br />
additional pairs will probably be needed there for additional values.<br />
<br />
if you prefer to define the parsing and formatting of readings individually per get command, you can use <br />
attributes like get01Regex, get01XPath, get01Format, get01OMap and so on just like for reading01...<br />
<br />
You can also include parameters / values that are passed to the get command in the request just like for set commands.<br />
The placeholder $val will be replaced with the value given to the get command or you can specify your own replacement as described above.<br />
<br />
If the new get parameter should also be queried regularly, you can define the following optional attributes:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr PM get01Poll 1<br />
attr PM get01PollDelay 300<br />
</syntaxhighlight><br />
<br />
The first attribute includes this reading in the automatic update cycle and the second defines an alternative lower update frequency. When the interval defined initially in the define is over and the normal readings are read from the device, the update function will check for additional get parameters that should be included in the update cycle.<br />
<br />
If a PollDelay is specified for a get parameter, the update function also checks if the time passed since it has last read this value is more than the given PollDelay. If not, this reading is skipped and it will be rechecked in the next cycle when interval is over again. So the effective PollDelay will always be a multiple of the interval specified in the initial define.<br />
<br />
Please note that each defined get command that is included in the regular update cycle will create its own HTTP request. So if you want to extract several values from the same request, it is much more efficient to do this by defining readingXXName and readingXXRegex, XPath or JSON attributes and to specify an interval and a URL in the define of the HTTPMOD device. <br />
<br />
Example for a Siemens webserver provided by Lanhydrock:<br />
<syntaxhighlight lang="perl"><br />
define ozw672 HTTPMOD https://192.168.178.8/api/auth/login.json?user=test&pwd=test 300<br />
<br />
attr ozw672 get1Name tempAussen<br />
attr ozw672 get1URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1960<br />
attr ozw672 get1Poll 1<br />
attr ozw672 get1PollDelay 1800<br />
<br />
attr ozw672 get2Name tempAussenGemischt<br />
attr ozw672 get2URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1964<br />
attr ozw672 get2Poll 1<br />
attr ozw672 get2PollDelay 1800<br />
<br />
attr ozw672 get3Name tempTWW<br />
attr ozw672 get3URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1996<br />
attr ozw672 get3Poll 1<br />
<br />
attr ozw672 get4Name tempKesselSoll<br />
attr ozw672 get4URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1910<br />
attr ozw672 get4Poll 1<br />
<br />
attr ozw672 get5Name tempKesselRuecklauf<br />
attr ozw672 get5URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1915<br />
attr ozw672 get5Poll 1<br />
<br />
attr ozw672 get6Name tempKesselRuecklaufSoll<br />
attr ozw672 get6URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1916<br />
attr ozw672 get6Poll 1<br />
<br />
attr ozw672 get7Name anzahlStartsBrenner<br />
attr ozw672 get7URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1927<br />
attr ozw672 get7PollDelay 1800<br />
attr ozw672 get7Poll 1<br />
<br />
attr ozw672 get8Name statusKessel<br />
attr ozw672 get8URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1898<br />
attr ozw672 get8Poll 1<br />
attr ozw672 get8Regex Value": "([a-zA-Zü ]*)"<br />
attr ozw672 get8OMap Aus:0, Nachlauf aktiv:5, Freigegeben für TWW:10, Freigegeben für HK:20, In Teillastbetrieb für TWW:40, In Teillastbetrieb für HK:50, In Betrieb für Trinkwasser:90, In Betrieb für Heizkreis:100<br />
<br />
attr ozw672 getRegex Value": "[ ]*([-.0-9]*)"<br />
<br />
attr ozw672 reAuthRegex .*session not valid.*<br />
attr ozw672 sid1IDRegex .*"(.*-.*-.*-[0-9a-z]*).*<br />
attr ozw672 sid1URL https://192.168.178.8/api/auth/login.json?user=test&pwd=test<br />
</syntaxhighlight><br />
<br />
== All attributes ==<br />
;reading[0-9]+Name<br />
:the name of a reading to extract with the corresponding readingRegex, readingJSON, readingXPath or readingXPath-Strict<br />
:Please note that the old syntax <b>readingsName.*</b> does not work with all features of HTTPMOD and should be avoided. It might go away in a future version of HTTPMOD.<br />
<br />
;(get|set)[0-9]+Name<br />
:Name of a get or set command<br />
:If the HTTP response that is received after the command is parsed with an individual parse option then this name is also used as a reading name. Please note that no individual parsing needs to be defined for a get or set. If no regex, XPath or JSON is specified for the command, then HTTPMOD will try to parse the response using all the defined readingRegex, reading XPath or readingJSON attributes.<br />
<br />
;(get|set|reading)[0-9]+Regex<br />
:If this attribute is specified, the Regex defined here is used to extract the value from the HTTP Response and assign it to a Reading with the name defined in the (get|set|reading)[0-9]+Name attribute.<br />
:If this attribute is not specified for an individual Reading or get or set but without the numbers in the middle, e.g. as getRegex or readingRegex, then it applies to all the other readings / get / set commands where no specific Regex is defined.<br><br />
:The value to extract should be in a capture group / sub expression e.g. ([\d\.]+) in the above example. Multiple capture groups will create multiple readings (see explanation above)<br />
:Using this attribute for a set command (setXXRegex) only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
:Please note that the old syntax <code>readingsRegex.*</code> does not work with all features of HTTPMOD and should be avoided. It might go away in a future version of HTTPMOD.<br />
:If for get or set commands neither a generic Regex attribute without numbers nor a specific (get|set)[0-9]+Regex attribute is specified and also no XPath or JSON parsing specification is given for the get or set command, then HTTPMOD tries to use the parsing definitions for general readings defined in reading[0-9]+Name, reading[0-9]+Regex or XPath or JSON attributes and assigns the Readings that match here.<br />
<br />
;(get|set|reading)[0-9]+RegOpt<br />
:Lets the user specify regular expression modifiers. For example if the same regular expression should be matched as often as possible in the HTTP response, then you can specify RegOpt g which will case the matching to be done as /regex/g<br />
:The results will be trated the same way as multiple capture groups so the reading name will be extended with -number. <br />
:For other possible regular expression modifiers see http://perldoc.perl.org/perlre.html#Modifiers<br />
<br />
;(get|set|reading)[0-9]+XPath<br />
:defines an xpath to one or more values when parsing HTML data (see examples above)<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;get|set|reading[0-9]+XPath-Strict<br />
:defines an xpath to one or more values when parsing XML data (see examples above)<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;(get|set|reading)[0-9]+AutoNumLen<br />
:In cases where a regular expression or an XPath results in multiple results and these results are stored in a common reading name with extension -number, then you can modify the format of this number to have a fixed length with leading zeros. AutoNumLen 3 for example will lead to reading names ending with -001 -002 and so on.<br />
<br />
;(get|set|reading)[0-9]+AlwaysNum<br />
:if set to 1 this attributes forces reading names to end with a -1, -01 (depending on the above described AutoNumLen) even if just one value is parsed.<br />
<br />
;get|set|reading[0-9]+JSON<br />
:defines a path to the JSON object wanted by concatenating the object names. See the above example.<br />
:If you don't know the paths, then start by using extractAllJSON and the use the names of the readings as values for the JSON attribute.<br><br />
:Please don't forget to also specify a name for a reading, get or set. <br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;(get|set|reading)[0-9]*RecombineExpr<br />
:defines an expression that is used in an eval to compute one reading value out of the list of matches.<br />
:This is supposed to be used for regexes or xpath specifications that produce multiple results if only one result that combines them is wanted. The list of matches will be in the variable @matchlist.<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;get[0-9]*CheckAllReadings<br />
:this attribute modifies the behavior of HTTPMOD when the HTTP Response of a get command is parsed. <br><br />
:If this attribute is set to 1, then additionally to the matching of the corresponding get specific regex (get[0-9]*Regex), XPath or JSON attribute also all the reading names and parse definitions defined in Reading[0-9]+Name and Reading[0-9]+Regex, XPath or JSON attributes are checked and if they match, the coresponding Readings are assigned as well.<br />
:Please note that this does not mean that get01CheckAllReadings will cause a get02Regex to be used. Only the corresponding get01Regex will be used but additionally all the readingXYRegex attributes.<br />
:This is automatically done if a get or set command is defined without its own parse attributes.<br />
<br />
;(get|reading)[0-9]*OExpr<br />
:defines an optional expression that is used in an eval to compute / format a readings value after parsing an HTTP response<br />
:The raw value from the parsing will be in the variable $val.<br />
:If specified as readingOExpr then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Expr.<br />
:Please note that the old syntax <b>readingsExpr.*</b> does not work with all features of HTTPMOD and should be avoided. It might go away in a future version of HTTPMOD.<br />
<br />
;(get|reading)[0-9]*Expr<br />
:This is the old syntax for (get|reading)[0-9]*OExpr. It should be replaced by (get|reading)[0-9]*OExpr. The set command upgradeAttributes which becomes visible when the attribute enableControlSet is set to 1, can do this renaming automatically.<br />
<br />
;(get|reading)[0-9]*OMap<br />
:Map that defines a mapping from raw value parsed to visible values like "0:mittig, 1:oberhalb, 2:unterhalb".<br />
:If specified as readingOMap then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Map.<br><br />
:The individual options in a map are separated by a komma and an optional space. Spaces are allowed to appear in a visible value however kommas are not possible.<br />
<br />
;(get|reading)[0-9]*Map<br />
:This is the old syntax for (get|reading)[0-9]*OMap. It should be replaced by (get|reading)[0-9]*OMap. The set command upgradeAttributes which becomes visible when the attribute enableControlSet is set to 1, can do this renaming automatically.<br />
<br />
;(get|set|reading)[0-9]*Format<br />
:Defines a format string that will be used in sprintf to format a reading value.<br />
:If specified without the numbers in the middle e.g. as readingFormat then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Format.<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br><br />
<br />
;(get|set|reading)[0-9]*Decode<br />
:defines an encoding to be used in a call to the perl function decode to convert the raw data string read from the device to a reading. <br />
:This can be used if the device delivers strings in an encoding like cp850 instead of utf8.<br />
:If your reading values contain Umlauts and they are shown as strange looking icons then you probably need to use this feature.<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;(get|set|reading)[0-9]*Encode<br />
:defines an encoding to be used in a call to the perl function encode to convert the raw data string read from the device to a reading. <br />
:This can be used if the device delivers strings in an encoding like cp850 and after decoding it you want to reencode it to e.g. utf8.<br />
:If your reading values contain Umlauts and they are shown as strange looking icons then you probably need to use this feature.<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;(get|set)[0-9]*URL<br />
:URL to be requested for the set or get command. If this option is missing, the URL specified during define will be used.<br />
<br />
;(get|set)[0-9]*Data<br />
:Data to be sent to the device as POST data when the get or set command is executed. if this attribute is not specified, an HTTP GET method will be used instead of an HTTP POST<br />
<br />
;(get|set)[0-9]*NoData<br />
:can be used to override a more generic attribute that specifies POST data for all get or set commands. With NoData no data is sent and therefor the request will be an HTTP GET.<br />
<br />
;(get|set)[0-9]*Header.*<br />
:HTTP Headers to be sent to the device when the set is executed<br />
<br />
;requestHeader.*<br />
:Define an optional additional HTTP Header to set in the HTTP request of the main loop<br />
<br />
;requestData<br />
:optional POST Data to be sent in the request of the main loop. If not defined, it will be an HTTP GET request as defined in HttpUtils which is used by this module<br />
<br />
;get[0-9]+Poll<br />
:if set to 1 the get is executed automatically during the normal update cycle (after the interval provided in the define command has elapsed)<br />
<br />
;get[0-9]+PollDelay<br />
:if the value should not be read in each iteration (after the interval given to the define command), then a minimum delay can be specified with this attribute. This has only an effect if the above Poll attribute has also been set. Every time the update function is called, it checks if since this get has been read the last time, the defined delay has elapsed. If not, then it is skipped this time.<br />
:PollDelay can be specified as seconds or as x[0-9]+ which means a multiple of the interval in the define command.<br />
<br />
;(get|set)[0-9]*TextArg<br />
:For a get command this defines that the command accepts a text value after the option name. By default a get command doesn't accept optional values after the command name. <br />
:If TextArg is specified and a value is passed after the get name then this value can then be used in a request URL, header or data as replacement for $val or in a user defined replacement that uses the internal "value" ($hash->{value}).<br />
:If used for a set command then it defines that the value to be set doesn't require any validation / conversion. <br />
:The raw value is passed on as text to the device. By default a set command expects a numerical value or a text value that is converted to a numeric value using a map.<br />
<br />
;set[0-9]+Min<br />
:Minimum value for input validation. <br />
<br />
;set[0-9]+Max<br />
:Maximum value for input validation. <br />
<br />
;set[0-9]+IExpr<br />
:Perl Expression to compute the raw value to be sent to the device from the input value passed to the set.<br />
<br />
;set[0-9]+Expr<br />
:This is the old syntax for (get|reading)[0-9]*IExpr. It should be replaced by (get|reading)[0-9]*IExpr. The set command upgradeAttributes which becomes visible when the attribute enableControlSet is set to 1, can do this renaming automatically.<br />
<br />
;set[0-9]+IMap<br />
:Map that defines a mapping from raw to input values like "0:mittig, 1:oberhalb, 2:unterhalb". This attribute atomatically creates a hint for FHEMWEB so the user can choose one of the input values.<br />
<br />
;set[0-9]+Map<br />
:This is the old syntax for (get|reading)[0-9]*IMap. It should be replaced by (get|reading)[0-9]*IMap. The set command upgradeAttributes which becomes visible when the attribute enableControlSet is set to 1, can do this renaming automatically.<br />
<br />
;set[0-9]+Hint<br />
:Explicit hint for fhemWEB that will be returned when set ? is seen. Can be used to get a slider or a list of values to choose from.<br />
<br />
;set[0-9]*NoArg<br />
:Defines that this set option doesn't require arguments. It allows sets like "on" or "off" without further values.<br />
<br />
;set[0-9]*ParseResponse<br />
:defines that the HTTP response to the set will be parsed as if it was the response to a get command.<br />
<br />
<br />
;(get|set)[0-9]*URLExpr<br />
:Defines a Perl expression to specify the HTTP Headers for this request. This overwrites any other header specification and should be used carefully only if needed. The original Header is availabe as $old. Typically this feature is not needed and it might go away in future versions of HTTPMOD. Please use the "replacement" attributes if you want to pass additional variable data to a web service. <br />
<br />
;(get|set)[0-9]*DatExpr<br />
:Defines a Perl expression to specify the HTTP Post data for this request. This overwrites any other post data specification and should be used carefully only if needed. The original Data is availabe as $old. Typically this feature is not needed and it might go away in future versions of HTTPMOD. Please use the "replacement" attributes if you want to pass additional variable data to a web service. <br />
<br />
;(get|set)[0-9]*HdrExpr<br />
:Defines a Perl expression to specify the URL for this request. This overwrites any other URL specification and should be used carefully only if needed. The original URL is availabe as $old. Typically this feature is not needed and it might go away in future versions of HTTPMOD. Please use the "replacement" attributes if you want to pass additional variable data to a web service. <br />
<br />
;ReAuthRegex<br />
:regular Expression to match an error page indicating that a session has expired and a new authentication for read access needs to be done. <br />
:This attribute only makes sense if you need a forms based authentication for reading data and if you specify a multi step login procedure based on the sid.. attributes.<br />
:This attribute is used for all requests. For set and get operations you can however specify individual reAuthRegexes with the (get|set)[0-9]*ReAuthRegex attributes.<br />
<br />
;(get|set)[0-9]*ReAuthRegex<br />
:Regex that will detect when a session has expired during a set operation and a new login needs to be performed.<br />
:It works like the global reAuthRegex but is used for set operations.<br />
<br />
;sid[0-9]*URL<br />
:different URLs or one common URL to be used for each step of an optional login procedure. <br />
<br />
;sid[0-9]*IDRegex<br />
:different Regexes per login procedure step or one common Regex for all steps to extract the session ID from the HTTP response<br />
<br />
;sid[0-9]*Data.*<br />
:data part for each step to be sent as POST data to the corresponding URL<br />
<br />
;sid[0-9]*Header.*<br />
:HTTP Headers to be sent to the URL for the corresponding step<br />
<br />
;sid[0-9]*IgnoreRedirects<br />
:Tells the HttpUtils to not follow HTTP Redirects for this Request. Might be needed for some devices that set a session cookie within a 303 Redirect.<br />
<br />
;clearSIdBeforeAuth<br />
:will set the session id to "" before doing the authentication steps<br />
<br />
;authRetries<br />
:number of retries for authentication procedure - defaults to 1<br />
<br />
;replacement[0-9]*Regex<br />
:Defines a replacement to be applied to an HTTP request header, data or URL before it is sent. This allows any part of the request to be modified based on a reading, an internal or an expression.<br />
:The regex defines which part of a header, data or URL should be replaced. The replacement is defined with the following attributes:<br />
<br />
;replacement[0-9]*Mode<br />
:Defines how the replacement should be done and what replacementValue means. Valid options are text, reading, internal and expression.<br />
<br />
;replacement[0-9]*Value<br />
:Defines the replacement. If the corresponding replacementMode is <code>text</code>, then value is a static text that is used as the replacement.<br />
:If replacementMode is <code>reading</code> then Value can be the name of a reading of this device or it can be a reading of a different device referred to by devicename:reading.<br />
:If replacementMode is <code>internal</code> the Value can be the name of an internal of this device or it can be an internal of a different device referred to by devicename:internal.<br />
:If replacementMode is <code>expression</code> the the Value is treated as a Perl expression that computes the replacement value. The expression can use $1, $2 and so on to refer to capture groups of the corresponding regex that is matched against the original URL, header or post data.<br />
:If replacementMode is <code>key</code> then the module will use a value from a key / value pair that is stored in an obfuscated form in the file system with the set storeKeyValue command. This might be useful for storing passwords.<br />
<br />
;[gs]et[0-9]*Replacement[0-9]*Value<br />
:This attribute can be used to override the replacement value for a specific get or set.<br />
<br />
;get|reading[0-9]*MaxAge<br />
:Defines how long a reading is valid before it is automatically overwritten with a replacement when the read function is called the next time.<br />
<br />
;get|reading[0-9]*MaxAgeReplacement<br />
:specifies the replacement for MaxAge - either as a static text or as a perl expression.<br />
<br />
;get|reading[0-9]*MaxAgeReplacementMode<br />
:specifies how the replacement is interpreted: can be text, expression and delete.<br />
<br />
;get|reading[0-9]*DeleteIfUnmatched<br />
:If set to 1 this attribute causes certain readings to be deleted when the parsing of the website does not match the specified reading. Internally HTTPMOD remembers which kind of operation created a reading (update, Get01, Get02 and so on). Specified readings will only be deleted if the same operation does not parse this reading again. This is especially useful for parsing that creates several matches / readings and the number of matches can vary from request to request. For example if reading01Regex creates 4 readings in one update cycle and in the next cycle it only matches two times then the readings containing the remaining values from the last round will be deleted.<br />
:Please note that this mechanism will not work in all cases after a restart. Especially when a get definition does not contain its own parsing definition but ExtractAllJSON or relies on HTTPMOD to use all defined reading.* attributes to parse the responsee to a get command, old readings might not be deleted after a restart of fhem.<br />
;get|reading[0-9]*DeleteOnError<br />
:If set to 1 this attribute causes certain readings to be deleted when the website can not be reached and the HTTP request returns an error. Internally HTTPMOD remembers which kind of operation created a reading (update, Get01, Get02 and so on). Specified readings will only be deleted if the same operation returns an error.<br />
The same restrictions as for DeleteIfUnmatched apply regarding a fhem restart.<br />
<br />
<br />
;httpVersion<br />
:defines the HTTP-Version to be sent to the server. This defaults to 1.0.<br />
<br />
;sslVersion<br />
:defines the SSL Version for the negotiation with the server. The attribute is evaluated by HttpUtils. If it is not specified, HttpUtils assumes SSLv23:!SSLv3:!SSLv2<br />
<br />
;sslArgs<br />
:defines a list that is converted to a key / value hash and gets passed to HttpUtils. To avoid certificate validation for broken servers you can for example specify <br />
:<code>attr myDevice sslArgs SSL_verify_mode,SSL_VERIFY_NONE</code><br />
<br />
;alignTime<br />
:Aligns each periodic read request for the defined interval to this base time. This is typcally something like 00:00 (see the FHEM at command)<br />
<br />
;noShutdown<br />
:pass the noshutdown flag to HTTPUtils for webservers that need it (some embedded webservers only deliver empty pages otherwise)<br />
<br />
;disable<br />
:stop doing automatic HTTP requests while this attribute is set to 1<br />
<br />
;enableControlSet<br />
:enables the built in set commands interval, stop, start, reread, upgradeAttributes, storeKeyValue.<br />
<br />
;enableCookies<br />
:enables the built in cookie handling if set to 1. With cookie handling each HTTPMOD device will remember cookies that the server sets and send them back to the server in the following requests. <br />
:This simplifies session magamenet in cases where the server uses a session ID in a cookie. In such cases enabling cookies should be sufficient and no sidRegex and no manual definition of a cookie header should be necessary.<br />
<br />
;showMatched<br />
:if set to 1 then HTTPMOD will create a reading with the name MATCHED_READINGS that contains the names of all readings that could be matched in the last request as well as UNMATCHED_READINGS and LAST_REQUEST.<br />
<br />
;showError<br />
:if set to 1 then HTTPMOD will create a reading and event with the Name LAST_ERROR that contains the error message of the last error returned from HttpUtils. <br />
<br />
;removeBuf<br />
:if set to 1 then HTTPMOD removes the internal named buf when a HTTP-response has been received. <br />
:$hash->{buf} is used internally be Fhem httpUtils and in some use cases it is desireable to remove this internal after reception <br />
:because it contains a very long response which looks ugly in Fhemweb.<br />
<br />
;timeout<br />
:time in seconds to wait for an answer. Default value is 2<br />
<br />
;queueDelay<br />
:HTTP Requests will be sent from a queue in order to avoid blocking when several Requests have to be sent in sequence. This attribute defines the delay between calls to the function that handles the send queue. It defaults to one second.<br />
<br />
;queueMax<br />
:Defines the maximum size of the send queue. If it is reached then further HTTP Requests will be dropped and not be added to the queue<br />
<br />
;minSendDelay<br />
:Defines the minimum time between two HTTP Requests.<br />
<br />
== Links ==<br />
* Beispiel: [[Wetter_und_Wettervorhersagen#Wetter_von_Weather_Underground|Wetter von WeatherUnderground auslesen]]<br />
* Beispiel: [[Pollenflug]]<br />
* Beispiel: [[HTTPMOD Beispielkonfiguration zur Anbindung einer Daikin Klimaanlage mit WLAN-Modul]]<br />
* {{Link2Forum|Topic=17804|LinkText=Thread}} in FHEM Forum that discusses the first version of this module <br />
* {{Link2Forum|Topic=29471|LinkText=Thread}} in FHEM Forum that discusses the second major version of this module <br />
* {{Link2Forum|Topic=45176|LinkText=Thread}} in FHEM Forum that discusses the third major version of this module <br />
* [http://perldoc.perl.org/perlretut.html Introduction to regular expressions]<br />
* [http://portswigger.net/burp/ BurpSuite]: Tool (local proxy) to help analyze http traffic<br />
<br />
[[Kategorie:IP Components]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=HTTPMOD&diff=22567HTTPMOD2017-09-16T12:06:30Z<p>Amenomade: /* Further replacements of URL, header or post data */ neues beispiel - Rika Ofen</p>
<hr />
<div>{{Infobox Modul<br />
|ModPurpose=Extract information from devices with an HTTP interface (or, more generic, from any URL) or send information to such devices <br />
|ModType=d<br />
|ModCmdRef=HTTPMOD<br />
|ModForumArea=Sonstiges<br />
|ModTechName=98_HTTPMOD.pm<br />
|ModOwner=StefanStrobel ({{Link2FU|3960|Forum}} / [[Benutzer:StefanStrobel|Wiki]])<br />
}}<br />
<br />
HTTPMOD provides a generic way to retrieve information from devices with an HTTP Interface and store them in Readings or send information to such devices. It queries a given URL with Headers and data defined by attributes. <br />
<br />
From the HTTP response it extracts readings named in attributes using Regexes, JSON or XPath parsing also defined by attributes.<br />
<br />
In an advanced [[Konfiguration|configuration]] the module can also send information to devices. To do this, a generic <code>set</code> option can be configured using attributes. <br />
<br />
== Availability == <br />
The module is part of the regular FHEM distribution.<br />
<br />
== Prerequisites ==<br />
This module uses the non blocking HTTP function <code>HttpUtils_NonblockingGet</code> provided by FHEM's [[HttpUtils]] in a new version published in December 2013.<br />
If not already installed in your environment, please [[update]] FHEM or install it manually using appropriate commands from your environment.<br />
Please also note that FHEM HttpUtils need the global attribute dnsServer to be set in order to work really non blocking even when dns requests can not be answered.<br />
<br />
== Define ==<br />
<syntaxhighlight lang="perl"><br />
define <name> HTTPMOD <URL> <Interval><br />
</syntaxhighlight><br />
The module connects to the given <code>URL</code> every <code>Interval</code> seconds, sends optional headers and data and then parses the response with regular expressions, xpath or json to set readings.<br />
<br />
URL can be "none" and Interval can be 0 if you prefer to only query data with a get command and not in a defined interval.<br />
<br />
Example:<br />
<syntaxhighlight lang="perl"><br />
define PM HTTPMOD http://MyPoolManager/cgi-bin/webgui.fcgi 60<br />
</syntaxhighlight><br />
<br />
== Set-Commands ==<br />
can be defined using attributes, see advanced configuration<br />
<br />
If you set the attribute enableControlSet to 1, the following additional built in set commands are available:<br />
;interval<br />
:set new interval time in seconds and restart the timer<br />
;reread<br />
:request the defined URL and try to parse it just like the automatic update would do it every Interval seconds without modifying the running timer.<br />
;stop<br />
:stop interval timer.<br />
;start<br />
:restart interval timer to call GetUpdate after interval seconds<br />
;upgradeAttributes<br />
:convert outdated attributes for older HTTPMOD-Versions that are still defined for this device from the old syntax to the new one.<br />
:attributes with the description "this attribute should not be used anymore" or similar will be translated to the new syntax, e.g. readingsName1 to reading01Name.<br />
;storeKeyValue<br />
:stores a key value pair in an obfuscated form in the file system. Such values can then be used in replacements where the mode is "key" e.g. to avoid storing passwords in the configuration in clear text<br />
<br />
== Get-Commands ==<br />
can be defined using attributes, see advanced configuration<br />
<br />
== simple Attributes ==<br />
;do_not_notify<br />
<br />
;readingFnAttributes<br />
<br />
;requestHeader.* <br />
:Define an additional HTTP Header to set in the HTTP request<br />
<br />
;requestData<br />
:POST Data to be sent in the request. If not defined, it will be a GET request as defined in HttpUtils used by this module<br />
<br />
;reading[0-9]+(-[0-9]+)?Name<br />
:the name of a reading to extract with the corresponding readingRegex<br />
<br />
;reading[0-9]*(-[0-9]+)?OExpr<br />
:defines an expression that is used in an eval to compute the readings value. The raw value will be in the variable $val.<br />
<br />
;reading[0-9]*(-[0-9]+)?OMap<br />
:Output Map. Defines a mapping from raw to visible values like "0:mittig, 1:oberhalb, 2:unterhalb". If specified as readingOMap then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*OMap.<br />
<br />
;reading[0-9]*(-[0-9]+)?Format<br />
:Defines a format string that will be used in sprintf to format a reading value. If specified as readingFormat then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Format.<br />
<br />
;reading[0-9]*(-[0-9]+)?Decode<br />
:defines an encoding to be used in a call to the perl function decode to convert the raw data string read from the device to a reading. This can be used if the device delivers strings in an encoding like cp850 instead of utf8.<br />
<br />
;reading[0-9]*(-[0-9]+)?Encode<br />
:defines an encoding to be used in a call to the perl function encode to convert the raw data string read from the device to a reading. This can be used if the device delivers strings in an encoding like cp850 and after decoding it you want to reencode it to e.g. utf8.<br />
<br />
;reading[0-9]+Regex<br />
:defines the regex to be used for extracting the reading. The value to extract should be in a capture group / sub expression <br />
:e.g. ([\d\.]+) in the above example. Multiple capture groups will create multiple readings (see explanation above)<br />
<br />
;reading[0-9]+XPath<br />
:defines an xpath to one or more readings when parsing HTML data (see examples below)<br />
<br />
;reading[0-9]+XPath-Strict<br />
:defines an xpath to one or more readings when parsing XML data (see examples below)<br />
<br />
;reading[0-9]+JSON<br />
:defines a path to the JSON object wanted by concatenating the object names with an underscore as delimiter (see the example below)<br />
<br />
;noShutdown<br />
:pass the noshutdown flag to HTTPUtils for webservers that need it (some embedded webservers only deliver empty pages otherwise)<br />
<br />
;disable<br />
:stop doing automatic HTTP requests while this attribute is set to 1<br />
<br />
;timeout<br />
:time in seconds to wait for an answer. Default value is 2<br />
<br />
;enableControlSet<br />
:enables the built in set commands ''interval'', ''stop'', ''start'', ''reread'', ''upgradeAttributes'', ''storeKeyValue''<br />
<br />
== Simple Configuration of HTTP Devices ==<br />
If your device expects special HTTP-headers then specify them as <code>attr requestHeader1</code> to <code>attr requestHeaderX</code>.<br />
If your Device expects an HTTP POST instead of HTTP GET then the POST-data can be specified as <code>attr requestData</code>.<br />
To get the readings, specify pairs of <code>attr readingXName</code> and <code>attr readingXRegex</code>, <code>attr readingXXPath</code>, <code>attr readingXXPath-Strict</code> or <code>attr readingXJSON</code> to define which readings you want to extract from the HTTP response and how to extract them. (The old syntax <code>attr readingsNameX</code> and <code>attr readingsRegexX</code> is still supported but the new one with <code>attr readingXName</code> and <code>attr readingXRegex</code> should be preferred. The actual values to be extracted have to be sub expressions within () in the regex (see example below)<br />
<br />
=== Example for a PoolManager 5: ===<br />
The PoolManager Web GUI can be queried with HTTP POST Requests like this one:<br />
<br />
<syntaxhighlight lang="perl"><br />
POST /cgi-bin/webgui.fcgi HTTP/1.1<br />
Host: 192.168.70.90<br />
Accept: */*<br />
Content-Type: application/json;charset=UTF-8<br />
Content-Length: 60<br />
<br />
{"get" :["34.4001.value" ,"34.4008.value" ,"34.4033.value"]}<br />
</syntaxhighlight><br />
<br />
The resulting HTTP Response would look like this:<br />
<br />
<syntaxhighlight lang="perl"><br />
HTTP/1.1 200 OK<br />
Content-type: application/json; charset=UTF-8<br />
Expires: 0<br />
Cache-Control: no-cache<br />
Date: Sun, 12 Jan 2014 12:23:11 GMT<br />
Server: lighttpd/1.4.26<br />
Content-Length: 179<br />
<br />
{<br />
"data": {<br />
"34.4001.value": "7.00",<br />
"34.4008.value": "0.52",<br />
"34.4033.value": "24.8"<br />
},<br />
"status": {<br />
"code": 0<br />
},<br />
"event": {<br />
"type": 1,<br />
"data": "48.30000.0"<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
To configure HTTPMOD for a PoolManager one would first define a PoolManager device with e.g. the name PM, the URL and an interval of e.g. 60 seconds. <br />
<br />
Then the data to be sent in the request needs to be defined because in this example the device expects a POST request so the query is not contained in the URL but in the request data.<br />
<br />
Also as seen above the device expects special HTTP headers in the request so these headers also need to be defined as <code>attr PM requestHeader1</code> and <code>attr PM requestHeader2</code><br />
<br />
Then the names of the readings to be extracted would be set with attributes<br />
<br />
Then for each reading value to be extracted a regular expression needs to be set that will match the value in question within ().<br />
<br />
Example:<br />
<syntaxhighlight lang="perl"><br />
define PM HTTPMOD http://MyPoolManager/cgi-bin/webgui.fcgi 60<br />
attr PM reading01Name PH<br />
attr PM reading01Regex 34.4001.value":[ \t]+"([\d\.]+)"<br />
<br />
attr PM reading02Name CL<br />
attr PM reading02Regex 34.4008.value":[ \t]+"([\d\.]+)"<br />
<br />
attr PM reading03Name3TEMP<br />
attr PM reading03Regex 34.4033.value":[ \t]+"([\d\.]+)"<br />
<br />
attr PM requestData {"get" :["34.4001.value" ,"34.4008.value" ,"34.4033.value", "14.16601.value", "14.16602.value"]}<br />
attr PM requestHeader1 Content-Type: application/json<br />
attr PM requestHeader2 Accept: */*<br />
attr PM stateFormat {sprintf("%.1f Grad, PH %.1f, %.1f mg/l Chlor", ReadingsVal($name,"TEMP",0), ReadingsVal($name,"PH",0), ReadingsVal($name,"CL",0))}<br />
</syntaxhighlight><br />
<br />
<br />
=== Example for AmbientMonitor ===<br />
AmbientMonitor is a webbased visualisation for sensors connected to an Arduino device. Its web interface can also be queried with HTTMOD to grab the data into readings.<br />
<br />
This example was provided by locutus. The hardware configuration is an Arduino + Ethercard with ENC28J60 Controller + DHT22 Sensor and software can be downloaded from https://github.com/lucadentella/AmbientMonitor<br />
<br />
In this example an HTTP GET is sufficent, so no <code>requestData</code> is needed. The device provides temperature and humidity readings in an HTTP response that looks like:<br />
<syntaxhighlight lang="perl"><br />
HTTP/1.0 200 OK <br />
Content-Type: text/html <br />
<br />
myCB({'temperature':22.00,'humidity':46.00})<br />
</syntaxhighlight><br />
<br />
the definition could be:<br />
<syntaxhighlight lang="perl"><br />
define AmbientMonitor HTTPMOD http://192.168.1.221/?callback=? 300<br />
attr AmbientMonitor requestHeader Content-Type: application/json<br />
attr AmbientMonitor reading1Name Temperatur<br />
attr AmbientMonitor reading1Regex temperature':([\d\.]+)<br />
attr AmbientMonitor reading2Name Feuchtigkeit<br />
attr AmbientMonitor reading2Regex humidity':([\d\.]+)<br />
attr AmbientMonitor stateFormat {sprintf("Temperatur %.1f C, Feuchtigkeit %.1f %", ReadingsVal($name,"Temperatur",0), ReadingsVal($name,"Feuchtigkeit",0))}<br />
</syntaxhighlight><br />
<br />
<br />
== formatting and manipulating values / readings ==<br />
Values that are parsed from an HTTP response can be further treated or formatted with the following attributes:<br />
<br />
* <code>(reading|get)[0-9]*(-[0-9]+)?OExpr</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?OMap</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?Format</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?Decode</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?Encode</code><br />
<br />
They can all be specified for an individual reading, for all readings in one match (e.g. if a regular expression has several capture groups) or for all readings in a get command (defined by getXX) or for all readings in the main reading list (defined by readingXX):<br />
<syntaxhighlight lang="perl"><br />
reading01Format %.1f<br />
</syntaxhighlight><br />
<br />
will format the reading with the name specified by the attribute reading01Name to be numerical with one digit after the decimal point.<br />
If the attribute reading01Regex is used and contains several capture groups then the format will be applied to all readings parsed by this regex unless these readings have their own format specified by reading01-1Format, reading01-2Format and so on.<br />
<br />
<syntaxhighlight lang="perl"><br />
reading01-2Format %.1f<br />
</syntaxhighlight><br />
<br />
Can be used in cases where a regular expression specified as reading01regex contains several capture groups or an xpath specified as reading01XPath creates several readings. <br />
In this case reading01-2Format specifies the format to be applied to the second match.<br />
<br />
<syntaxhighlight lang="perl"><br />
readingFormat %.1f<br />
</syntaxhighlight><br />
<br />
applies to all readings defined by a reading-Attribute that have no more specific format.<br />
<br />
If you need to do some calculation on a raw value before it is used as a reading, you can define the attribute <code>readingOExpr</code>.<br />
It defines a Perl expression that is used in an eval to compute the readings value. The raw value will be in the variable $val.<br />
<br />
Example for an expression:<br />
<syntaxhighlight lang="perl"><br />
attr PM reading03OExpr $val * 10<br />
</syntaxhighlight><br />
Just like in the above example of the readingFormat attributes, readingOExpr and the other following attributes can be applied on several levels.<br />
<br />
To map a numerical value to a name, you can use the readingOMap attribute. <br />
It defines a mapping from raw to visible values like "0:mittig, 1:oberhalb, 2:unterhalb".<br />
<br />
Example for a map:<br />
<syntaxhighlight lang="perl"><br />
attr PM reading02-3OMap 0:kalt, 1:warm, 2:sehr warm<br />
</syntaxhighlight><br />
<br />
To convert character sets, the module can first decode a string read from the device and then encode it again. For example:<br />
<syntaxhighlight lang="perl"><br />
attr PM getDecode UTF-8<br />
</syntaxhighlight><br />
<br />
This applies to all readings defined for Get-Commands.<br />
<br />
== Some help with Regular Expressions ==<br />
If HTTPMOD seems not to work and the FHEM Logfile contains a message like <br />
:<code>HTTPMOD: Response didn't match Reading ...</code><br />
then you should check if the value you want to extract is read into the internal with the name buf. Internals are visible when you click on the defined HTTPMOD Device. buf is an internal variable that contains the HTTP Response read. If the value is there and you get the mentioned message then probably something is wrong with your regular expression. Please note that buf might contain special characters like newlines but they are not shown in fhemweb. If you are new to regular expressions then the introduction at http://perldoc.perl.org/perlretut.html might be helpful. <br />
<br />
For a typical HTTPMOD use case where you want to extract a number out of a HTTP-Response you can use something like <code>[\d\.]+</code> to match the number itself. The expression matches the number characters (<code>\d</code>) or a <code>.</code> if one of these characters occurs at least once. <br />
<br />
To tell HTTPMOD that the number is what you want to use for the reading, you have to put the expression in between <code>()</code>. A <code>([\d\.]+)</code> alone would match the longest number in the HTTP Response which is very likely not the number you are looking for so you need to add something to the expression to give it a context and define how to find the number that you are looking for.<br />
<br />
If there is a title text before the number or a special text after the number you can put this in the regex. In one of the examples above <code>humidity':([\d\.]+)</code> is looking for the number that immediately follows the text <code>humidity':</code> without any blanks in between.<br />
Be careful if the text you are getting from your device contains special characters like newline. You don't see such special characters in the fhem webinterface as contents of the internal buf but they might cause your regular expression to fail. <br />
<br />
If you have trouble defining a regular expression that matches a certain name, then many complicated characters and then a number, it might be helpful to use a negation in matching like <code>temp[^\d]+([\d\.]).*</code>. In this examle <code>[^\d]+</code> means any character that is not a numerical digit, more than once.<br />
<br />
=== Regular Expressions with multiple capture Groups ===<br />
The regular expressions used in the above example for a Poolmanager will take the value that matches one capture group. This is the part of the regular expression inside (). In the above example "([\d\.]+)" refers to numerical digits or points between double quotation marks. Only the string consiting of digits and points will match inside (). This piece is assigned to the reading.<br />
<br />
You can also use regular expressions that have several capture groups which might be helpful when parsing tables. In this case an attribute like <br />
<br />
<syntaxhighlight lang="perl"><br />
reading02Regex something[ \t]+([\d\.]+)[ \t]+([\d\.]+)<br />
</syntaxhighlight><br />
<br />
could match two numbers. When you specify only one reading02Name like <br />
<syntaxhighlight lang="perl"><br />
reading02Name Temp<br />
</syntaxhighlight><br />
<br />
the name Temp will be used with the extension -1 and -2 thus giving a reading Temp-1 for the first number and Temp-2 for the second. You can also specify individual names for several readings that get parsed from one regular expression with several capture groups by defining attributes <br />
<br />
<syntaxhighlight lang="perl"><br />
reading02-1Name<br />
reading02-2Name<br />
...<br />
</syntaxhighlight><br />
The same notation can be used for formatting attributes like readingXOMap, readingXFormat and so on.<br />
<br />
The usual way to define readings is however to have an individual regular expression with just one capture group per reading as shown in the above example.<br />
<br />
== Parsing JSON ==<br />
<br />
If a webservice delivers data in JSON format, HTTPMOD can directly parse JSON which might be easier in this case than definig regular expressions.<br />
The next example shows the data that can be requested from a Poolmanager with the following partial configuration:<br />
<br />
<syntaxhighlight lang="perl"><br />
define test2 HTTPMOD none 0<br />
attr test2 get01Name Chlor<br />
attr test2 getURL http://192.168.70.90/cgi-bin/webgui.fcgi<br />
attr test2 getHeader1 Content-Type: application/json<br />
attr test2 getHeader2 Accept: */*<br />
attr test2 getData {"get" :["34.4008.value"]}<br />
</syntaxhighlight><br />
<br />
The data in the HTTP response looks like this:<br />
<br />
<syntaxhighlight lang="perl"><br />
{<br />
"data": {<br />
"34.4008.value": "0.25"<br />
},<br />
"status": {<br />
"code": 0<br />
},<br />
"event": {<br />
"type": 1,<br />
"data": "48.30000.0"<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
the classic way to extract the value 0.25 into a reading with the name Chlor with a regex would have been<br />
<syntaxhighlight lang="perl"><br />
attr test2 get01Regex 34.4008.value":[ \t]+"([\d\.]+)"<br />
</syntaxhighlight><br />
<br />
with JSON you can write <br />
<syntaxhighlight lang="perl"><br />
attr test2 get01JSON data_34.4008.value <br />
</syntaxhighlight><br />
which will create a reading with the Name "Chlor" (as shown above) and take the value 0.25 from the JSON string.<br />
<br />
or if you don't care about the naming of your readings, you can simply extract all JSON data with <br />
<syntaxhighlight lang="perl"><br />
attr test2 extractAllJSON<br />
</syntaxhighlight><br />
<br />
which would apply to all data read from this device and create the following readings out of the HTTP response shown above:<br />
<br />
{| class="wikitable"<br />
| data_34.4008.value || 0.25<br />
|-<br />
| event_data || 48.30000.0<br />
|-<br />
| event_type || 1<br />
|-<br />
| status_code || 0<br />
|}<br />
<br />
or you can specify<br />
<syntaxhighlight lang="perl"><br />
attr test2 get01ExtractAllJSON<br />
</syntaxhighlight><br />
which would only apply to all data read as response to the get command defined as get01. <br />
<br />
It might seem very simple at first sight to use extractAllJSON but if you prefer readings with a meaningful name you should instead define these readings with readingXXName and readingXXJSON or getXXName and getXXJSON individually. Of Course it would be possible to create additional user readings outside HTTPMOD but doing calculations, naming and formatting inside HTTPMOD is more efficient.<br />
<br />
=== JSON Lists ===<br />
<br />
imagine the HTTP Response contains:<br />
<br />
<syntaxhighlight lang="perl"><br />
{ "power":"0",<br />
"modes":["Off","SimpleColor","RainbowChase"],<br />
"code1":3,<br />
"code2":4<br />
}<br />
</syntaxhighlight><br />
<br />
then a configuration like <br />
<br />
<syntaxhighlight lang="perl"><br />
attr device reading01JSON modes <br />
attr device reading01Name Mode <br />
</syntaxhighlight><br />
<br />
will create a list of Subreadings just like a regex with multiple matches can create multiple subreadings:<br />
<br />
{| class="wikitable"<br />
| Mode-1 || Off<br />
|-<br />
| Mode-2 || SimpleColor<br />
|-<br />
| Mode-3 || RainbowChase <br />
|}<br />
<br />
if you don't want several subreadings but one reading that contains the list of modes, you can specify a recombine expression:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr device reading01Name Modes <br />
attr device reading01RecombineExpr join ",", @matchlist <br />
</syntaxhighlight><br />
<br />
which will create one reading containing a list:<br />
<br />
{| class="wikitable"<br />
| Modes || Off,SimpleColor,RainbowChase<br />
|}<br />
<br />
JSON parsing specifications also don't Need to match exactly. If there is no exact match for a defined reading, the HTTPMOD will try to Interpret the specification as a regex and look for json object paths that match the specification as a regex. For example:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr device reading01Name CodeElem<br />
attr device reading01JSON code<br />
</syntaxhighlight><br />
<br />
which will create a list of readings:<br />
<br />
{| class="wikitable"<br />
| CodeElem-1|| 3<br />
|-<br />
| CodeElem-2 || 4<br />
|}<br />
<br />
and of course they could also be recombined into one reading with a RecombineExpr Attribute.<br />
<br />
== Parsing http / XML using xpath ==<br />
Another alternative to regex parsing is the use of XPath to extract values from HTTP responses.<br />
The following example shows how XML data can be parsed with XPath-Strict or HTML Data can be parsed with XPath.<br />
Both work similar and the example uses XML Data parsed with the XPath-Strict option:<br />
<br />
If The XML data in the HTTP response looks like this:<br />
<br />
<syntaxhighlight lang="xml"><br />
<root xmlns:foo="http://www.foo.org/" xmlns:bar="http://www.bar.org"><br />
<actors><br />
<actor id="1">Peter X</actor><br />
<actor id="2">Charles Y</actor><br />
<actor id="3">John Doe</actor><br />
</actor><br />
</root><br />
</syntaxhighlight><br />
<br />
with XPath you can write <br />
<syntaxhighlight lang="perl"><br />
attr htest reading01Name Actor<br />
attr htest reading01XPath-Strict //actor[2]/text()<br />
</syntaxhighlight><br />
<br />
This will create a reading with the Name "Actor" and the value "Charles Y".<br />
<br />
Since XPath specifications can define several values / matches, HTTPMOD can also interpret these and store them in multiple readings:<br />
<syntaxhighlight lang="perl"><br />
attr htest reading01Name Actor<br />
attr htest reading01XPath-Strict //actor/text()<br />
</syntaxhighlight><br />
<br />
will create the readings <br />
<br />
{| class="wikitable"<br />
| Actor-1 || Peter X<br />
|-<br />
| Actor-2 || Charles Y<br />
|-<br />
| Actor-3 || John Doe<br />
|}<br />
<br />
== Further replacements of URL, header or post data ==<br />
sometimes it might be helpful to dynamically change parts of a URL, HTTP header or post data depending on existing readings, internals or <br />
perl expressions at runtime. This might be needed to pass further variables to a server, a current date or other things. <br />
<br />
To support this HTTPMOD offers generic replacements that are applied to a request before it is sent to the server. A replacement can be defined with the attributes <br />
<br />
* <code>replacement[0-9]*Regex</code><br />
* <code>replacement[0-9]*Mode</code><br />
* <code>replacement[0-9]*Value</code><br />
* <code>[gs]et[0-9]*Replacement[0-9]*Value</code><br />
<br />
a replacement always replaces a match of a regular expression. <br />
<br />
'''replacement[0-9]*Mode:'''<br />
The way the replacement value is defined can be specified with the replacement mode.<br />
* If the <code>replacement[0-9]*Mode</code> is <code>reading</code>, then the corresponding <code>replacement[0-9]*Value</code> is interpreted as the name of a ''reading'' of the same device or as ''device:reading'' to refer to another device.<br />
* If the <code>replacement[0-9]*Mode</code> is <code>internal</code>, then the corresponding <code>replacement[0-9]*Value</code> is interpreted as the name of an ''internal'' of the same device or as ''device:internal'' to refer to another device.<br />
* If the <code>replacement[0-9]*Mode</code> is <code>text</code>, then the corresponding <code>replacement[0-9]*Value</code> is interpreted as a static text<br />
* If the <code>replacement[0-9]*Mode</code> is <code>expression</code>, then the corresponding <code>replacement[0-9]*Value</code> is evaluated as a perl expression to compute the replacement. Inside such a replacement expression it is possible to refer to capture groups of the replacement regex.<br />
* If the <code>replacement[0-9]*Mode</code> is <code>key</code>, then the module will use a value from a key / value pair that is stored in an obfuscated form in the file system with the set storeKeyValue command. This might be useful for storing passwords.<br />
<br />
<br />
Example:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr mydevice getData {"get" :["%%value%%.value"]}<br />
attr mydevice replacement01Mode text<br />
attr mydevice replacement01Regex %%value%%<br />
<br />
attr mydevice get01Name Chlor<br />
attr mydevice get01Replacement01Value 34.4008<br />
<br />
attr mydevice get02Name Something<br />
attr mydevice get02Replacement01Value 31.4024<br />
<br />
attr mydevice get05Name profile<br />
attr mydevice get05URL http://www.mydevice.local/getprofile?password=%%password%%<br />
attr mydevice replacement02Mode key<br />
attr mydevice replacement02Regex %%password%%<br />
attr mydevice get05Replacement02Value password<br />
</syntaxhighlight> <br />
<br />
defines that <code>%%value%%</code> will be replaced by a static text.<br />
<br />
All Get commands will be HTTP post requests of a similar form. Only the <code>%%value%%</code> will be different from get to get.<br />
The first get will set the reading named Chlor and for the request it will take the generic getData and replace %%value%% with 34.4008.<br />
<br />
A second get will look the same except a different name and replacement value.<br />
<br />
With the command <code>set storeKeyValue password geheim</code> you can store the password geheim in an obfuscated form in the file system. <br />
To use this password and send it in a request you can use the above replacement with mode key. The value password will then refer to the ofuscated string stored with the key password.<br />
<br />
The mode <code>expression</code> allows you to define your own replacement syntax:<br />
<syntaxhighlight lang="perl"> <br />
attr mydevice replacement01Mode expression<br />
attr mydevice replacement01Regex {{([^}]+)}}<br />
attr mydevice replacement01Value ReadingsVal("mydevice", $1, "")<br />
attr mydevice getData {"get" :["{{temp}}.value"]}<br />
</syntaxhighlight> <br />
<br />
In this example any <code><nowiki>{{name}}</nowiki></code> in a URL, header or post data will be passed on to the perl function ReadingsVal <br />
which uses the string between <code><nowiki>{{}}</nowiki></code> as second parameter. This way one defined replacement can be used for many different<br />
readings.<br />
<br />
HTTPMOD has two built in replacements: One for session Ids and another one for the input value in a set command.<br />
The placeholder $sid is always replaced with the internal <code>$hash->{sid}</code> which contains the session id after it is extracted from a previous HTTP response. <br />
If you don't like to use the placeholder $sid then you can define your own replacement for example like:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr mydevice replacement01Mode internal<br />
attr mydevice replacement01Regex %session%<br />
attr mydevice replacement01Value sid<br />
</syntaxhighlight> <br />
<br />
Now the internal <code>$hash->{sid}</code> will be used as a replacement for the placeholder %session%.<br />
<br />
In the same way a value that is passed to a set-command can be put into a request with a user defined replacement. <br />
In this case the internal <code>$hash->{value}</code> will contain the value passed to the set command. <br />
<code>$hash->{value}</code> might even be a string containing several values that could be put into several different positions in a request by using user defined replacements.<br />
<br />
'''Other example : steering a pellet stove from Rika'''<br />
<br />
The stove API of Rika on https://www.rika-firenet.com/web/ delivers a JSON string with all settings and values, and can be piloted with a data string containing all the "set" values at once.<br />
Delivered JSON on get https://www.rika-firenet.com/api/client/xxxxxxxx/status : (xxxxxxxx must be replaced with the unique stove ID)<br />
<syntaxhighlight lang="perl"><br />
{<br />
"name": "Vorzimmer",<br />
"stoveID": "xxxxxxxxx",<br />
"lastSeenMinutes": 1,<br />
"lastConfirmedRevision": 1504385700,<br />
"controls": {<br />
"revision": 1504385700,<br />
"onOff": true,<br />
"operatingMode": 2,<br />
"heatingPower": 65,<br />
"targetTemperature": 24,<br />
"heatingTimesActive": false,<br />
"heatingTimesActiveForComfort": true,<br />
"setBackTemperature": 18,<br />
"convectionFan1Active": false,<br />
"convectionFan1Level": 0,<br />
"convectionFan1Area": 0,<br />
"convectionFan2Active": false,<br />
"convectionFan2Level": 0,<br />
"convectionFan2Area": 0,<br />
"frostProtectionActive": false,<br />
"frostProtectionTemperature": 5<br />
},<br />
"sensors": {<br />
"statusError": 0,<br />
"statusWarning": 0,<br />
"statusService": 0,<br />
"statusMainState": 1,<br />
"statusSubState": 3,<br />
"statusFrostStarted": false,<br />
"inputFlameTemperature": 21,<br />
"inputRoomTemperature": 21,<br />
"inputExternalRequest": true,<br />
"outputDischargeMotor": 0,<br />
"outputInsertionMotor": 0,<br />
"outputIDFan": 0,<br />
"outputAirFlaps": 0,<br />
"outputIgnition": false,<br />
"parameterStoveTypeNumber": 13,<br />
"parameterVersionMainBoard": 223,<br />
"parameterVersionTFT": 223,<br />
"parameterRuntimePellets": 11,<br />
"parameterRuntimeLogs": 0,<br />
"parameterFeedRateTotal": 17,<br />
"parameterFeedRateService": 683,<br />
"parameterOnOffCycles": 2<br />
},<br />
"stoveType": "DOMO MultiAir",<br />
"stoveFeatures": {<br />
"multiAir1": true,<br />
"multiAir2": true,<br />
"insertionMotor": false,<br />
"airFlaps": false,<br />
"logRuntime": false<br />
}<br />
}<br />
</syntaxhighlight><br />
<br />
Data string to send to https://www.rika-firenet.com/api/client/xxxxxxxx/controls in order to set values:<br />
<syntaxhighlight lang="perl"><br />
heatingTimesActiveForComfort=true&frostProtectionTemperature=3&setBackTemperature=18&targetTemperature=24&convectionFan2Level=0&convectionFan2Active=false&convectionFan1Level=0&onOff=true&convectionFan1Active=false&convectionFan2Area=0&revision=1505550101&heatingTimesActive=false&convectionFan1Area=0&frostProtectionActive=false&operatingMode=2&heatingPower=65<br />
</syntaxhighlight><br />
<br />
Code in 99_myUtils.pm:<br />
<syntaxhighlight lang="perl"><br />
sub<br />
replaceJSON ($$) {<br />
my ($valToReplace, $value) = @_;<br />
<br />
#$value in the parameters is a default value<br />
#It has to be replaced through the real value nnn passed in the set command "set <device> valToset nnn"<br />
$value = InternalVal("Ofen", "value", $value);<br />
Log3 ("Ofen", 3, "replaceJSON Internalvalue: $value");<br />
<br />
#Force an update to avoid outdated revision number<br />
fhem ("get Ofen revision");<br />
<br />
#Get all the controls as json<br />
my $json = ReadingsVal("Ofen", "controlsJSON","");<br />
Log3 ("Ofen", 3, "replaceJSON configsJSON: $json");<br />
<br />
# When starting FHEM or rereading config, the reading controlsJSON is empty<br />
return if ($json eq ""); <br />
<br />
my $decoded = decode_json($json);<br />
my $result;<br />
for my $key ( keys %$decoded ) {<br />
$result .= "$key=";<br />
if ($key eq $valToReplace) {<br />
$result .= $value."&";<br />
} else {<br />
$result .= $decoded->{$key}."&";<br />
}<br />
}<br />
chop($result); #remove last &<br />
Log3("Ofen", 3, "replaceJSON Result: $result");<br />
return $result;<br />
}<br />
</syntaxhighlight><br />
<br />
Define stove in fhem:<br />
<syntaxhighlight lang="perl"><br />
defmod Ofen HTTPMOD https://www.rika-firenet.com/api/client/xxxxxxxx/status 60<br />
<br />
attr Ofen enableCookies 1<br />
attr Ofen reAuthRegex id="login"|Unauthorized<br />
attr Ofen sid01Data email=xx@xx&password=xx<br />
attr Ofen sid01URL https://www.rika-firenet.com/web/login<br />
<br />
attr Ofen reading01JSON sensors_inputRoomTemperature<br />
attr Ofen reading01Name RaumTemp<br />
attr Ofen reading02JSON controls_setBackTemperature<br />
attr Ofen reading02Name Absenkung<br />
attr Ofen reading03JSON controls_frostProtectionTemperature<br />
attr Ofen reading03Name Frostschutz<br />
attr Ofen reading10Name controlsJSON<br />
attr Ofen reading10Regex (?s)controls.*?({.*?})<br />
<br />
attr Ofen get09Name revision<br />
attr Ofen get09URL https://www.rika-firenet.com/api/client/xxxxxxxx/status<br />
<br />
attr Ofen setURL https://www.rika-firenet.com/api/client/xxxxxxxx/controls<br />
attr Ofen setData {{data}}<br />
attr Ofen replacement01Mode expression<br />
attr Ofen replacement01Regex {{data}}<br />
<br />
attr Ofen set11Name frostProtectionTemperature<br />
attr Ofen set11Replacement01Value replaceJSON("frostProtectionTemperature", 2)<br />
<br />
attr Ofen set12Name targetTemperature<br />
attr Ofen set12Replacement01Value replaceJSON("targetTemperature", 24)<br />
</syntaxhighlight><br />
<br />
A detailed explanation (in german) of the login process can be found here: [https://forum.fhem.de/index.php/topic,76220.msg682514.html#msg682514]<br />
and the explanation of the other parameters here: [https://forum.fhem.de/index.php/topic,76220.msg685710.html#msg685710]<br />
<br />
== replacing reading values when they have not been updated / the device did not respond ==<br />
If a device does not respond then the values stored in readings will keep the same and only their timestamp shows that they are outdated. <br />
If you want to modify reading values that have not been updated for a number of seconds, you can use the attributes<br />
<br />
* <code>(reading|get)[0-9]*(-[0-9]+)?MaxAge</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?MaxAgeReplacementMode</code><br />
* <code>(reading|get)[0-9]*(-[0-9]+)?MaxAgeReplacement</code><br />
<br />
Every time the module tries to read from a device, it will also check if readings have not been updated <br />
for longer than the <code>MaxAge</code> attributes allow. If readings are outdated, the <code>MaxAgeReplacementMode</code> defines how the affected<br />
reading values should be replaced. <code>MaxAgeReplacementMode</code> can be <code>text</code>, <code>reading</code>, <code>internal</code>, <code>expression</code> or <code>delete</code>.<br />
<br />
<code>MaxAge</code> specifies the number of seconds that a reading should remain untouched before it is replaced. <br />
<br />
<code>MaxAgeReplacement</code> contains either a static text that is used as replacement value or a Perl expression that is evaluated to <br />
give the replacement value. This can be used for example to replace a temperature that has not bee updated for more than 5 minutes <br />
with the string "outdated - was 12": <br />
<syntaxhighlight lang="perl"><br />
attr PM readingMaxAge 300<br />
attr PM readingMaxAgeReplacement "outdated - was " . $val<br />
attr PM readingMaxAgeReplacementMode expression<br />
</syntaxhighlight><br />
The variable <code>$val</code> contains the value of the reading before it became outdated.<br />
<br />
Or to show that a device was offline:<br />
<syntaxhighlight lang="perl"><br />
attr MyLight reading01Name color<br />
attr MyLight reading01JSON result_02_color<br />
attr MyLight reading01MaxAge 300<br />
attr MyLight reading01MaxAgeReplacement "offline"<br />
attr MyLight reading01MaxAgeReplacementMode text<br />
</syntaxhighlight><br />
<br />
<br />
== Note on determining how to send requests to a special device ==<br />
If you don't know which URLs, headers or POST data your web GUI uses, you might try a local proxy like BurpSuite [http://portswigger.net/burp/ BurpSuite] to track requests and responses. This is a tedious task but probably the best way to achieve a successful result. <br />
<br />
Let us consider an example. The Telekom Speedport W724V has a login-site that is famous for being cumbersome. Burp allows to monitor each step in the login procedure. In the case of a speedport the following steps occur:<br />
<br />
First burp shows that a get command is issued<br />
################################################################################################## <br />
GET / HTTP/1.1<br />
Host: speedport.ip<br />
Cache-Control: max-age=0<br />
Upgrade-Insecure-Requests: 1<br />
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36<br />
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8<br />
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4<br />
Cookie: lang=de<br />
Connection: close <br />
In order to mimic the behavior of a real person calling the website HTTPMOD should copy all necessary steps. Host, Cookie and the GET-command are usually necessary. The same cannot be said of the User-Agent because the website can be called from any mobile or desktop computer. <br />
<br />
Then, the speedport will answer with a command that consists of several lines. By going through every line for every step in the login procedure one will finally arrive at the information that is necessary to successfully enter the login of the speedport (in case of the W724V, for example, it is necessary to copy a token called _httoken and to include the referer).<br />
<br />
== Advanced configuration to define a <code>set</code> command and send data to a device ==<br />
<br />
When a set option is defined by attributes, the module will use the value given to the set command and integrate it into an HTTP-Request that sends the value to the device. The definitions for URL, headers and post data can contain the placeholder $val which will be replaced by the value given to the set command.<br />
<br />
This can be as simple as:<br />
<syntaxhighlight lang="perl"><br />
# No cyclic requests and no main URL needed in this example<br />
define MyDevice HTTPMOD none 0<br />
<br />
attr MyDevice set01Name Licht<br />
attr MyDevice set01URL http://192.168.1.22/switch=$val<br />
</syntaxhighlight><br />
<br />
A user command <br />
<syntaxhighlight lang="perl"><br />
set MyDevice Licht 1<br />
</syntaxhighlight><br />
<br />
will be translated into the http GET request<br />
<syntaxhighlight lang="perl"><br />
http://192.168.1.22/switch=1<br />
</syntaxhighlight><br />
<br />
In this example a map would also be helpful, that translates on / off to 0 or 1 and allows the user to select on/of in fhemweb:<br />
<syntaxhighlight lang="perl"><br />
attr MyDevive set01IMap 0:off, 1:on<br />
</syntaxhighlight><br />
This also provides input validation to make sure that only on and off can be used with the set command.<br />
<br />
In more complex Scenarios you might need to login before sending a command and the Login might create a session id that has to be part of further requests either in the URL, in headers or in the post data.<br />
<br />
Extension to the above example for a PoolManager 5 where a set needs a session id in the URL and the values have to be passed in JSON strings as post data:<br />
<syntaxhighlight lang="perl"><br />
attr PM set01Name HeizungSoll<br />
attr PM set01URL http://MyPoolManager/cgi-bin/webgui.fcgi?sid=$sid<br />
attr PM set01Hint 6,10,20,30<br />
attr PM set01Min 6<br />
attr PM set01Max 30<br />
attr PM setHeader1 Content-Type: application/json<br />
attr PM set01Data {"set" :{"34.3118.value" :"$val" }}<br />
</syntaxhighlight><br />
<br />
This example defines a set option with the name HeizungSoll.<br />
By issuing <code>set PM HeizungSoll 10</code> in FHEM, the value 10 will be sent in the defined HTTP<br />
Post to URL <code>http://MyPoolManager/cgi-bin/webgui.fcgi</code> in the Post Data as<br />
<br />
<syntaxhighlight lang="html4strict"><br />
{"set" :{"34.3118.value" :"10" }}<br />
</syntaxhighlight><br />
<br />
The optional attributes set01Min and set01Max define input validations that will be checked in the set function. <br />
The optional attribute set01Hint will define a selection list for the FHEMweb GUI.<br />
<br />
The HTTP response to such a request will be ignored unless you specify the attribute <code>setParseResponse</code> <br />
for all set commands or <code>set01ParseResponse</code> for the set command with number 01.<br />
If the HTTP response to a set command is parsed then this is done like the parsing of responses to get commands and you can use the attributes ending e.g. on Format, Encode, Decode, OMap and OExpr to manipulate / format the values read.<br />
<br />
If a parameter to a set command is not numeric but should be passed on to the device as text, then you can specify the attribute setTextArg. For example: <br />
<syntaxhighlight lang="perl"><br />
attr PM set01TextArg<br />
</syntaxhighlight><br />
<br />
If a set command should not require a parameter at all, then you can specify the attribute NoArg. For example: <br />
<syntaxhighlight lang="perl"><br />
attr PM set03Name On<br />
attr PM set03NoArg<br />
</syntaxhighlight><br />
<br />
== Advanced configuration to create a valid session id that might be necessary ==<br />
In simple cases logging in works with basic authentication. In the case HTTPMOD accepts a username and password as part of the URL in the form <br />
<syntaxhighlight lang="perl"><br />
http://User:Password@192.168.1.18/something<br />
</syntaxhighlight><br />
<br />
However basic auth is seldom used. If you need to fill in a username and password in a HTML form and the session is then managed by a session id, here is how to configure this:<br />
<br />
when sending data to an HTTP-Device in a set, HTTPMOD will replace any <code>$sid</code> in the URL, Headers and Post data with the internal <code>$hash->{sid}</code>. To authenticate towards the device and give this internal a value, you can use an optional multi step login procedure defined by the following attributes: <br />
<br />
* <code>sid[0-9]*URL</code><br />
* <code>sid[0-9]*Data.*</code><br />
* <code>sid[0-9]*Header.*</code><br />
* <code>sid[0-9]*IgnoreRedirects</code><br />
* <code>idRegex</code><br />
* <code>idJSON</code><br />
* <code>idXPath</code><br />
* <code>idXPath-Strict</code><br />
* <code>(get|set|sid)[0-9]*IdRegex</code><br />
* <code>(get|set|sid)[0-9]*IdJSON</code><br />
* <code>(get|set|sid)[0-9]*IdXPath</code><br />
* <code>(get|set|sid)[0-9]*IdXPath-Strict</code><br />
<br />
Each step can have a URL, Headers, Post Data pieces and a Regex to extract a resulting Session ID into <code>$hash->{sid}</code>.<br />
HTTPMOD will create a sorted list of steps (the numbers between sid and URL / Data / Header) and the loop through these steps and send the corresponding requests to the device. For each step a $sid in a Header or Post Data will be replaced with the current content of <code>$hash->{sid}</code>.<br />
<br />
Using this feature, HTTPMOD can perform a forms based authentication and send user name, password or other necessary data to the device and save the session id for further requests.<br />
<br />
To determine when this login procedure is necessary, HTTPMOD will first try to send a request without <br />
doing the login procedure. If the result contains an error that authentication is necessary, then a login is performed. <br />
To detect such an error in the HTTP response, you can again use a regular expression, JSON or XPath, this time with the attributes <br />
<br />
* <code>reAuthRegex</code><br />
* <code>reAuthJSON</code><br />
* <code>reAuthXPath</code><br />
* <code>reAuthXPath-Strict</code><br />
* <code>(get|set)[0-9]*ReAuthRegex</code><br />
* <code>(get|set)[0-9]*ReAuthJSON</code><br />
* <code>(get|set)[0-9]*ReAuthXPath</code><br />
* <code>(get|set)[0-9]*ReAuthXPath-Strict</code><br />
<br />
reAuthJSON or reAuthXPath typically only extract one piece of data from a response. <br />
If the existence of the specified piece of data is sufficent to start a login procedure, then nothing more needs to be defined to detect this situation. <br />
If however the indicator is a status code that contains different values depending on a successful request and a failed request if a new authentication is needed, <br />
then you can combine things like reAuthJSON with reAuthRegex. In this case the regex is only matched to the data extracted by JSON (or XPath). <br />
This way you can easily extract the status code using JSON parsing and then specify the code that means "authentication needed" as a regular expression.<br />
<br />
If for one step not all of the URL, Data or Header Attributes are set, then HTTPMOD tries to use a <br />
<code>sidURL</code>, <code>sidData.*</code> or <code>sidHeader.*</code> Attribute (without the step number after sid). This way parts that are the same for all steps don't need to be defined redundantly.<br />
<br />
=== Example for a multi step login procedure: ===<br />
<syntaxhighlight lang="perl"><br />
attr PM reAuthRegex /html/dummy_login.htm <br />
attr PM sidURL http://192.168.70.90/cgi-bin/webgui.fcgi?sid=$sid<br />
attr PM sidHeader1 Content-Type: application/json<br />
attr PM sid1IDRegex wui.init\('([^']+)'<br />
attr PM sid2Data {"set" :{"9.17401.user" :"fhem" ,"9.17401.pass" :"password" }}<br />
attr PM sid3Data {"set" :{"35.5062.value" :"128" }}<br />
attr PM sid4Data {"set" :{"42.8026.code" :"pincode" }}<br />
</syntaxhighlight><br />
<br />
In this case HTTPMOD detects that a login is necessary by looking for the pattern /html/dummy_login.htm in the HTTP response. <br />
If it matches, it starts a login sequence. In the above example all steps request the same URL. In step 1 only the defined Header is sent in an HTTP get request. The response will contain a session id that is extraced with the regex wui.init\('([^']+)'.<br />
<br />
In the next step this session id is sent in a post request to the same URL where tha post data contains a username and password. The a third and a fourth request follow that set a value and a code. The result will be a valid and authorized session id that can be used in other requests where $sid is part of a URL, header or post data and will be replaced with the session id extracted above.<br />
<br />
In the special case where a session id is set as a HTTP-Cookie (with the header Set-cookie: in the HTTP response) HTTPMOD offers an even simpler way. With the attribute enableCookies a very basic cookie handling mechanism is activated that stores all cookies that the server sends to the HTTPMOD device and puts them back as cookie headers in the following requests.<br />
<br />
For such cases no sidIdRegex and no $sid in a user defined header is necessary.<br />
<br />
== Advanced configuration to define a <code>get</code> and request additional data with its own request from a device ==<br />
<br />
The normal automatic HTTP request that is done repeatedly after the defined interval has elapsed works well in cases where all required readings can be requested in one common HTTP request. If however a device needs individual requests with different URLs or different POST data for each value, then another method is necessary. <br />
For such cases a <code>get</code> option can be defined and the user can either issue FHEM <code>get</code> commands each time he needs the reading or the user can set an attribute to request the reading automatically together with the normal iteration.<br />
For each <code>get</code> option attributes define an individual URL, optional headers, and post data as well as individual regular expressions and formatting options. <br />
<br />
When a get option is defined by attributes, the module allows querying additional values from the device that require individual HTTP-Requests or special parameters to be sent<br />
<br />
Extension to the above example:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr PM get01Name MyGetValue <br><br />
attr PM get01URL http://MyPoolManager/cgi-bin/directory/webgui.fcgi?special=1?sid=$sid <br><br />
attr PM getHeader1 Content-Type: application/json <br><br />
attr PM get01Data {"get" :{"30.1234.value"}} <br><br />
</syntaxhighlight><br />
<br />
This example defines a get option with the name MyGetValue.<br />
By issuing <code>get PM MyGetValue</code> in FHEM, the defined HTTP request is sent to the device.<br />
The HTTP response is then parsed using the same readingXXName and readingXXRegex attributes as above so<br />
additional pairs will probably be needed there for additional values.<br />
<br />
if you prefer to define the parsing and formatting of readings individually per get command, you can use <br />
attributes like get01Regex, get01XPath, get01Format, get01OMap and so on just like for reading01...<br />
<br />
You can also include parameters / values that are passed to the get command in the request just like for set commands.<br />
The placeholder $val will be replaced with the value given to the get command or you can specify your own replacement as described above.<br />
<br />
If the new get parameter should also be queried regularly, you can define the following optional attributes:<br />
<br />
<syntaxhighlight lang="perl"><br />
attr PM get01Poll 1<br />
attr PM get01PollDelay 300<br />
</syntaxhighlight><br />
<br />
The first attribute includes this reading in the automatic update cycle and the second defines an alternative lower update frequency. When the interval defined initially in the define is over and the normal readings are read from the device, the update function will check for additional get parameters that should be included in the update cycle.<br />
<br />
If a PollDelay is specified for a get parameter, the update function also checks if the time passed since it has last read this value is more than the given PollDelay. If not, this reading is skipped and it will be rechecked in the next cycle when interval is over again. So the effective PollDelay will always be a multiple of the interval specified in the initial define.<br />
<br />
Please note that each defined get command that is included in the regular update cycle will create its own HTTP request. So if you want to extract several values from the same request, it is much more efficient to do this by defining readingXXName and readingXXRegex, XPath or JSON attributes and to specify an interval and a URL in the define of the HTTPMOD device. <br />
<br />
Example for a Siemens webserver provided by Lanhydrock:<br />
<syntaxhighlight lang="perl"><br />
define ozw672 HTTPMOD https://192.168.178.8/api/auth/login.json?user=test&pwd=test 300<br />
<br />
attr ozw672 get1Name tempAussen<br />
attr ozw672 get1URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1960<br />
attr ozw672 get1Poll 1<br />
attr ozw672 get1PollDelay 1800<br />
<br />
attr ozw672 get2Name tempAussenGemischt<br />
attr ozw672 get2URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1964<br />
attr ozw672 get2Poll 1<br />
attr ozw672 get2PollDelay 1800<br />
<br />
attr ozw672 get3Name tempTWW<br />
attr ozw672 get3URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1996<br />
attr ozw672 get3Poll 1<br />
<br />
attr ozw672 get4Name tempKesselSoll<br />
attr ozw672 get4URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1910<br />
attr ozw672 get4Poll 1<br />
<br />
attr ozw672 get5Name tempKesselRuecklauf<br />
attr ozw672 get5URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1915<br />
attr ozw672 get5Poll 1<br />
<br />
attr ozw672 get6Name tempKesselRuecklaufSoll<br />
attr ozw672 get6URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1916<br />
attr ozw672 get6Poll 1<br />
<br />
attr ozw672 get7Name anzahlStartsBrenner<br />
attr ozw672 get7URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1927<br />
attr ozw672 get7PollDelay 1800<br />
attr ozw672 get7Poll 1<br />
<br />
attr ozw672 get8Name statusKessel<br />
attr ozw672 get8URL https://192.168.178.8/api/menutree/read_datapoint.json?SessionId=$sid&Id=1898<br />
attr ozw672 get8Poll 1<br />
attr ozw672 get8Regex Value": "([a-zA-Zü ]*)"<br />
attr ozw672 get8OMap Aus:0, Nachlauf aktiv:5, Freigegeben für TWW:10, Freigegeben für HK:20, In Teillastbetrieb für TWW:40, In Teillastbetrieb für HK:50, In Betrieb für Trinkwasser:90, In Betrieb für Heizkreis:100<br />
<br />
attr ozw672 getRegex Value": "[ ]*([-.0-9]*)"<br />
<br />
attr ozw672 reAuthRegex .*session not valid.*<br />
attr ozw672 sid1IDRegex .*"(.*-.*-.*-[0-9a-z]*).*<br />
attr ozw672 sid1URL https://192.168.178.8/api/auth/login.json?user=test&pwd=test<br />
</syntaxhighlight><br />
<br />
== All attributes ==<br />
;reading[0-9]+Name<br />
:the name of a reading to extract with the corresponding readingRegex, readingJSON, readingXPath or readingXPath-Strict<br />
:Please note that the old syntax <b>readingsName.*</b> does not work with all features of HTTPMOD and should be avoided. It might go away in a future version of HTTPMOD.<br />
<br />
;(get|set)[0-9]+Name<br />
:Name of a get or set command<br />
:If the HTTP response that is received after the command is parsed with an individual parse option then this name is also used as a reading name. Please note that no individual parsing needs to be defined for a get or set. If no regex, XPath or JSON is specified for the command, then HTTPMOD will try to parse the response using all the defined readingRegex, reading XPath or readingJSON attributes.<br />
<br />
;(get|set|reading)[0-9]+Regex<br />
:If this attribute is specified, the Regex defined here is used to extract the value from the HTTP Response and assign it to a Reading with the name defined in the (get|set|reading)[0-9]+Name attribute.<br />
:If this attribute is not specified for an individual Reading or get or set but without the numbers in the middle, e.g. as getRegex or readingRegex, then it applies to all the other readings / get / set commands where no specific Regex is defined.<br><br />
:The value to extract should be in a capture group / sub expression e.g. ([\d\.]+) in the above example. Multiple capture groups will create multiple readings (see explanation above)<br />
:Using this attribute for a set command (setXXRegex) only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
:Please note that the old syntax <code>readingsRegex.*</code> does not work with all features of HTTPMOD and should be avoided. It might go away in a future version of HTTPMOD.<br />
:If for get or set commands neither a generic Regex attribute without numbers nor a specific (get|set)[0-9]+Regex attribute is specified and also no XPath or JSON parsing specification is given for the get or set command, then HTTPMOD tries to use the parsing definitions for general readings defined in reading[0-9]+Name, reading[0-9]+Regex or XPath or JSON attributes and assigns the Readings that match here.<br />
<br />
;(get|set|reading)[0-9]+RegOpt<br />
:Lets the user specify regular expression modifiers. For example if the same regular expression should be matched as often as possible in the HTTP response, then you can specify RegOpt g which will case the matching to be done as /regex/g<br />
:The results will be trated the same way as multiple capture groups so the reading name will be extended with -number. <br />
:For other possible regular expression modifiers see http://perldoc.perl.org/perlre.html#Modifiers<br />
<br />
;(get|set|reading)[0-9]+XPath<br />
:defines an xpath to one or more values when parsing HTML data (see examples above)<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;get|set|reading[0-9]+XPath-Strict<br />
:defines an xpath to one or more values when parsing XML data (see examples above)<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;(get|set|reading)[0-9]+AutoNumLen<br />
:In cases where a regular expression or an XPath results in multiple results and these results are stored in a common reading name with extension -number, then you can modify the format of this number to have a fixed length with leading zeros. AutoNumLen 3 for example will lead to reading names ending with -001 -002 and so on.<br />
<br />
;(get|set|reading)[0-9]+AlwaysNum<br />
:if set to 1 this attributes forces reading names to end with a -1, -01 (depending on the above described AutoNumLen) even if just one value is parsed.<br />
<br />
;get|set|reading[0-9]+JSON<br />
:defines a path to the JSON object wanted by concatenating the object names. See the above example.<br />
:If you don't know the paths, then start by using extractAllJSON and the use the names of the readings as values for the JSON attribute.<br><br />
:Please don't forget to also specify a name for a reading, get or set. <br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;(get|set|reading)[0-9]*RecombineExpr<br />
:defines an expression that is used in an eval to compute one reading value out of the list of matches.<br />
:This is supposed to be used for regexes or xpath specifications that produce multiple results if only one result that combines them is wanted. The list of matches will be in the variable @matchlist.<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;get[0-9]*CheckAllReadings<br />
:this attribute modifies the behavior of HTTPMOD when the HTTP Response of a get command is parsed. <br><br />
:If this attribute is set to 1, then additionally to the matching of the corresponding get specific regex (get[0-9]*Regex), XPath or JSON attribute also all the reading names and parse definitions defined in Reading[0-9]+Name and Reading[0-9]+Regex, XPath or JSON attributes are checked and if they match, the coresponding Readings are assigned as well.<br />
:Please note that this does not mean that get01CheckAllReadings will cause a get02Regex to be used. Only the corresponding get01Regex will be used but additionally all the readingXYRegex attributes.<br />
:This is automatically done if a get or set command is defined without its own parse attributes.<br />
<br />
;(get|reading)[0-9]*OExpr<br />
:defines an optional expression that is used in an eval to compute / format a readings value after parsing an HTTP response<br />
:The raw value from the parsing will be in the variable $val.<br />
:If specified as readingOExpr then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Expr.<br />
:Please note that the old syntax <b>readingsExpr.*</b> does not work with all features of HTTPMOD and should be avoided. It might go away in a future version of HTTPMOD.<br />
<br />
;(get|reading)[0-9]*Expr<br />
:This is the old syntax for (get|reading)[0-9]*OExpr. It should be replaced by (get|reading)[0-9]*OExpr. The set command upgradeAttributes which becomes visible when the attribute enableControlSet is set to 1, can do this renaming automatically.<br />
<br />
;(get|reading)[0-9]*OMap<br />
:Map that defines a mapping from raw value parsed to visible values like "0:mittig, 1:oberhalb, 2:unterhalb".<br />
:If specified as readingOMap then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Map.<br><br />
:The individual options in a map are separated by a komma and an optional space. Spaces are allowed to appear in a visible value however kommas are not possible.<br />
<br />
;(get|reading)[0-9]*Map<br />
:This is the old syntax for (get|reading)[0-9]*OMap. It should be replaced by (get|reading)[0-9]*OMap. The set command upgradeAttributes which becomes visible when the attribute enableControlSet is set to 1, can do this renaming automatically.<br />
<br />
;(get|set|reading)[0-9]*Format<br />
:Defines a format string that will be used in sprintf to format a reading value.<br />
:If specified without the numbers in the middle e.g. as readingFormat then the attribute value is a default for all other readings that don't specify an explicit reading[0-9]*Format.<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br><br />
<br />
;(get|set|reading)[0-9]*Decode<br />
:defines an encoding to be used in a call to the perl function decode to convert the raw data string read from the device to a reading. <br />
:This can be used if the device delivers strings in an encoding like cp850 instead of utf8.<br />
:If your reading values contain Umlauts and they are shown as strange looking icons then you probably need to use this feature.<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;(get|set|reading)[0-9]*Encode<br />
:defines an encoding to be used in a call to the perl function encode to convert the raw data string read from the device to a reading. <br />
:This can be used if the device delivers strings in an encoding like cp850 and after decoding it you want to reencode it to e.g. utf8.<br />
:If your reading values contain Umlauts and they are shown as strange looking icons then you probably need to use this feature.<br />
:Using this attribute for a set command only makes sense if you want to parse the HTTP response to the HTTP request that the set command sent by defining the attribute setXXParseResponse.<br />
<br />
;(get|set)[0-9]*URL<br />
:URL to be requested for the set or get command. If this option is missing, the URL specified during define will be used.<br />
<br />
;(get|set)[0-9]*Data<br />
:Data to be sent to the device as POST data when the get or set command is executed. if this attribute is not specified, an HTTP GET method will be used instead of an HTTP POST<br />
<br />
;(get|set)[0-9]*NoData<br />
:can be used to override a more generic attribute that specifies POST data for all get or set commands. With NoData no data is sent and therefor the request will be an HTTP GET.<br />
<br />
;(get|set)[0-9]*Header.*<br />
:HTTP Headers to be sent to the device when the set is executed<br />
<br />
;requestHeader.*<br />
:Define an optional additional HTTP Header to set in the HTTP request of the main loop<br />
<br />
;requestData<br />
:optional POST Data to be sent in the request of the main loop. If not defined, it will be an HTTP GET request as defined in HttpUtils which is used by this module<br />
<br />
;get[0-9]+Poll<br />
:if set to 1 the get is executed automatically during the normal update cycle (after the interval provided in the define command has elapsed)<br />
<br />
;get[0-9]+PollDelay<br />
:if the value should not be read in each iteration (after the interval given to the define command), then a minimum delay can be specified with this attribute. This has only an effect if the above Poll attribute has also been set. Every time the update function is called, it checks if since this get has been read the last time, the defined delay has elapsed. If not, then it is skipped this time.<br />
:PollDelay can be specified as seconds or as x[0-9]+ which means a multiple of the interval in the define command.<br />
<br />
;(get|set)[0-9]*TextArg<br />
:For a get command this defines that the command accepts a text value after the option name. By default a get command doesn't accept optional values after the command name. <br />
:If TextArg is specified and a value is passed after the get name then this value can then be used in a request URL, header or data as replacement for $val or in a user defined replacement that uses the internal "value" ($hash->{value}).<br />
:If used for a set command then it defines that the value to be set doesn't require any validation / conversion. <br />
:The raw value is passed on as text to the device. By default a set command expects a numerical value or a text value that is converted to a numeric value using a map.<br />
<br />
;set[0-9]+Min<br />
:Minimum value for input validation. <br />
<br />
;set[0-9]+Max<br />
:Maximum value for input validation. <br />
<br />
;set[0-9]+IExpr<br />
:Perl Expression to compute the raw value to be sent to the device from the input value passed to the set.<br />
<br />
;set[0-9]+Expr<br />
:This is the old syntax for (get|reading)[0-9]*IExpr. It should be replaced by (get|reading)[0-9]*IExpr. The set command upgradeAttributes which becomes visible when the attribute enableControlSet is set to 1, can do this renaming automatically.<br />
<br />
;set[0-9]+IMap<br />
:Map that defines a mapping from raw to input values like "0:mittig, 1:oberhalb, 2:unterhalb". This attribute atomatically creates a hint for FHEMWEB so the user can choose one of the input values.<br />
<br />
;set[0-9]+Map<br />
:This is the old syntax for (get|reading)[0-9]*IMap. It should be replaced by (get|reading)[0-9]*IMap. The set command upgradeAttributes which becomes visible when the attribute enableControlSet is set to 1, can do this renaming automatically.<br />
<br />
;set[0-9]+Hint<br />
:Explicit hint for fhemWEB that will be returned when set ? is seen. Can be used to get a slider or a list of values to choose from.<br />
<br />
;set[0-9]*NoArg<br />
:Defines that this set option doesn't require arguments. It allows sets like "on" or "off" without further values.<br />
<br />
;set[0-9]*ParseResponse<br />
:defines that the HTTP response to the set will be parsed as if it was the response to a get command.<br />
<br />
<br />
;(get|set)[0-9]*URLExpr<br />
:Defines a Perl expression to specify the HTTP Headers for this request. This overwrites any other header specification and should be used carefully only if needed. The original Header is availabe as $old. Typically this feature is not needed and it might go away in future versions of HTTPMOD. Please use the "replacement" attributes if you want to pass additional variable data to a web service. <br />
<br />
;(get|set)[0-9]*DatExpr<br />
:Defines a Perl expression to specify the HTTP Post data for this request. This overwrites any other post data specification and should be used carefully only if needed. The original Data is availabe as $old. Typically this feature is not needed and it might go away in future versions of HTTPMOD. Please use the "replacement" attributes if you want to pass additional variable data to a web service. <br />
<br />
;(get|set)[0-9]*HdrExpr<br />
:Defines a Perl expression to specify the URL for this request. This overwrites any other URL specification and should be used carefully only if needed. The original URL is availabe as $old. Typically this feature is not needed and it might go away in future versions of HTTPMOD. Please use the "replacement" attributes if you want to pass additional variable data to a web service. <br />
<br />
;ReAuthRegex<br />
:regular Expression to match an error page indicating that a session has expired and a new authentication for read access needs to be done. <br />
:This attribute only makes sense if you need a forms based authentication for reading data and if you specify a multi step login procedure based on the sid.. attributes.<br />
:This attribute is used for all requests. For set and get operations you can however specify individual reAuthRegexes with the (get|set)[0-9]*ReAuthRegex attributes.<br />
<br />
;(get|set)[0-9]*ReAuthRegex<br />
:Regex that will detect when a session has expired during a set operation and a new login needs to be performed.<br />
:It works like the global reAuthRegex but is used for set operations.<br />
<br />
;sid[0-9]*URL<br />
:different URLs or one common URL to be used for each step of an optional login procedure. <br />
<br />
;sid[0-9]*IDRegex<br />
:different Regexes per login procedure step or one common Regex for all steps to extract the session ID from the HTTP response<br />
<br />
;sid[0-9]*Data.*<br />
:data part for each step to be sent as POST data to the corresponding URL<br />
<br />
;sid[0-9]*Header.*<br />
:HTTP Headers to be sent to the URL for the corresponding step<br />
<br />
;sid[0-9]*IgnoreRedirects<br />
:Tells the HttpUtils to not follow HTTP Redirects for this Request. Might be needed for some devices that set a session cookie within a 303 Redirect.<br />
<br />
;clearSIdBeforeAuth<br />
:will set the session id to "" before doing the authentication steps<br />
<br />
;authRetries<br />
:number of retries for authentication procedure - defaults to 1<br />
<br />
;replacement[0-9]*Regex<br />
:Defines a replacement to be applied to an HTTP request header, data or URL before it is sent. This allows any part of the request to be modified based on a reading, an internal or an expression.<br />
:The regex defines which part of a header, data or URL should be replaced. The replacement is defined with the following attributes:<br />
<br />
;replacement[0-9]*Mode<br />
:Defines how the replacement should be done and what replacementValue means. Valid options are text, reading, internal and expression.<br />
<br />
;replacement[0-9]*Value<br />
:Defines the replacement. If the corresponding replacementMode is <code>text</code>, then value is a static text that is used as the replacement.<br />
:If replacementMode is <code>reading</code> then Value can be the name of a reading of this device or it can be a reading of a different device referred to by devicename:reading.<br />
:If replacementMode is <code>internal</code> the Value can be the name of an internal of this device or it can be an internal of a different device referred to by devicename:internal.<br />
:If replacementMode is <code>expression</code> the the Value is treated as a Perl expression that computes the replacement value. The expression can use $1, $2 and so on to refer to capture groups of the corresponding regex that is matched against the original URL, header or post data.<br />
:If replacementMode is <code>key</code> then the module will use a value from a key / value pair that is stored in an obfuscated form in the file system with the set storeKeyValue command. This might be useful for storing passwords.<br />
<br />
;[gs]et[0-9]*Replacement[0-9]*Value<br />
:This attribute can be used to override the replacement value for a specific get or set.<br />
<br />
;get|reading[0-9]*MaxAge<br />
:Defines how long a reading is valid before it is automatically overwritten with a replacement when the read function is called the next time.<br />
<br />
;get|reading[0-9]*MaxAgeReplacement<br />
:specifies the replacement for MaxAge - either as a static text or as a perl expression.<br />
<br />
;get|reading[0-9]*MaxAgeReplacementMode<br />
:specifies how the replacement is interpreted: can be text, expression and delete.<br />
<br />
;get|reading[0-9]*DeleteIfUnmatched<br />
:If set to 1 this attribute causes certain readings to be deleted when the parsing of the website does not match the specified reading. Internally HTTPMOD remembers which kind of operation created a reading (update, Get01, Get02 and so on). Specified readings will only be deleted if the same operation does not parse this reading again. This is especially useful for parsing that creates several matches / readings and the number of matches can vary from request to request. For example if reading01Regex creates 4 readings in one update cycle and in the next cycle it only matches two times then the readings containing the remaining values from the last round will be deleted.<br />
:Please note that this mechanism will not work in all cases after a restart. Especially when a get definition does not contain its own parsing definition but ExtractAllJSON or relies on HTTPMOD to use all defined reading.* attributes to parse the responsee to a get command, old readings might not be deleted after a restart of fhem.<br />
;get|reading[0-9]*DeleteOnError<br />
:If set to 1 this attribute causes certain readings to be deleted when the website can not be reached and the HTTP request returns an error. Internally HTTPMOD remembers which kind of operation created a reading (update, Get01, Get02 and so on). Specified readings will only be deleted if the same operation returns an error.<br />
The same restrictions as for DeleteIfUnmatched apply regarding a fhem restart.<br />
<br />
<br />
;httpVersion<br />
:defines the HTTP-Version to be sent to the server. This defaults to 1.0.<br />
<br />
;sslVersion<br />
:defines the SSL Version for the negotiation with the server. The attribute is evaluated by HttpUtils. If it is not specified, HttpUtils assumes SSLv23:!SSLv3:!SSLv2<br />
<br />
;sslArgs<br />
:defines a list that is converted to a key / value hash and gets passed to HttpUtils. To avoid certificate validation for broken servers you can for example specify <br />
:<code>attr myDevice sslArgs SSL_verify_mode,SSL_VERIFY_NONE</code><br />
<br />
;alignTime<br />
:Aligns each periodic read request for the defined interval to this base time. This is typcally something like 00:00 (see the FHEM at command)<br />
<br />
;noShutdown<br />
:pass the noshutdown flag to HTTPUtils for webservers that need it (some embedded webservers only deliver empty pages otherwise)<br />
<br />
;disable<br />
:stop doing automatic HTTP requests while this attribute is set to 1<br />
<br />
;enableControlSet<br />
:enables the built in set commands interval, stop, start, reread, upgradeAttributes, storeKeyValue.<br />
<br />
;enableCookies<br />
:enables the built in cookie handling if set to 1. With cookie handling each HTTPMOD device will remember cookies that the server sets and send them back to the server in the following requests. <br />
:This simplifies session magamenet in cases where the server uses a session ID in a cookie. In such cases enabling cookies should be sufficient and no sidRegex and no manual definition of a cookie header should be necessary.<br />
<br />
;showMatched<br />
:if set to 1 then HTTPMOD will create a reading with the name MATCHED_READINGS that contains the names of all readings that could be matched in the last request as well as UNMATCHED_READINGS and LAST_REQUEST.<br />
<br />
;showError<br />
:if set to 1 then HTTPMOD will create a reading and event with the Name LAST_ERROR that contains the error message of the last error returned from HttpUtils. <br />
<br />
;removeBuf<br />
:if set to 1 then HTTPMOD removes the internal named buf when a HTTP-response has been received. <br />
:$hash->{buf} is used internally be Fhem httpUtils and in some use cases it is desireable to remove this internal after reception <br />
:because it contains a very long response which looks ugly in Fhemweb.<br />
<br />
;timeout<br />
:time in seconds to wait for an answer. Default value is 2<br />
<br />
;queueDelay<br />
:HTTP Requests will be sent from a queue in order to avoid blocking when several Requests have to be sent in sequence. This attribute defines the delay between calls to the function that handles the send queue. It defaults to one second.<br />
<br />
;queueMax<br />
:Defines the maximum size of the send queue. If it is reached then further HTTP Requests will be dropped and not be added to the queue<br />
<br />
;minSendDelay<br />
:Defines the minimum time between two HTTP Requests.<br />
<br />
== Links ==<br />
* Beispiel: [[Wetter_und_Wettervorhersagen#Wetter_von_Weather_Underground|Wetter von WeatherUnderground auslesen]]<br />
* Beispiel: [[Pollenflug]]<br />
* Beispiel: [[HTTPMOD Beispielkonfiguration zur Anbindung einer Daikin Klimaanlage mit WLAN-Modul]]<br />
* {{Link2Forum|Topic=17804|LinkText=Thread}} in FHEM Forum that discusses the first version of this module <br />
* {{Link2Forum|Topic=29471|LinkText=Thread}} in FHEM Forum that discusses the second major version of this module <br />
* {{Link2Forum|Topic=45176|LinkText=Thread}} in FHEM Forum that discusses the third major version of this module <br />
* [http://perldoc.perl.org/perlretut.html Introduction to regular expressions]<br />
* [http://portswigger.net/burp/ BurpSuite]: Tool (local proxy) to help analyze http traffic<br />
<br />
[[Kategorie:IP Components]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=Alexa-Fhem&diff=22505Alexa-Fhem2017-09-06T16:24:46Z<p>Amenomade: /* Alexa-Fhem als Service (systemd) installieren */</p>
<hr />
<div>'''Alexa-Fhem''' ist eine in JavaScript geschriebene und auf NodeJS basierende Software, welche es ermöglicht, der digitalen Amazon Assistentin Alexa zusätzliche Skills für die Heimautomatisierung via FHEM beizubringen. Eine erste funktionierende Version wurde von [https://forum.fhem.de/index.php?action=profile;u=430 justme1968] im {{Link2Forum|Topic=60244|LinkText=Forum}} veröffentlicht.<br />
Das ist eine erste Version der Dokumentation zur Installation und Einrichtung, eine Erweiterung wird sicherlich in nächster Zeit noch folgen.<br />
{{Infobox Modul<br />
|ModPurpose=Anbindung von FHEM an Amazon Assistent Alexa<br />
|ModType=x<br />
|ModTechName=<br />
|ModForumArea=Frontends/Sprachsteuerung<br />
|ModOwner=justme1968<br />
}} <br />
<br />
<br />
==Einführung==<br />
===Glossar===<br />
*Echo bzw. Echo Dot (im Folgenden maskulin bezeichnet) sind die derzeit verfügbaren Geräte des Alexa-Systems '''BILDER EINSTELLEN - Achtung Urheberrecht'''<br />
*AVS ist der Amazon Voice Service, d.h. die Spracherkennungskomponente des Systems.{{Randnotiz|RNTyp=r|RNText=Für die Nutzung der Amazon AWS-Dienste müssen zwingend die Daten einer Kreditkarte angegeben werden. Nach gegenwärtigem Kenntnisstand sollen jedoch keine Kosten für die Nutzung der im Rahmen dieses How To beschriebenen Dienste anfallen, sofern diese in einem Rahmen genutzt werden, der selbst eine intensive private Nutzung nicht überschreitet. Der Benutzer sei an dieser Stelle auf die von Amazon veröffentlichten Preislisten verwiesen. Die Autoren dieser Anleitung und der darin beschriebenen Module übernehmen keine Haftung für eventuelle Kosten, die aus der Nutzung der AWS entstehen. }}<br />
*AWS sind die Amazon Web Services, also per URL erreichbare Dienste zur Ausführung von Berechnungen etc. Im Rahmen von Alexa-Fhem wird bei AWS eine eigene JavaScript-Funktion hinterlegt, die zur Kommunikation mit dem FHEM-Server dient. Im Jargon von Amazon ist dies eine so genannte Lambda-Funktion '''WARUM ? Nachlesen bei Amazon'''.<br />
*Card bezeichnet einen Eintrag in der Alexa-App, der die erkannte Sprachnachricht sowie weiter gehenden Informationen über die Reaktion von Alexa enzthält und Rückmeldung an Amazon erlaubt.<br />
*Skill (engl. für Fähigkeit) ist die Bezeichnung für eine per Spracherkennung bediente Funktionalität des Alexa-Systems, z.B. zur Nachrichtenansage, zur Wettervorhersage oder zur Steuerung von FHEM<br />
<br />
===Arbeitsweise und Datenfluss===<br />
[[Datei:2gpXyLN.jpg|200px|thumb|right|Grafische Darstellung der beteiligten Komponenten]]<br />
Echo -> AVS -> AWS Lambda -> alexa-fhem -> AWS Lambda -> AVS -> Echo<br />
<br />
*Der Echo (oder ein anderes Alexa/AVS fähiges Gerät) nimmt Audiodaten auf und schickt diese an AVS (Amazon Voice Service) zur Erkennung<br />
*AVS führt die Spracherkennung durch und erzeugt ein Event mit Informationen zu den erkannten Daten<br />
:*Beim Alexa SmartHome Skill sind die möglichen Sätze für die Spracherkennung relativ fest vorgegeben <br />
:*Beim Alexa Custom Skill kommen die dazu nötigen Informationen aus dem ''Interaction Model'' der Alexa Skills Configuration<br />
*Das Event wird an den unter ''Configuration'' in der Alexa Skills Configuration hinterlegten Endpoint geschickt<br />
:*Beim Alexa SmartHome Skill ist das zwingend eine AWS Lambda Routine<br />
:*Beim Alexa Custom Skill kann das im Prinzip auch ein eigener Web Service sein<br />
*Das Event wird vom <code>lambda.js</code> code an alexa-fhem weitergeleitet<br />
*alexa-fhem steuert FHEM und sendet ein Antwort-Event zurück<br />
*<code>lambda.js</code> nimmt diese Antwort entgegen und gibt sie an AVS zurück<br />
*AVS sogt dafür das der Echo 'antwortet' und dass die Card in der Alexa App erscheint<br />
<br />
===Anmerkungen===<br />
*Ein Skill hat keinen Zugriff auf die Audiodaten<br />
*Mit dem Skill API kann ein Skill zu zu keiner Zeit von sich aus aktiv werden und 'einfach' Daten an den Echo schicken oder ihn dazu bringen irgendetwas zu tun.<br />
*Wenn man berücksichtigt welchen Weg die Daten insgesamt gehen, ist es erstaunlich, wie schnell die Reaktion auf einen gesprochenen Satz erfolgt.<br />
<br />
=== Abgrenzung des '''Alexa Smart Home Skills''' und des '''Alexa Custom Skills''' ===<br />
<br />
Der [[Alexa-Fhem#Smart_Home|Alexa Smart Home Skill]] ist ein Amazon-Alexa-Standard-Skill, der wesentliche Basisfunktionalitäten bereitstellt. Zu diesen gehört im Wesentlichen die Funktionalität, durch Alexa-FHEM bereitgestellte Devices im Alexa-Account des Benutzers anzulegen. Der Alexa Smart Home Skill reagiert auf gesprochene Interaktion in einem beschränkten Umfang. Beispielsweise genügt ein "Alexa, schalte die Wohnzimmerlampe an" um eine Interaktion zwischen Alexa Smart Home Skill und FHEM-Alexa auszulösen. Nach erfolgreicher Einrichtung wird dieser Skill in der Alexa-App bzw. im Web in der Rubrik "Smart Home" als Skill angezeigt.<br />
<br />
Der [[Alexa-Fhem#Custom|Alexa Custom Skill]] ist kein Standard-Smart-Home-Skill, sondern ein individuell entwickelter Skill, so wie alle anderen Skills auch. Er wird daher auch nicht in der Alexa-App unter der Rubrik "Smart Home" angezeigt. Gesprochene Interaktion mit diesem Skill erfolgt dadurch, dass entweder der Skill explizit gestartet wird (z.B. "Alexa, starte [Name des Skills]") oder direkt angesprochen wird (z.B. "Alexa, frage [Name des Skills] wie ist der Status von [Device] "). Der Alexa Custom Skill befindet sich in Entwicklung und wird hinsichtlich seiner Funktionalitäten laufend weiterentwickelt. Die Einrichtung dieses Skills ist grundsätzlich optional, jedoch werden anspruchsvollere Steuerungsmöglichkeiten nur mit diesem realisiert werden können.<br />
<br />
==Installation==<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Da die einzelnen Schritte der Anleitung an verschiedenen Stellen unterbrochen und später fortgesetzt werden müssen, empfiehlt es sich, die Anleitung einmal vollständig gelesen zu haben. Während der Konfiguration sollten alle nachfolgenden Abschnitte parallel in gleichzeitig geöffneten Browserfenstern durchgeführt werden, die jeweils bis zum Abschluss geöffnet bleiben müssen. }}<br />
Grundvoraussetzung für alle folgenden Schritte ist das Vorhandensein eines Amazon-Accounts. Es wird davon ausgegangen, dass die Konten für alle im Folgenden genutzten Amazon-Dienste eingerichtet wurden.<br />
<br />
===node.js installieren===<br />
Zunächst wird das Betriebssystem (in diesem Falle Debian oder Ubuntu) auf den aktuellen Stand gebracht:<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
sudo apt-get update<br />
sudo apt-get upgrade<br />
sudo apt-get install build-essential libssl-dev</syntaxhighlight><br />
<br />
Nun muss NodeJS installiert werden. Leider ist die Version im Debian Repository deutlich zu alt, daher wird mit den folgenden Befehlen das Node Repository hinzugefügt und NodeJS (in der LTS Version) entsprechend installiert:<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -<br />
sudo apt-get install -y nodejs<br />
</syntaxhighlight><br />
<br />
=== Alexa-Fhem installieren ===<br />
'''Aus gegebenem Anlass: Dies ist weder eine Einführung in Linux, noch eine Anfängerdokumentation für FHEM.''' Also erst die Grundlagen lernen, und dann mit Alexa beginnen !<br />
<br />
Die aktuelle Version ist jeweils {{Link2Forum|Topic=60244|Message=540117|LinkText=hier}} zu finden.<br />
<br />
====Erstinstallation====<br />
Hier wird die Erstinstallation von Alexa-Fhem beschrieben.<br />
===== Linux =====<br />
# Die tgz-Datei unter Linux im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) entpacken (''nicht'' unter Windows, das zerstört die Rechteeinstellungen).<syntaxhighlight lang="bash" style="width:50%;">tar -xvzf dateiname.tgz</syntaxhighlight><br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen <syntaxhighlight lang="bash" style="width:50%;">mv package alexa-fhem</syntaxhighlight><br />
# Durch <syntaxhighlight lang="bash" style="width:50%;">cd alexa-fhem</syntaxhighlight> in das Verzeichnis wechseln<br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren (kein sudo!).<br />
# SSL Zertifikat erzeugen durch Aufruf von <syntaxhighlight lang="bash" style="width:50%;">./createKey.sh</syntaxhighlight> (kein sudo!). Hierbei beachten, dass ein Kennwort vergeben werden muss, das mindestens aus 4 Zeichen besteht, dieses Kennwort bitte merken.<br />
# Das Verzeichnis ''.alexa'' anlegen, ''und zwar im Home-Verzeichnis desjenigen Benutzers, unter dem Alexa-Fhem laufen soll.'' Insbesondere ist zu beachten, dass dieser Nutzer u.U. im Startskript explizit gesetzt wird. Mit dem untenstehenden Skript ist das ''nicht'' der User fhem, sondern der User ''pi''. Das Symbol ''~/'' verweist auf das Home-Verzeichnis des Benutzers, der gerade die Installation vornimmt.<br />
# Die Datei ''config-sample.json'' nach ''.alexa/config.json'' kopieren. Achtung: Installiert man alexa-fhem als root-user, zeigt das Symbol ''~/'' auf ''/root'' - und die Konfigurationsdatei wird ggf. bei einem manuellen Start von Alexa-Fhem nicht gefunden.<br />
# Achtung: Ggf. müssen auch die Dateien key.pem und cert.pem ins entsprechende Verzeichnis kopiert werden.<br />
===== Windows =====<br />
''Vor'' der Installation von Alexa-Fhem muss man folgende Anwendungen installieren:<br />
* Node.js (die aktuelle Version findet man unter https://nodejs.org/en/download/)<br />
* OpenSSL (http://slproweb.com/products/Win32OpenSSL.html oder https://www.heise.de/download/product/win32-openssl-47316/download)<br />
Erst dann fängt man mit Alexa-Fhem an.<br />
<br />
<br />
# Die tgz-Datei im Hauptverzeichnis von FHEM (z.B. <code>С:\Program Files (x86)\fhem</code>) entpacken.<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen<br />
# Windows-Shell (Kommandozeile, Eingabeaufforderung usw.) öffnen. "Start" -> "Ausführen" (oder [Windows-Taste]+[R]) -> cmd -> Ok. Durch <syntaxhighlight lang="bash" style="width:50%;">cd "<FHEM-Hauptverzeichis>\alexa-fhem"</syntaxhighlight> in das Verzeichnis wechseln. <br/>Dabei ist natürlich das <FHEM-Hauptverzeichis> durch den entsprechenden Pfad aus dem Schritt 1 zu ersetzen. Im o.g. Beispiel wäre es <code>cd "С:\Program Files (x86)\fhem\alexa-fhem"</code><br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren.<br/> Bei der Fehlermeldung wie "Der Befehl "npm" ist entweder falsch geschrieben oder konnte nicht gefunden werden." ist die Installation von Node.js zu überprüfen.<br />
# SSL Zertifikat erzeugen. Dafür muss man alle Befehle aus dem Skript ''createKey.sh'' nacheinander manuell ausführen. Hierbei beachten, dass ein Kennwort vergeben werden muss, das mindestens aus 4 Zeichen besteht, dieses Kennwort bitte merken. Der Windows-Welt unbekannter Befehl <code>mv</code> ist durch <code>move /y</code> zu ersetzen:<syntaxhighlight lang="bash" style="width:50%;">openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;">openssl rsa -in key.pem -out newkey.pem</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;">move /y newkey.pem key.pem</syntaxhighlight> Eventuelle Fehlermeldung "can't open config file: /usr/local/ssl/openssl.cnf" o.Ä. lässt sich durch Befehl <code>set OPENSSL_CONF=<OpenSSL-Verzeichnis>\bin\openssl.cfg</code> beheben, wobei <OpenSSL-Verzeichnis> durch den entsprechenden Installationspfad (typischerweise <code>c:\OpenSSL-Win32</code>) zu ersetzen ist.<br />
# Das Verzeichnis ''.alexa'' anlegen, ''und zwar im Benutzerverzeichnis desjenigen Benutzers, unter dem Alexa-Fhem laufen soll.'' In aktuellen Versionen von Windows (ab Windows 7 bzw. ab Windows Server 2008 R2) liegt das Verzeichnis unter <code>C:\Users\<Benutzername></code>, also z.B. für Benutzer "Administrator" - unter <code>C:\Users\Administrator</code>.<br/>Falls Windows sich weigert das Verzichniss mit dem Punkt am Anfang zu erstellen, kann man das aus der Kommandozeile machen:<syntaxhighlight lang="bash" style="width:50%;">cd "C:\Users\<Benutzername>"</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;"><br />
mkdir ".alexa"</syntaxhighlight><br />
# Die Datei ''config-sample.json'' nach ''C:\Users\<Benutzername>\.alexa\config.json'' kopieren.<br />
# Achtung: Ggf. müssen auch die Dateien key.pem und cert.pem ins entsprechende Verzeichnis (<code>"<FHEM-Hauptverzeichis>\alexa-fhem\bin</code>) kopiert werden.<br />
<br />
====Update====<br />
Hier wir das Update auf eine neue Version von Alexa-Fhem beschrieben<br />
===== Linux =====<br />
# Das Verzeichnis ''alexa-fhem'' im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) umbenennen in ''alexa-fhem.old''.<br />
# Die tgz-Datei der neuen Alexa-Fhem-Version unter Linux im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) entpacken (''nicht'' unter Windows, das zerstört die Rechteeinstellungen).<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen, in das Verzeichnis wechseln<br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren (kein sudo!).<br />
# Die Zertifikatsdateien key.pem und cert.pem aus dem alten Verzeichnis ''alexa-fhem.old'' ins neue Verzeichnis ''alexa-fhem'' kopieren.<br />
Natürlich dann den Dienst neu starten, auch müssen selbstredend irgendwelche Modifikationen an der Datei server.js in der neuen Version nachgezogen werden. Wenn alles läuft, kann das alte Verzeichnis ''alexa-fhem.old'' gelöscht werden.<br />
===== Windows =====<br />
# Das Verzeichnis ''alexa-fhem'' im Hauptverzeichnis von FHEM (z.B. <code>С:\Program Files (x86)\fhem</code>) umbenennen in ''alexa-fhem.old''.<br />
# Die tgz-Datei der neuen Alexa-Fhem-Version im Hauptverzeichnis von FHEM entpacken.<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen<br />
# Windows-Shell (Kommandozeile, Eingabeaufforderung usw.) öffnen. "Start" -> "Ausführen" (oder [Windows-Taste]+[R]) -> cmd -> Ok. Durch <syntaxhighlight lang="bash" style="width:50%;">cd "<FHEM-Hauptverzeichis>\alexa-fhem"</syntaxhighlight> in das Verzeichnis wechseln. <br/>Dabei ist natürlich das <FHEM-Hauptverzeichis> durch den entsprechenden Pfad aus dem Schritt 1 zu ersetzen. Im o.g. Beispiel wäre es <code>cd "С:\Program Files (x86)\fhem\alexa-fhem"</code><br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren.<br />
# Die Zertifikatsdateien key.pem und cert.pem aus dem alten Verzeichnis ''alexa-fhem.old'' ins neue Verzeichnis ''alexa-fhem'' kopieren.<br />
Natürlich dann den Dienst neu starten, auch müssen selbstredend irgendwelche Modifikationen an der Datei server.js in der neuen Version nachgezogen werden. Wenn alles läuft, kann das alte Verzeichnis ''alexa-fhem.old'' gelöscht werden.<br />
<br />
==== Alexa-Fhem konfigurieren ====<br />
Der Inhalt der Datei ''~/.alexa/config.json'' muss an die eigene Umgebung angepasst werden. <br />
# ''nat-pmp'' -> wenn nat-pmp verwendet werden soll: die ip des eigenen routers,<br />
# ''nat-upnp'' -> wenn nat-upnp verwendet werden soll: ''true'',<br />
# ''applicationId'' <br />
#:* Wenn man nur den SmartHome-Skill verwenden möchte, kann dieser Eintrag leer bleiben.<br />
#:* Ansonsten ist er mit der SkillID des Alexa Custom Skills zu belegen, siehe Abschnitt [[#Skill_Id_bestimmen | Skill Id bestimmen]]<br />
# ''oauthClientID'' -> ''Client ID'' dem Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
# ''server'' -> IP-Adresse des eigenen FHEM-Servers<br />
# ''port'' -> Portnummer des eigenen FHEM-Servers<br />
Beispiel:<br />
{<br />
"alexa": {<br />
"name": "Alexa TEST",<br />
"keyFile": "./key.pem",<br />
"certFile": "./cert.pem",<br />
"applicationId": "amzn1.ask.skill.xxxxxxxxxxxxxxxxxxxxxxxxxxxx",<br />
"oauthClientID": "amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"<br />
},<br />
"connections": [<br />
{<br />
"name": "FHEM",<br />
"server": "192.168.0.xxx.xxx",<br />
"port": "8083",<br />
"filter": "room=AlexaRoom"<br />
}<br />
]<br />
}<br />
<br />
Mehrere Custom Skills lassen sich mit der folgenden Syntax eintragen<br />
"applicationId": [ "amzn1.ask.skill.1" , "amzn1.ask.skill.2" ],<br />
"oauthClientID": [ "amzn1.application-oa2-client.1" , "amzn1.application-oa2-client.1" ]<br />
<br />
Danach durch Aufruf von <syntaxhighlight lang="bash" style="width:50%;">./bin/alexa</syntaxhighlight> den Dienst starten (kein sudo!)<br />
<br />
<br />
Unter Windows startet man Alexa-Dienst durch <syntaxhighlight lang="bash" style="width:50%;">node alexa</syntaxhighlight> aus der <code>alex-fhem/bin</code> (also erst z.B. durch <code>cd "<FHEM-Hauptverzeichis>\alexa-fhem\bin"</code> ins richtige Verzeichnis kommen)<br />
<br />
Der Start des Alexa-Dienstes auf der Console ist immer dann zu empfehlen, wenn man auf die Ausgaben des Dienstes angewiesen ist und beispielsweise sehen möchte, welche Devices durch den Dienst bereitgestellt werden oder ob Fehler auftreten. Beendet man die Console-Session wird auch der Dienst wieder beendet. Insofern ist die vorgenannte Vorgehensweise nur für ein Debugging zu empfehlen und nicht im Regelbetrieb. Nachfolgend ist beschrieben, wie man den Alexa-Dienst aus FHEM heraus starten / stoppen und neu starten kann.<br />
<br />
==== Alexa-Fhem aus FHEM heraus starten ====<br />
Zunächst das Start-up-Skript aus diesem Post herunterladen {{Link2Forum|Topic=60244|Message=517271|LinkText=https://forum.fhem.de/index.php/topic,60244.msg517271.html#msg517271}} und unter /etc/init.d/alexa speichern.<br />
<br />
Das Script geht davon aus, das der alexa-fhem script unter /opt/fhem/alexa-fhem liegt, und die logfiles später unter /opt/fhem/log. Sollte das nicht der Fall sein, muss das Skript angepasst werden.<br />
<br />
Nun folgende Kommandos ausführen:<br />
<syntaxhighlight lang="bash" style="width:50%;">sudo chmod 755 /etc/init.d/alexa<br />
sudo update-rc.d alexa defaults</syntaxhighlight><br />
<br />
In der Datei <code>/etc/sudoers</code> den User fhem für die Nutzung von sudo zulassen (<code>sudo nano /etc/sudoers</code>), z.B. durch Anfügen der nachfolgenden Zeile:<br />
<code>fhem ALL=(ALL) NOPASSWD: ALL</code><br />
<br />
Nun folgende Devices anlegen (ggf. einem Raum zuordnen, z.B. AlexaControl):<br />
<syntaxhighlight lang="bash" style="width:75%;">define FHEM.Alexa.Status dummy<br />
<br />
define FHEM.Alexa dummy<br />
attr FHEM.Alexa event-on-change-reading state<br />
attr FHEM.Alexa webCmd status:start:stop:restart<br />
<br />
define FHEM.Alexa.DOIF DOIF ([FHEM.Alexa] eq "start") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa start > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "stop")<br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa stop > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "restart") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa restart > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "status") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa status > /dev/null 2>&1 &")})</syntaxhighlight><br />
<br />
==== Alexa-Fhem als Service (systemd) installieren ====<br />
Auf neueren Installationen (z.B. RPi Jessie) wird init.d durch systemd ersetzt. Folgend die Anleitung um alexa-fhem als Service zu installieren auf einem Raspberry Pi mit Jessie.<br />
<br />
Zunächst einen neuen Benutzer anlegen unter dem alexa-fhem laufen soll, falls man nicht möchtet dass alexa-fhem z.B. mit dem fhem User ausgeführt wird:<br />
<br />
<code lang="bash" style="width:75%;"><br />
sudo useradd -M --system alexa<br />
</code><br />
<br />
Eigentlich braucht der Benutzer keine Gruppen, aber man kann den Benutzer auch der Gruppe <code>dialout</code> hinzufügen (<code>sudo usermod -a -G dialout alexa</code>)<br />
<br />
Datei "alexa.service" unter <code>/etc/systemd/system</code> anlegen:<br />
<br />
[Unit]<br />
Description=Node.js Alexa Server <br />
After=syslog.target network-online.target<br />
<br />
[Service]<br />
Type=simple<br />
User=alexa <br />
WorkingDirectory=/opt/alexa/alexa-fhem<br />
ExecStart=/opt/fhem/alexa-fhem/bin/alexa -U /home/alexa/.alexa<br />
Restart=on-failure<br />
RestartSec=10<br />
KillMode=process<br />
<br />
[Install]<br />
WantedBy=multi-user.target <br />
<br />
Den Pfad <code>/home/alexa/.alexa</code> an die Systemgegebenheiten anpassen. Letztendlich kann die config.json irgendwo liegen, hauptsache alexa-fhem weiß wo. <br />
<br />
Im WorkingDirectory wird der alexa Dienst die Zertifikate suchen.<br />
<br />
Achtung: Natürlich muss der Benutzer auch Zugriff sowohl auf das Verzeichnis mit der config als auch das alexa-fhem Verzeichnis und das WorkingDirectory haben.<br />
<br />
Um den Service zu aktiveren und zu starten helfen folgende Befehle:<br />
sudo systemctl daemon-reload<br />
sudo systemctl enable alexa<br />
sudo systemctl start alexa<br />
<br />
Status abfragen mit<br />
sudo systemctl status alexa<br />
<br />
Log einsehen?<br />
sudo journalctl -u alexa<br />
<br />
(mit <code>-f</code> kann man den follow Modus aktivieren, wie <code>tail -f</code>).<br />
Bei einen reboot startet alexa-fhem jetzt automatisch.<br />
<br />
==== Alexa-Fhem testen ====<br />
Node.Js stellt einen Web-Server am Port 3000 bereit, das oben erzeugte Zertifikat sichert diesen Zugang per SSL ab. Durch Aufruf der Adresse<br />
<code>https://<IP-Adresse des Servers>:3000</code> kann man testen, ob der Alexa-Fhem Service läuft - der Seitenaufruf liefert eine Zeile JSON-Code, beginnend mit<br />
<code>{"header":{"name":"UnsupportedOperationError"...</code><br />
<br />
=== Alexa Device anlegen ===<br />
Das Modul 39_alexa.pm stellt innerhalb von FHEM verschiedene Attribute z.B. alexaName oder alexaRoom zur Verfügung. Manche dieser Attribute (wie z.b. alexaName) werden in beiden Skills verwendet, andere werden ausschließlich bei einer Nutzung des Alexa Custom Skill verwendet.<br />
<br />
Die Einrichtung des Alexa Device geschieht durch die nachfolgende Definition:<br />
<syntaxhighlight lang="bash" style="width:70%;">define MyAlexa alexa</syntaxhighlight><br />
<br />
<hr><br />
<br />
=== Alexa Skills ===<br />
Für folgende Schritte muss man unter der Adresse http://developer.amazon.com angemeldet sein<br />
# Anmeldung auswählen<br />[[Datei:Developer.amazon.com-01-login2.png|200px]]<br />
# Anmeldedaten eingeben<br />[[Datei:Developer.amazon.com-02-userpass2.png|200px]]<br />
<br />
==== Security Profile anlegen ====<br />
Die Erzeugung eines Sicherheitsprofils muss nur einmal erfolgen, es wird dann für alle weiteren Skills verwendet.<br />
# Nach der Anmeldung Auswahl von ''APPS & SERVICES''<br />[[Datei:Developer.amazon.com-03-apps_and_services.png|200px]]<br />
# Anschließend auswählen ''Security Profiles''<br />[[Datei:Developer.amazon.com-05-apps_and_services_-_security_profiles.png|200px]]<br />
# Auswählen ''Create a New Security Profile'' aus<br />[[Datei:Developer.amazon.com-06-apps_and_services_-_create_a_new_security_profile.png|200px]]<br />
# Dann einen Namen und eine Beschreibung für das Profil eingeben und mit ''Save'' bestätigen<br />[[Datei:Developer.amazon.com-07-apps_and_services_-_security_profile_management.png|200px]]<br />
<br />
===== Login with Amazon =====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Hier wird beschrieben, wo ''Client Id'' und ''Client Secret'' zu finden sind}}<br />
# Oben rechts auf ''Login with Amazon'' klicken.<br/>[[Datei:Developer.amazon.com-08-login_with_amazon.png|200px]]<br />
# Auf der neu geladenen Seite auswählen ''Sign up''<br/>[[Datei:Developer.amazon.com-09-login_with_amazon_-_sign_up.png|200px]]<br />
# Anschließend im Dropdown Menü das vorher angelegte Profil auswählen und mit ''Confirm'' bestätigen<br/>[[Datei:Developer.amazon.com-10-login_with_amazon_-_create_new_profile.png|200px]] [[Datei:Developer.amazon.com-11-login_with_amazon_-_create_new_profile2.png|200px]]<br />
# Im folgenden Fenster die Adresse [https://www.amazon.com/gp/help/customer/display.html?nodeId=468496 https://www.amazon.com/gp/help/customer/display.html?nodeId=468496] eingeben und mit ''Save'' bestätigen. '''Todo Erklärungsbedarf: WARUM diese Adresse'''<br/>[[Datei:Developer.amazon.com-12-login_with_amazon_-_enter_consent_screen_information.png|200px]]<br />
# Anschließend bei dem neu angelegten Eintrag auf der rechten Seite auf das Zahnrad klicken und ''Web Settings'' auswählen<br/>[[Datei:Developer.amazon.com-13-login_with_amazon_-_web_settings.png|200px]]<br />
# Im neu geladenen Fenster anklicken von ''Edit''<br/>[[Datei:Developer.amazon.com-14-login_with_amazon_-_edit.png|200px]]<br />
# Anschließend bei ''Allowed Return URLs'' die folgenden drei Adressen eingeben. ''xxx'' muss hierbei durch den Wert ersetzt werden, der in den beiden Abschnitten [[#SmartHome_Skill_anlegen | SmartHome Skill anlegen]] bzw. [[#Custom_Skill_anlegen | Custom Skill anlegen]] jeweils unter Punkt 4 (Seite ''Configuration'') bei ''Redirect Urls'' am Ende der URLs angezeigt wird<br />
## [https://layla.amazon.co.uk/api/skill/link/xxx https://layla.amazon.co.uk/api/skill/link/xxx]<br />
## [https://pitangui.amazon.com/api/skill/link/xxx https://pitangui.amazon.com/api/skill/link/xxx]<br />
## [https://layla.amazon.com/api/skill/link/xxx https://layla.amazon.com/api/skill/link/xxx]<br />
.<br/>[[Datei:Developer.amazon.com-15-login_with_amazon_-_allowed_return_urls.png|200px]]<br />
<br />
==== Skills bearbeiten ====<br />
# Im Menü den Punkt ''ALEXA'' auswählen<br />[[Datei:Developer.amazon.com-03-apps_and_services.png|200px]]<br />
# Anschließend im Feld ''Alexa Skills Kit'' auf ''Get started'' klicken<br />[[Datei:Developer.amazon.com-17-alexa_-_alex_skills_kit_-_get_started.png|200px]]<br />
<br />
===== SmartHome Skill anlegen =====<br />
# Oben rechts ''Add a New Skill'' auswählen<br />[[Datei:Developer.amazon.com-18-alexa_-_alex_skills_kit_-_add_a_new_skill.png|200px]]<br />
# Auf der folgenden Seite eingeben und dann mit ''Next'' bestätigen:<br />
#:* ''Skill Type'' -> ''SmartHome Skill API'' <br />
#:* ''Language'' -> ''German''<br />
#:* ''Name'' -> beliebiger Name, z.B. "MySmartHome Basic")<br />
#:* ''Payload Version'' -> ''v2 (other devices)'' <br/>[[Datei:Developer.amazon.com-19-alexa_-_alex_skills_kit_-_skill_information.png|200px]]<br />
# Die folgende Seite einfach mit ''Next'' überspringen<br />[[Datei:Developer.amazon.com-20-alexa_-_alex_skills_kit_-_interaction_model.png|200px]]<br />
# Auf der Seite ''Configuration'' Folgendes eingeben:<br />
#:* ''Service Endpoint Type'' -> ''AWS Lambda'' ist vorausgewählt und kann nicht geändert werden.<br />
#:* ''Geographical Region'' -> ''Europe'' auswählen und im Textfeld die ARN aus Abschnitt [[#ARN_der_AWS_Lambda_Funktion_bestimmen | AWS Lambda Funktion]] eintragen. <br />
#:* ''Authorization URL'' -> <code>https://www.amazon.com/ap/oa</code><br />
#:* ''Client ID'' -> ''Client ID'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
#:* ''Scope'' -> <code>profile:user_id</code> (wörtlich 1:1 eintragen)<br />
#:* ''Redirect URLs'' - sollten vorbelegt sein<br />
#:* ''Authorization Grant Type'' -> ''Auth Code Grant'' auswählen<br />
#:* ''Access Token URI'' -> <code>https://api.amazon.com/auth/o2/token</code><br />
#:* ''Client Secret'' -> ''Client Secret'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
#:* ''Client Authentication Scheme'' -> ''HTTP Basic''<br />
#:* ''Privacy Policy URL'' -> <code>https://www.amazon.com/gp/help/customer/display.html?nodeId=468496</code><br /><br /><br />
<br />[[Datei:Developer.amazon.com-21-alexa_-_alex_skills_kit_-_configuration.png|200px]] [[Datei:Developer.amazon.com-22-alexa_-_alex_skills_kit_-_test.png|200px]]<br />
<br />
===== Custom Skill anlegen =====<br />
<ol><br />
<li> Oben rechts ''Add a New Skill'' auswählen<br />[[Datei:Developer.amazon.com-18-alexa_-_alex_skills_kit_-_add_a_new_skill.png|200px]]</li><br />
<li> Auf der folgenden Seite (''Skill Information'') die nachstehenden Daten eingeben und dann mit ''Next'' bestätigen:<br />
<ul><br />
<li> ''Skill Type'' -> ''Custom Interaction Model'' </li><br />
<li> ''Language'' -> ''German''</li><br />
<li> ''Name'' -> beliebiger Name, z.B. "MySmartHome Advanced". Dieser wird in der Alexa App unter "Meine Skills" angezeigt.</li><br />
<li> ''Invocation Name'' -> Aufruf des Skills, unter dem dieser später gestartet wird. Z.B. "Alexa, starte James"<br />[[Datei:CustomSkill_2.PNG|400px]]</li><br />
</ul></li><br />
<li>Auf der Seite ''Interaction Model'' folgende Eingaben tätigen und mit ''Next'' abschließen<br />
<ul><br />
<li>In einem separaten Browserfenster FHEM aufrufen, und für das bereits definierte Alexa-Gerät das Kommando <code>get MyAlexa interactionModel</code> aufrufen. Es erscheint ein Popup-Fenster mit ziemlich vielen Zeilen.<br />
<li>In die Box ''Intent Schema'' kopiert man den ersten Teil dieser FHEM-Ausgabe hinein, also:<br/><blockquote><br />
{ <br />
"intents" : [ <br />
<hier ziemlich viele Zeilen> <br />
]<br />
}<br />
</blockquote></li><br />
<li>Nun die ''Custom Slot Types'' einrichten. Dazu muss aus dem zweiten Teil der FHEM-Ausgabe jeweils der Slot-Type (z.B. <code>FHEM_article</code>) in das Feld ''TYPE'' eingetragen werden, das nach dem Anklicken von ''Add Slot Type'' erscheint. In das darunter liegende größere Textfeld kommen die möglichen Werte für diesen Slot, so wie sie aus der FHEM-Ausgabe abzulesen sind. Dann mit ''Save'' sichern. Als Custom Slot Type erscheint dann für diesen Beispiel-Slot<br />
FHEM_article der | die | das | den<br />
d.h., die Zeilenumbrüche bei den möglichen Werten werden als "|" dargestellt.</li><br />
<li>Hier muss nun ein Bruch im Arbeitsfluss durchgeführt werden, denn bei der Erstellung des Custom Skills kommt es auf die Reihenfolge der Einträge an. Deshalb zunächst diese FHEM-Ausgabe schließen, und für dasselbe FHEM-Device <code>get MyAlexa customSlotTypes</code> ausführen. Auch diese Ausgabe wird, wie oben beschriebeen, in Custom Slot Types eingetragen (erst der TYPE, dann die möglichen Werte)<br />
<li>Anschließend erneut die FHEM-Ausgabe schließen und erneut für das bereits definierte Alexa-Gerät das Kommando <code>get MyAlexa interactionModel</code> aufrufen.<br />
<li>Unter ''Sample Utterances'' nun den Text aus dem dritten Teil dieser FHEM-Ausgabe hineinkopieren<br />[[Datei:CustomSkill_5.PNG|400px]]</li><br />
</ul></li><br />
<li>Auf der Seite ''Configuration'' Folgendes eingeben und mit ''Next'' bestätigen:<br />
<ul><br />
<li>''Service Endpoint Type'' -> ''AWS Lambda'' auswählen</li><br />
<li>''Geographical Region'' -> ''Europe'' auswählen und im Textfeld den Wert aus Abschnitt [[#AWS_Lambda_Funktion_anlegen | AWS Lambda Funktion anlegen]] (Punkt 12) eintragen. </li><br />
<li>''Do you allow users to create an account or link to an existing account with you?'' -> ''Yes''</li><br />
<li>''Authorization URL'' -> <code>https://www.amazon.com/ap/oa</code></li><br />
<li>''Client ID'' -> ''Client ID'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1</li><br />
<li>''Scope'' -> <code>profile:user_id</code> (wörtlich 1:1 eintragen)</li><br />
<li>''Redirect URLs'' - sollten vorbelegt sein</li><br />
<li>''Authorization Grant Type'' -> ''Auth Code Grant'' auswählen</li><br />
<li>''Access Token URI'' -> <code>https://api.amazon.com/auth/o2/token</code></li><br />
<li>''Client Secret'' -> ''Client Secret'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1</li><br />
<li>''Client Authentication Scheme'' -> ''HTTP Basic''</li><br />
<li>''Privacy Policy URL'' -> <code>https://www.amazon.com/gp/help/customer/display.html?nodeId=468496</code></li><br />
</ul><br />
Beim Sichern dieser Seite mit ''Next'' kann es zu einer Fehlermeldung kommen, wenn man seine Skill-Definitionen mit dem einfachen SmartHome-Skill begonnen hat. Deshalb muss noch der entsprechende Trigger für die [[#AWS_Lambda-Funktion | AWS Lambda Funktion]] nachgetragen werden, dies wird in Abschnitt [[#Trigger_f.C3.BCr_Custom_Skill_hinzuf.C3.BCgen | Trigger für Custom Skill hinzufügen]] beschrieben.<br />
<br />[[Datei:CustomSkill_6.PNG|400px]] [[Datei:CustomSkill_7.PNG|400px]]</li><br />
<br />
==== Testen ====<br />
Hat man den Custom Skill angelegt, bietet dieser auch eine komfortable Testmöglichkeit. Dazu wählt man in der Übersichtsseite ''All Skills'' den Button ''Edit'' des Alexa Custom Skill aus. Auf der nachfolgenden Seite dann links ''Test''. <br />
Die Testseite enthält <br />
* ein Feld ''Voice Simulator'', mit dem man die Sprachsausgabe testen kann, <br />
* ein Feld ''Service Simulator'', mit dem die Verarbeitung von Alexa-Kommandois getestet werden kann. Hier kann man z.B. eintragen<br />
"Alexa, sage <Custom Skill Invocation Name>: Stelle Weckzeit auf Neunzehn Siebenundzwanzig Uhr"<br />
"Alexa, frage <Custom Skill Invocation Name> nach dem Status von Weckzeit"<br />
Dabei ist natürlich der ''Custom Skill Invocation Name'' durch den Wert zu ersetzen, den man im Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]] unter Punkt 2 eingetragen hat.<br />
<br />
==== Skill Id bestimmen ====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Hier wird beschrieben, wo die ''Alexa Skill Id'' zu finden ist}}<br />
Für das [[#AWS_Lamba_Funktion_anlegen | Anlegen einer ''AWS Lambda Funktion'']] bzw für die [[#Alexa-Fhem_konfigurieren | Konfiguration von Alexa-Fhem]] wird die ''Alexa Skill Id'' benötigt. An diese kommt man wie folgt:<br />
# Anmelden wie unter [[#Alexa_Skills | Alexa Skills]] beschrieben.<br />
# Menüpunkt ''ALEXA'' auswählen, wie [[#Skills_bearbeiten | Skills bearbeiten]] erklärt.<br />
# Beim gewünschten Eintrag auf ''Edit'' klicken<br />[[Datei:Developer.amazon.com-23-alexa_-_alex_skills_kit_-_overview.png|200px]]<br />
# Die Id, die nun oben angezeigt wird, ist die gesuchte. Sie hat typischerweise das Format <code>amzn1.ask.skill.[Zahlen und Bindestriche]</code><br />[[Datei:Aws.amazon.com-06-configure_triggers2.png|200px]]<br />
<br />
<hr><br />
<br />
=== AWS Lambda Funktion ===<br />
Für folgende Schritte muss man unter der Adresse http://aws.amazon.com angemeldet sein<br />
# Anmeldung auswählen<br />[[Datei:Aws.amazon.com-01-site.png|200px]]<br />
# Anmeldedaten eingeben<br />[[Datei:Aws.amazon.com-02-login.png|200px]]<br />
# Den Punkt ''Lambda'' links auf der Startseite auswählen, bzw. im Menü ''Services'' unter ''Compute'' den Menüpunkt ''Lambda'' auswählen<br />[[Datei:Aws.amazon.com-03-lambda.png|200px]]<br />
<br />
==== AWS Lambda Funktion anlegen ====<br />
# Für eine erste Lambda-Funktion den Punkt ''Get Started Now'' auswählen<br />[[Datei:Aws.amazon.com-04-get_started_now.png|200px]]<br />
# Den Blueprint ''Blank function'' auswählen<br />[[Datei:Aws.amazon.com-05-select_blueprint.png|200px]]<br />
# Im neuen Fenster dann auf den gestrichelten Kasten klicken und ''Alexa Smart Home'' auswählen und mit ''Next'' bestätigen<br />[[Datei:Aws.amazon.com-06-configure_triggers1.png|200px]]<br />
## Achtung, es ist möglich, dass dabei ''Alexa Smart Home'' überhaupt nicht angeboten wird. Dann bitte ganz rechts oben in der Ecke nachsehen, welche Region bzw. welches Land ausgewählt ist. Empfohlen wird, ''Ireland'' auszuwählen. Dann erscheint bei den Funktionen auch ''Alexa Smart Home''.<br />
# Bei ''Application Id'' den Wert eintragen, dessen Ermittlung im Abschnitt [[#Skill_Id_bestimmen | Skill Id bestimmen]] beschrieben wird, den Haken bei ''Enable trigger'' setzen und mit ''Next'' bestätigen <br />[[Datei:Aws.amazon.com-06-configure_triggers3.png|200px]]<br />
# Auf der Konfigurationsseite eingeben:<br />
## ''Name'' -> ''FHEM''<br />
## ''Runtime'' -> Node.js 4.3. <br />
## ''Role'' -> ''Choose an existing role'' <br />
### Achtung: wenn es noch keine existing role gibt, zuerst ''Create a custom role'' -> in dem Popup dann ''lambda_basic_execution'' auswählen und auf ''Allow'' klicken sowie bei ''Existing role'' dann ''x'' wählen.<br />
# Auf der Code-Seite wird bzw. im großen Textfeld ist dann der Code aus der Datei ''lambda.js'' im Paket [[#Alexa-Fhem_installieren | Alexa-Fhem]] vollständig einzufügen. Dabei muss noch der Hostname im Quellcode an den eigenen Hostnamen angepasst werden. <br />
# Anschließend alles mit ''Next'' bestätigen.<br />[[Datei:Aws.amazon.com-07-configure_function.png|200px]]<br />
# Auf der Übersichtsseite dann ''Create function'' anklicken<br />[[Datei:Aws.amazon.com-08-review.png|200px]]<br />
<br />
==== Trigger für Custom Skill hinzufügen ====<br />
Editiert man eine Lambda-Funktion, werden auf der Seite ''Triggers'' diejenigen Dienste angezeigt, die diese Funktion aufrufen.<br />
* Hier taucht der Trigger ''Alexa Smart Home'' zusammen mit der ''Application Id'' auf, der bei der Einrichtung des SmartHome-Skills eingetragen wurde.<br />
* Zur Verbindung mit dem Custom Skill ist es nötig, einen zweiten Trigger hinzuzufügen. Durch Anklicken von ''Add Trigger'' wird eine Auswahlseite eingeblendet. Im neuen Fenster dann auf den gestrichelten Kasten klicken und ''Alexa Skills Kit' auswählen und mit ''Next'' bestätigen<br />
<br />
==== ARN der AWS Lambda Funktion bestimmen ====<br />
# Auf der Übersichtsseite oben links den Menüpunkt ''Functions'' aúswählen<br />[[Datei:Aws.amazon.com-09-go_overview.png|200px]]<br />
# Anschließend den Radiobutton der angelegten Funktion ''FHEM'' markieren und im Menü ''Action'' den Punkt ''Show ARN'' auswählen<br />[[Datei:Aws.amazon.com-10-1-show_arn.png|200px]]<br />
# Es wird nun eine ARN Adresse angezeigt, die für den Abschnitt [[#SmartHome_Skill_anlegen| SmartHome Skill anlegen]] benötigt wird<br />[[Datei:Aws.amazon.com-10-2-arn.png|200px]]<br />
<br />
=== Absichern des Zugriffs ===<br />
Natürlich muss der Zugriff auf den von Alexa-Fhem verwendeten Port (default: 3000, Bestandteil des Codes in der AWS Lambda-Funktion) durch die Firewall freigeschaltet werden (auf einer FritzBox unter "Portfreigaben").<br />
<br />
==== Absicherung direkt in Alexa-FHEM ====<br />
Die Kommunikation zwischen Amazon AWS und Alexa-FHEM ist auf die folgenden Arten gesichert:<br />
* Die Verbindung erfolgt per HTTPS<br />
* Es werden nur Verbindung angenommen auf denen ein gültiges Alexa-Event gesendet wird. <br />
* Es werden nur Verbindungen angenommen die ein gültiges und noch nicht abgelaufenes OAuth-Token enthalten. Jedes neue Token wird live bei Amazon auf Gültigkeit geprüft. <br />
* Es werden nur Verbindungen mit lokal konfigurierter Skill-ID angenommen.<br />
* Es ist nicht möglich von außen beliebige FHEM Kommandos zu senden. Die FHEM Kommandos werden nur lokal erzeugt.<br />
<br />
Wer möchte kann Alexa-FHEM natürlich noch weiter absichern. Es gilt aber, dass nicht jedes zusätzliche Glied in der Kette die Sicherheit sondern unter Umständen nur die Angriffsfläche erhöht. Ein falsch konfigurierter und nach aussen offener Apache (oder anderer ReverseProxy) ist unter Umständen ein größeres Risiko als Alexa-FHEM alleine.<br />
<br />
==== Absicherung per ReverseProxy ====<br />
<s>Die Kommunikation zwischen Amazon und FHEM ist wegen der Verwendung von SSL schon verschlüsselt - prinzipiell kann aber jeder von außen mit Alexa-Fhem kommunizieren. Man sollte sich deshalb im Klaren darüber sein, dass dies eine Sicherheitslücke darstellt:</s> Jeder offene Port verleitet zu Angriffen, und mit zunehmender Verbreitung von Alexa steigt auch das Risiko. Es wird deshalb empfohlen, vor den eigentlichen Alexa-Server zur Absicherung einen Apache-Webserver als ReverseProxy zu setzen. Nicht nur ist der Apache eine hervorragend stabile und seit Jahrzehnten getestete Software, sondern die Konfiguration als ReverseProxy erlaubt auch, den Zugriff auf den Alexa-Fhem-Rechner auf die Amazon-Maschinen zu beschränken.<br />
<br />
'''Achtung: Dies ist keine allgemeine Anleitung in Sachen Computersicherheit.''' Im Folgenden gehen wir davon aus, dass <br />
* Grundbegriffe wie Firewall, IP-Ports, SSL und Dynamic DNS vertraut sind<br />
* Ein Apache Webserver (idealerweise auf einer zweiten Maschine) bereits installiert ist und die Konfiguration verstanden wurde (wenn nicht: Es gibt im Netz ''tausende'' von Anleitungen dafür...)<br />
* Ein Servername von einem DynDNS-Anbieter - sagen wir ''myhome.is-my-castle.com'' - bereits von ''außen'' auf unser SmartHome zeigt.<br />
* Alexa-Fhem in einer der oben beschriebenen Basiskonfigurationen läuft, d.h. der Zugriff auf <code>https://myhome.is-my-castle.com:3000</code> ergibt, wie im Punkt [[#Alexa-Fhem_testen|Alexa-Fhem testen]] beschrieben, eine Antwort des Node.js Servers.<br />
<br />
Als erster Schritt zur Absicherung muss das ReverseProxy Modul für den Apache installiert und mit <code>a2enmod</code> aktiviert werden, hierzu sei auf [https://www.digitalocean.com/community/tutorials/how-to-use-apache-http-server-as-reverse-proxy-using-mod_proxy-extension diese Anleitung] verwiesen. Der zweite Schritt besteht darin, den SSL-Zugriff durch ein Passwort abzusichern. Dazu wird auf dem Apache-Rechner das Programm <br />
htpasswd <passwdfile> <username><br />
ausgeführt, das Programm fragt dann nach dem gewünschten Passwort. Wir nehmen im Folgenden an, dass das Passwortfile ''/etc/apache2/htpasswd'' ist, der gesetzte Username ''alexa'' lautet und das Passwort ''my_smarthome'' ist.<br />
<br />
Im dritten Schritt wird nun in das Apache-Konfigurationsfile die Weiterleitung auf den eigentlichen Alexa-Fhem-Rechner eingetragen. Dazu wählen wir, dass von außen der Standard-SSL-Port 443 benutzt werden soll, sowie als Verzeichnisname ''/alexa''. '''Achtung:''' Dieser Code soll '''nicht''' in die Default-Konfiguration des Apache-Webservers. Sondern in eine separate Datei (Dateiname z.B. "fhem"), die ins Unterverzeichnis /etc/apache2/conf.d gestellt wird.<br />
<br />
<VirtualHost *:443><br />
ServerName myhome.is-my-castle.com<br />
SSLEngine on<br />
SSLProxyEngine on<br />
SSLProxyCheckPeerCN off<br />
SSLProxyCheckPeerName off<br />
SSLCertificateKeyFile /etc/apache2/mycert/server.key<br />
SSLCertificateFile /etc/apache2/mycert/server.crt<br />
<Location /alexa><br />
AuthType Basic<br />
AuthName "Authentication Required"<br />
AuthUserFile "/etc/apache2/htpasswd"<br />
Require valid-user<br />
ProxyPass https://<hier IP-Adresse des Alexa-Fhem-Rechners>:3000/<br />
ProxyPassReverse https://<hier IP-Adresse des Alexa-Fhem-Rechners>:3000/<br />
Order deny,allow<br />
Allow from All<br />
</Location><br />
(... Hier eventuell weitere Umleitungen)<br />
</VirtualHost><br />
Nach einem Neustart des Apache-Servers, dem Schließen des Ports 3000 in der Firewall sowie dem Öffnen des Ports 443 ist der Alexa-Fhem-Rechner von außen nur noch erreichbar durch den Aufruf von <code>https://myhome.is-my-castle.com/alexa</code> und verlangt unmittelbar die Eingabe von Username und Passwort.<br />
<br />
Der vierte Schritt ist nun, den Code der AWS Lambda-Funktion an fünf Stellen zu verändern<br />
'''const PORT=443;'''<br />
const HOST='myhome.is-my-castle.com';<br />
'''const PATH='/alexa';'''<br />
'''const AUTH='alexa:my_smarthome';'''<br />
// entry<br />
exports.handler = function(event, context, callback) {<br />
console.log(`EVENT: ${event}`);<br />
console.log(`CONTEXT: ${context}`); <br />
var post_data = JSON.stringify(event);<br />
var options = {<br />
hostname: HOST,<br />
port: PORT,<br />
//family: 6,<br />
'''path: PATH,'''<br />
method: 'POST',<br />
'''auth: AUTH,'''<br />
rejectUnauthorized: false, // accept self-signed<br />
(etc., Rest des Codes wie gehabt)<br />
Natürlich muss der Zugriff getestet werden. Bei Beachtung aller dieser Schritte werden alle un-autorisierten Zugriffe von außen abgewehrt. Eine noch weiter gehende Sicherung ist möglich, dazu kann in der Serverkonfiguration der Zugriff auf die Amazon-Domains beschränkt werden. Das ganze Alexa-System ist aber noch in konstanter Weiterentwicklung, diese Domain-Namen können sich also noch ändern.<br />
<br />
== Einrichtung in der Alexa App==<br />
Nachdem die Alexa Skills angelegt wurden, müssen diese noch in der Alexa App eingerichtet werden.<br />
Dafür jeweils per Desktop-Browser auf [http://alexa.amazon.de alexa.amazon.de] anmelden, nicht die App unter iOS oder Android verwenden. Diese hat Probleme mit der OAuth Verknüpfung.<br />
<br />
=== Alexa Skill ===<br />
# Auf ''Skills'' klicken<br />[[Datei:Alexa.amazon.de-01-startseite.png|200px]]<br />
# Oben rechts ''Meine Skills'' bzw. ''Ihre Skills'' auswählen<br />[[Datei:Alexa.amazon.de-03-meine_skills.png|200px]]<br />
# In der Liste der Skills sollte das angelegte FHEM Skill angezeigt werden. Dieses anklicken<br />[[Datei:Alexa.amazon.de-02-liste_skills.png|200px]]<br />
# Oben Rechts in den Details des Skills auf ''Skill aktivieren'' klicken<br />[[Datei:Alexa.amazon.de-04-skill_details.png|200px]]<br />
# In dem neu geöffneten Fenster die Autorisierung bestätigen<br />[[Datei:Alexa.amazon.de-05-amazon_auth.png|200px]]<br />
# Anschließend sollte die Verbindung erfolgreich aufgebaut worden sein <br />[[Datei:Alexa.amazon.de-06-success.png|200px]]<br />
<br />
=== Geräte ===<br />
# Auf http://alexa.amazon.de anmelden<br />
# Auf ''Smart Home'' klicken<br />[[Datei:Alexa.amazon.de-01-startseite.png|200px]]<br />
# Anschließend den Punkt ''Geräte suchen'' anklicken<br />[[Datei:Alexa.amazon.de-07-Gerätesuche.png|200px]]<br />
# Wurde soweit alles korrekt eingerichtet, werden nun die gefundenen Geräte angezeigt.<br />
<br />
Tip: Es macht Sinn, unter ''Meine Gruppen'' Gruppen benannt nach den Räumen einzurichten. Hierdurch kann Alexa die Geräte besser auseinander halten, vor allem wenn die den gleichen Alias (z.B. "Licht") haben.<br />
<br />
== Einrichtung unter FHEM ==<br />
Im Folgenden werden exemplarisch ein paar Geräte beschrieben, die man nutzbringend mit FHEM einsetzen kann.<br />
<br />
Bei Verwendung des Custom Skills übersetzt die Kombination der Attribute ''alexaMapping'' und ''homebridgeMapping'' Sprachbefehle ("Intents") in gerätespezifische Kommandos. <br />
* Das Attribut alexaMapping wird am Alexa-Device gesetzt und dient dazu, erkannte Sprachkommandos in abstrakte Characteristiken zu überführen. Für den einfacheren SmartHome Skill hat darum das Attribut ''alexaMapping'' keine Bedeutung, sondern nur der ''genericDeviceType'' des zu steuernden Gerätes.<br />
* Das Attribut homebridgeMapping wird für beide Skills am zu steuernden Gerät gesetzt und übersetzt diese Charakteristiken in die konkreten Befehle, die das Gerät versteht. Der inhalt des Attributs wird von links nach rechts ausgewertet und ist wie folgt aufgebaut:<br />
** Das Attribut enthält eine durch Leerzeichen getrennte Liste aus Konfigurationen für jeweils eine Characteristik<br />
** Jede einzelne der Characteristik-Konfigurationen besteht aus dem Namen der Characteristik, gefolgt von "=" und einer kommaseparierten Liste von Parametern.<br />
attr <device> homebridgeMapping <Characteristic1>=<param1.1>,<param1.2>,... <Characteristic2>=<param2.1>,<param2.2>,...<br />
** Jeder Parameter besteht entweder aus<br />
*** <code><cmd>:<device>:<reading></code>, hier können nicht verwendete Elemente von links nach rechts weg gelassen werden.<br />
*** <code><name>=<value></code>, hier kann <code><value></code> entweder ein Wert oder semikolonseparierte Liste sein.<br />
*** Oder dem schlüsselwort <code>clear</code>, welches alle vorhandenen (default) Parameter dieser Characteristik löscht. <code>clear</code> kann auch an Stelle einer ganzen Characteristik-Konfiguration stehen<br />
Weiter führende Dokumentation zum homebridgeMapping findet sich unter https://forum.fhem.de/index.php/topic,48558.0.html<br />
<br />
=== Einfacher Schalter ===<br />
* Ein einfacher Schalter, der die set-Kommandos ''on'' und ''off'' kennt, kann direkt mit Alexa-Fhem gekoppelt werden <br />
* Für kompliziertere Aktionen, etwa das Übermitteln eines spezifischen Schaltbefehls an FHEM, ist die Einrichtung eines Dummies zu empfehlen. <br />
Ob Dummy oder nicht, wichtig sind die drei fett gedruckten Zeilen<br />
define Alexa.Party dummy<br />
'''attr Alexa.Party alexaName party'''<br />
'''attr Alexa.Party alexaRoom alexaroom'''<br />
'''attr Alexa.Party genericDeviceType switch'''<br />
attr Alexa.Party group AlexaGeräte<br />
attr Alexa.Party room AlexaRoom<br />
'''attr Alexa.Party setList on off'''<br />
Selbstverständlich kann man diesen Dummy mit einem notify oder DOIF abfangen, um die gewünschte Schaltaktion auszuführen. <br />
<br />
Ein Alternative zum Dummy ist das Anlegen eines readingsProxy, dem die entsprechenden Attribute gegeben werden.<br />
<br />
Weil es sich hierbei um eines der einfachen Geräte handelt, die Alexa selbst im SmartHome Skill bearbeiten kann, ist auch der zweite Schritt bei der Einrichtung in der Alexa App sinnvoll: Der Schalter wird dann im Bereich Smart Home der Alexa App erkannt. Wer ihn auch mit dem Custon Skill bedienen möchte, muss natürlich Sorge tragen, dass der Alexa-Name ''party'' bei den FHEM_Devices auftaucht und die entsprechenden weiteren Slot Types und Example Utterances in der Konfiguration des Custom Skills vorhanden sind (siehe Abschnitt [[##Custom_Skill_anlegen | Custom Skill Anlegen]]).<br />
<br />
=== Wecker ===<br />
Dieses Gerät kann man nur mit dem Custom Skill bedienen, es wird also '''nicht''' im Bereich Smart Home der Alexa App auftauchen. Wir richten einen Dummy ein, wichtig sind wieder die fett gedruckten Zeilen:<br />
define Alexa.Weckzeit dummy<br />
'''attr Alexa.Weckzeit alexaName weckzeit'''<br />
'''attr Alexa.Weckzeit alexaRoom alexaroom'''<br />
attr Alexa.Weckzeit genericDeviceType clock<br />
attr Alexa.Weckzeit group AlexaGeräte<br />
'''attr Alexa.Weckzeit homebridgeMapping Weckzeit=state,cmd=+'''<br />
attr Alexa.Weckzeit room AlexaRoom<br />
'''attr Alexa.Weckzeit setList Weckzeit:time'''<br />
Das Attribut ''genericDeviceTye'' ist nicht wichtig, weil es ein generisches Device dieser Art gar nicht gibt. Wichtig hingegen ist das Attribut ''homebridgeMapping'' <br />
<br />
Für das Gerät ''MyAlexa'', das in Abschnitt definiert wurde, muss im Attribut ''alexaMapping'' auftauchen<br />
Weckzeit=verb=stelle,valuePrefix=für;auf,values=AMAZON.TIME,valueSuffix=uhr<br />
Darüber hinaus muss der Alexa-Name ''weckzeit'' bei den FHEM_Devices auftauchen und die entsprechenden weiteren Slot Types und Example Utterances in der Konfiguration des Custom Skills vorhanden sein (siehe Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]]).<br />
<br />
Der Aufruf dieses Gerätes mit Alexa erfolgt dann z.B. mit den Sätzen<br />
<pre style="width:50%;"><br />
"Alexa, sage <Custom Skill Invocation Name>: Stelle Weckzeit auf Neunzehn Uhr Siebenundzwanzig"<br />
"Alexa, frage <Custom Skill Invocation Name> nach dem Status von Weckzeit"<br />
</pre><br />
Dabei ist natürlich der ''Custom Skill Invocation Name'' durch den Wert zu ersetzen, den man im Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]] unter Punkt 2 eingetragen hat.<br />
<br />
Zur weiteren Bearbeitung kann man jetzt mit einem DOIF Statusänderungen des Dummies abfangen und durch eine kleine Helperfunktion ins "echte" FHEM weiterleiten.<br />
define Alexa.Weckzeit.N DOIF (["Alexa.Weckzeit:.*"])({AlexaHelper("Alexa.Weckzeit","$EVENT")}) <br />
Die Helperfunktion (z.B. in 99_myUtils.pm) stellt aus der übergebenen Zeit (immer im Format dd:mm) eine sprachkompatible Nachricht $nc und einen mit den FHEM-Zeitangaben kompatiblen String $nt zusammen und reicht beide an eine Routine ''changeWakeTime'' weiter (dokumentiert in den [https://www.dpunkt.de/buecher/12387/9783960090120-smarthome-hacks.html Smart Home Hacks]).<br />
sub AlexaHelper($$){<br />
my ($name,$event)=@_;<br />
if( $name eq "Alexa.Weckzeit" ){ <br />
my ($nc,$nt);<br />
#-- volle Stunde----------------------------------------<br />
if( $event =~ /(\d+):00/ ){<br />
$nc=sprintf("%d Uhr",$1);<br />
$nt=sprintf("%02d:00:00",$1);<br />
#-- nicht volle Stunde---------------------------------<br />
}elsif( $event =~ /(\d+):(\d+)/ ){<br />
$nc=sprintf("%d Uhr %d",$1,$2);<br />
$nt=sprintf("%02d:%02d:00",$1,$2);<br />
}<br />
changeWakeTime(\'GalaxyTab.EG\',\'$nc\',\'$nt\');<br />
}<br />
}<br />
<br />
<hr><br />
<br />
=== Lichtszene ===<br />
Eine Lichtszene wird mit dem Modul LightScene angelegt. Wir gehen davon aus, dass in der Lichtszene die beiden Szenen Alle_An und Alle_Aus, sowie mindestens eine weitere Szene (hier: Sitzgruppe) definiert wurde.<br />
* Nachfolgend wird ein Beispiel beschrieben, wie man eine Lichtszene mit dem einfachen SmartHome Skill steuern kann. Die verwendeten Kommandos sind dann<br />
<pre><br />
"Alexa, schalte (die) Beleuchtung an" -> LightScene Alle_An wird ausgewählt<br />
"Alexa, schalte (die) Beleuchtungsitzgruppe an" -> LightScene Sitzgruppe wird ausgewählt<br />
...<br />
"Alexa, schalte (die) Beleuchtung aus" -> LightScene Alle_Aus wird ausgewählt<br />
</pre><br />
* Künftig wird man LightScene mit dem Custom Skill eventuell direkt steuern können - allerdings hat das einen geringeren WAF, als die Steuerung über den SmartHome Skill: Der Einschaltsatz muss dann mindestens lauten<br />
<pre><br />
"Alexa, sage <Custom Skill Invocation Name>: schalte (die) Beleuchtung an" -> LightScene Alle_An wird ausgewählt<br />
</pre><br />
Dafür wird es aber auch möglich sein direkt die SzenenNamen im gesprochenen Kommando zu verwenden und so auf die Umwege über dummys und ähnliches zu verzichten.<br />
<br />
<br />
Im ersten Schritt wird ein Dummy für die Gesamtbeleuchtung eingerichtet:<br />
define Alexa.Beleuchtung dummy <br />
attr Beleuchtung setList on off<br />
'''attr Alexa.Beleuchtung alexaName beleuchtung'''<br />
'''attr Alexa.Beleuchtung alexaRoom alexaroom'''<br />
'''attr Alexa.Beleuchtung genericDeviceType switch'''<br />
Anschließend wird für jede vorhandene Lichtszene (außer Alle_An und Alle_Aus) ein weiterer Dummy angelegt:<br />
define Alexa.Beleuchtung.Sitzgruppe dummy <br />
attr Beleuchtung setList on off<br />
'''attr Alexa.Beleuchtung.Sitzgruppe alexaName beleuchtungsitzgruppe'''<br />
'''attr Alexa.Beleuchtung.Sitzgruppe alexaRoom alexaroom'''<br />
'''attr Alexa.Beleuchtung.Sitzgruppe genericDeviceType switch''' <br />
Die eigentliche Steuerung übernimmt dann ein DOIF<br />
define Alexa.Beleuchtung.N DOIF<br />
(["Alexa.Beleuchtung.Sitzgruppe:on"])<br />
(set <devicename der Lichtszene> scene Sitzgruppe,<br />
set Alexa.Beleuchtung off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
DOELSIF<br />
... <weitere on-Events der anderen Szenen werden abgefangen><br />
DOELSEIF<br />
(["Alexa.Beleuchtung:on"])<br />
(set <devicename der Lichtszene> scene Alle_An,<br />
set Alexa.Beleuchtung.Sitzgruppe off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
DOELSEIF<br />
(["Alexa.Beleuchtung:off"])<br />
(set <devicename der Lichtszene> scene Alle_Aus,<br />
set Alexa.Beleuchtung.Sitzgruppe off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
Mit diesem DOIF wird ein Radiobutton simuliert, d.h. wie bei den Stationstasten vor Uralt-Radios sorgt die Auswahl einer Szene immer dafür, dass alle anderen Dummies ausgeschaltet werden.<br />
Natürlich kann man das auch mit einem kleinen Perl-Programm erreichen.<br />
<br />
<br />
Zwei andere Ansätze Lichtszenen zu schalten die ohne DOIF auskommen sind im Folgenden beschrieben:<br />
<br />
* Wenn es von Interesse ist die Steuerung mit einer Darstellung in FTUI zu verbinden: Statt der oben beschriebenen dummy Devices kann man readingsProxy Devices mit passenden setFn und valueFn analog zum [[Harmony#Button_f.C3.BCr_eine_bestimmte_Activity_im_Frontend_und_Homekit_.C3.BCber_readingsProxy|diesem Beispiel für harmony aktivitäten]] verwenden.<br />
<br />
* Für jede zu schaltende Szene wird ein dummy angelegt dessen homebridgeMapping direkt auf das LightScene Device zeigt:<br />
<br />
define <dummy> dummy<br />
attr <dummy> setList on off<br />
attr <dummy> genericDeviceType switch<br />
attr <dummy> homebridgeMapping On=<light scene>::state,valueOn=<szene>,cmdOn=scene+<szene>,cmdOff=scene+<szene aus><br />
<br />
Bei der zweiten Variante wird davon ausgegangen das der aktuelle status nicht abgefragt oder angezeigt werden soll. Deshalb gibt es keine direkte RadioButton Funktionalität.<br />
<br />
== Nutzung ==<br />
Um den Namen zu bestimmen, unter dem ein Gerät mit Alexa angesprochen wird, verwendet Alexa-Fhem mit absteigender Priorität:<br />
* das alexaName Attribut<br />
* das alias Attribut<br />
* das NAME Internal<br />
Damit Alexa ein Gerät eindeutig identifizieren kann, sollten eindeutige Gerätenamen verwendet werden, bestehed möglichst aus einem Wort und ohne Ziffern. Wenn Alexa einen Namen nicht versteht, kann man unter [http://alexa.amazon.de/spa/index.html] nachsehen was tatsächlich verstanden wurde und den Gerätenamen ggf. anpassen.<br />
<br />
=== SmartHome Skill ===<br />
Gruppen (Räume) müssen in der Alexa App konfiguriert werden. Über das API lassen sich nur der Name und die Schalteigenschaften übergeben.<br />
<br />
Nach erfolgreicher Einrichtung des SmartHome Skills sollte Alexa mit den folgenden Befehlen nutzbar sein:<br />
<pre style="width:50%;"><br />
“alexa, schalte <gerät/gruppe> ein”<br />
“alexa, schalte <gerät/gruppe> aus”<br />
“alexa, stelle <gerät/gruppe> auf <wert> prozent”<br />
“alexa, stelle <gerät/gruppe> auf <anzahl> grad”<br />
“alexa, erhöhe <gerät/gruppe> um <anzahl> prozent”<br />
“alexa, reduziere <gerät/gruppe> um <anzahl> prozent”<br />
“alexa, erhöhe <gerät/gruppe> um <anzahl> grad”<br />
“alexa, reduziere <gerät/gruppe> um <anzahl> grad”<br />
</pre><br />
<br />
=== Custom Skill ===<br />
Der Custom Skill erlaubt im Gegensatz zum SmartHome Skill eine weitreichende Konfiguration der möglichen Kommandos.<br />
<br />
Das Prinzip der Kommandokonfiguration ist {{Link2Forum|Topic=60244|Message=532513|LinkText=im Forum}} beschrieben.<br />
<br />
TODO: Abfragen, Attribute (alexaMapping, alexaTypes, fhemIntents, articles, prepositions)<br />
<br />
== Troubleshooting ==<br />
<br />
====Allgemeiner Hinweis====<br />
Besonders wichtig ist, dass man sich sehr genau an diese Anleitung hält. Ein häufiger Fehler ist, dass die einfachen Anführungszeichen in der Anleitung unter '''AWS Lambda Funktion anlegen''' Punkt 8 einfach weggelassen werden. Diese sind zwingend notwendig. Es darf auch nur der reine Hostname eingetragen werden. Also kein ''http://'' davor. Entweder eine feste IP Adresse oder den Hostnamen, um den Rechner zu erreichen, den ihr über den Port 3000 freigegeben habt. Das sollte dann so aussehen:<br />
<pre style="width:50%;"><br />
const PORT=3000;<br />
const HOST='mein.host.name';<br />
</pre><br />
<br />
====Freigabe von Port 3000====<br />
{{Randnotiz|RNTyp=Fehl|RNText=Derzeit müsst ihr über einen echten IPv4 Anschluss verfügen, damit der Amazon Lambda-Server euch erreichen kann. DS-Lite Anschlüsse wie die von <b>UnityMedia</b> z.B. funktionieren derzeit leider nicht. Eine möglicher "Workaround" wird hier beschrieben: https://forum.fhem.de/index.php/topic,60244.msg518276.html#msg518276}}<br />
<br />
Auf dem Router muss der Port 3000 Protokoll TCP freigegeben werden. D.h. von außen muss man wenn man den Port 3000 aufruft, auf dem intern laufenden node.js Alexa-Dienst zugreifen können.<br />
Je nach Router gestaltet sich das Portforwarding bzw. die Portumleitung etwas schwieriger.<br />
<br />
Bei einem Speedport Router der Telekom beispielsweise, muss der Router komplett neu gestartet werden, wenn die Portfreigabe eingerichtet wurde. <br />
<br />
Bei der Fritz!Box ist das nicht nötig, bei dieser finden die Freigabe unter ''Internet -> Freigaben -> Portfreigaben'' statt. Dort wählt man dann den Rechner aus und richtet eine neue Freigabe ein. Wichtig hierbei ist, dass man Portfreigabe auswählt und nicht MyFRITZ!-Freigabe. Bei Port von bis trägt man 3000 ein, bei Port extern ebenfalls.<br />
<br />
Um die Portweiterleitung zu testen, solltet ihr euch auch nicht im gleichen Netz befinden. Viele Router blockieren den Netzaufruf aus dem gleichen Netz. Am besten testet ihr es, wenn ihr an eurem Mobiltelefon W-LAN deaktiviert und im Browser folgende Seite aufruft: ''https://mein.hostname:3000''. Wenn ihr im Browser dann einen Quellcode von Alexa seht, funktioniert die Portumleitung.<br />
<br />
Wenn bis hier alles funktioniert und es läuft dennoch nicht rund, liegt das Problem woanders. Kommt z.B. bei der Gerätesuche kein Request rein (sichtbar auf dem Bildschirm, wenn bin/alexa gestartet wurden), kann evtl. der Lambda-Dienst falsch konfiguriert sein.<br />
<br />
====Probleme mit node.js - npm install====<br />
<br />
Falls eine Fehlermeldung auftritt, dass "npm" nicht gefunden werden kann, bitte NodeJS entsprechend der Anleitung im Homebridge-Artikel vorgehen: [[Homebridge_einrichten#NodeJS_installieren|NodeJS installieren]] sowie [[Homebridge_einrichten#Python.2C_g.2B.2B.2C_MDNS_installieren|Python, g++, MDNS installieren]], siehe auch folgenden Abschnitt.<br />
<br />
====Es kommen diverse Fehlermeldungen beim Starten von alexa-fhem und es beendet sich====<br />
Wenn man auf der Konsole angemeldet ist, den Befehl<syntaxhighlight lang="bash" style="width:50%;">node -v</syntaxhighlight>eingeben. Ist die Version niedriger als die geforderte 0.12, muss eine neuere installiert werden. Hier darf man dann im Wiki unter [[Homebridge_einrichten#NodeJS_installieren]] nachschauen. NodeJS V4 sollte hierbei schon ausreichen. Solange die node.js Version nicht passt, gar nicht groß rum experimentieren! Bitte beachtet, dass alle Voraussetzungen unter [[Alexa-Fhem#Voraussetzungen]] erfüllt sind! Keine Experimente mit Versionen die darunter liegen.<br />
<br />
====Fehlermeldung ''NAT-PMP failed: Error: timeout'' Fehler angezeigt beim Start von alexa-fhem====<br />
Wenn ihr dann alexa-fhem über die Konsole startet und bekommt folgenden Fehler: ''NAT-PMP failed: Error: timeout'', lasst euch davon nicht irritieren. Das bedeutet lediglich, dass der Port nicht automatich freigegeben wurde über uPNP. Alternativ prüft, ob die Funktion der Portfreigabe via uPNP auf eurem Router aktiviert ist.<br />
<br />
====Nach Start auf der Console beendet sich Alexa-FHEM sofort wieder====<br />
Unmittelbar nach dem Start von Alexa-FHEM werden ein paar UPNP Fehlermeldungen ausgegeben. Unmittelbar danach beendet sich Alexa-FHEM wieder. <br />
<br />
Viele scheinen ein Problem mit UPNP auf dem Raspberry Pi zu haben. Wenn dieses Problem auftritt einfach in der <code>~/.alexa/config.json</code> die folgenden Zeilen rauslöschen:<br />
<br />
<pre><br />
"nat-pmp": "10.0.1.1",<br />
"nat-upnp": true,<br />
</pre><br />
<br />
Jetzt erneut Alexa-FHEM starten. Sollte nun laufen.<br />
<br />
====Was ist zu tun, wenn alexa-fhem keine Geräte findet?====<br />
Zunächst müssen die Geräte, die angesprochen werden wollen, unter FHEM ein neues Attribut zugewiesen bekommen. Dazu das Gerät in FHEM öffnen und das Attribut ''genericDeviceType switch'' hinzufügen, wenn es ein Schalter mit der Funktiona AN/AUS sein soll. Wenn man will, kann man dem Gerät jetzt noch über das Attribut ''alias'' eine besseren Namen geben, mit dem Alexa das Gerät dann auch finden kann.<br />
Anschließend muss alexa-fhem neu gestartet werden und die definierten Geräte sollten nun gefunden werden.<br />
<br />
====Was ist zu tun, wenn Alexa zwar Geräte findet, diese aber nicht angesprochen werden können?====<br />
Zuerst die Informationen zum Datenfluss ganz oben ansehen. Dann am besten von hinten nach vorne vorgehen:<br />
* wenn nichts bei alexa-fhem ankommt: port forwarding prüfen<br />
* wenn lambda.js nichts los wird: im cloudwatch log nachsehen<br />
* wenn bei lambda.js nichts ankommt: den trigger prüfen<br />
<br />
<br />
Zunächst sollte man sich unter ''http://aws.amazon.com'' das Logfile seiner erstellten Funktion anschauen. Ist überhaupt ein Logfile vorhanden? Falls nicht, liegt es vermutlich am Trigger.<br />
Den solltet ihr überprüfen. Scheinbar kommt es hin und wieder vor, dass dieser nicht gesetzt ist. Dazu einfach auf ''Triggers'' klicken und mit ''Add trigger'' erneut einen anlegen. Hier muss, wie in der Anleitung unter '''AWS Lambda Funktion anlegen''' Punkt 7, die ''Application Id'' stehen und der Haken bei ''Enable trigger'' gesetzt sein. Dann alexa-fhem neu starten.<br />
Wenn ihr Änderugen gemacht habt und den alexa-fhem Dienst noch nicht neu gestartet habt, wäre jetzt der richtige Zeitpunkt.<br />
<br />
====Was ist zu tun, wenn sich der Alexa-Service nicht starten lässt?====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Der User in der User= Directive von alexa.service muss Ausführungsrecht auf dem alexa binary haben (x), so wie auch mind. Lesezugriff auf dem Verzeichnis nach -U Option in der ExecStart= Directive und auch auf dem WorkingDirectory }}<br />
Schaut bitte in das Unterverzeichnis [alexa-fhem (also dort, wo Ihr Alexa-FHEM instelliert habt]/bin. Die dort befindliche Datei ''alexa'' muss ausführbar sein. Also z.B. so:<br />
<syntaxhighlight lang="bash" style="width:70%;">2755327 4 -rwxr-xr-x 1 pi pi 339 Nov 26 23:20 alexa</syntaxhighlight><br />
Sollte dies nicht der Fall sein bitte mit:<br />
<syntaxhighlight lang="bash" style="width:70%;">chmod +x alexa</syntaxhighlight><br />
die Datei ausführbar machen. Sofern der User "pi" Eigentümer ist, ist kein sudo erforderlich.<br />
<br />
Eine lauffähige Konfiguration ist {{Link2Forum|Topic=71612|Message=668383|LinkText=hier}} zu sehen.<br />
<br />
Ein Fehler in der Rechtekonfiguration führt in der Regel zu folgendem Ergebnis nach <code>sudo systemctl status alexa</code>:<br />
<br />
<syntaxhighlight lang="bash"> Loaded: loaded (/etc/systemd/system/alexa.service; enabled)<br />
Active: activating (auto-restart) (Result: exit-code) since mer. 2017-09-06 02:33:23 CEST; 3s ago<br />
Process: 18332 ExecStart=/opt/fhem/alexa-fhem/bin/alexa -U /home/alexa/.alexa (code=exited, status=217/USER)<br />
Main PID: 18332 (code=exited, status=217/USER)</syntaxhighlight><br />
<br />
====Wie kann ich via Alexa-FHEM auf FHEM zugreifen, wenn der Port mit Benutzername/Kennwort geschützt ist?====<br />
<br />
Hierzu muss die Datei <code>~/.alexa/config.json</code> geöffnet werden und der Abschnitt "connections" um folgende Zeile ergänzt werden:<pre><br />
"auth": {"user": "fhem", "pass": "fhempassword"},</pre><br />
Bei Verwendung von SSL bei FHEM muss auch noch <pre><br />
"ssl": true,</pre> hinzugefügt werden<br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Sprachsteuerung]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=Alexa-Fhem&diff=22494Alexa-Fhem2017-09-06T01:19:33Z<p>Amenomade: /* Was ist zu tun, wenn sich der Alexa-Service nicht starten lässt? */</p>
<hr />
<div>'''Alexa-Fhem''' ist eine in JavaScript geschriebene und auf NodeJS basierende Software, welche es ermöglicht, der digitalen Amazon Assistentin Alexa zusätzliche Skills für die Heimautomatisierung via FHEM beizubringen. Eine erste funktionierende Version wurde von [https://forum.fhem.de/index.php?action=profile;u=430 justme1968] im {{Link2Forum|Topic=60244|LinkText=Forum}} veröffentlicht.<br />
Das ist eine erste Version der Dokumentation zur Installation und Einrichtung, eine Erweiterung wird sicherlich in nächster Zeit noch folgen.<br />
{{Infobox Modul<br />
|ModPurpose=Anbindung von FHEM an Amazon Assistent Alexa<br />
|ModType=x<br />
|ModTechName=<br />
|ModForumArea=Frontends/Sprachsteuerung<br />
|ModOwner=justme1968<br />
}} <br />
<br />
<br />
==Einführung==<br />
===Glossar===<br />
*Echo bzw. Echo Dot (im Folgenden maskulin bezeichnet) sind die derzeit verfügbaren Geräte des Alexa-Systems '''BILDER EINSTELLEN - Achtung Urheberrecht'''<br />
*AVS ist der Amazon Voice Service, d.h. die Spracherkennungskomponente des Systems.{{Randnotiz|RNTyp=r|RNText=Für die Nutzung der Amazon AWS-Dienste müssen zwingend die Daten einer Kreditkarte angegeben werden. Nach gegenwärtigem Kenntnisstand sollen jedoch keine Kosten für die Nutzung der im Rahmen dieses How To beschriebenen Dienste anfallen, sofern diese in einem Rahmen genutzt werden, der selbst eine intensive private Nutzung nicht überschreitet. Der Benutzer sei an dieser Stelle auf die von Amazon veröffentlichten Preislisten verwiesen. Die Autoren dieser Anleitung und der darin beschriebenen Module übernehmen keine Haftung für eventuelle Kosten, die aus der Nutzung der AWS entstehen. }}<br />
*AWS sind die Amazon Web Services, also per URL erreichbare Dienste zur Ausführung von Berechnungen etc. Im Rahmen von Alexa-Fhem wird bei AWS eine eigene JavaScript-Funktion hinterlegt, die zur Kommunikation mit dem FHEM-Server dient. Im Jargon von Amazon ist dies eine so genannte Lambda-Funktion '''WARUM ? Nachlesen bei Amazon'''.<br />
*Card bezeichnet einen Eintrag in der Alexa-App, der die erkannte Sprachnachricht sowie weiter gehenden Informationen über die Reaktion von Alexa enzthält und Rückmeldung an Amazon erlaubt.<br />
*Skill (engl. für Fähigkeit) ist die Bezeichnung für eine per Spracherkennung bediente Funktionalität des Alexa-Systems, z.B. zur Nachrichtenansage, zur Wettervorhersage oder zur Steuerung von FHEM<br />
<br />
===Arbeitsweise und Datenfluss===<br />
[[Datei:2gpXyLN.jpg|200px|thumb|right|Grafische Darstellung der beteiligten Komponenten]]<br />
Echo -> AVS -> AWS Lambda -> alexa-fhem -> AWS Lambda -> AVS -> Echo<br />
<br />
*Der Echo (oder ein anderes Alexa/AVS fähiges Gerät) nimmt Audiodaten auf und schickt diese an AVS (Amazon Voice Service) zur Erkennung<br />
*AVS führt die Spracherkennung durch und erzeugt ein Event mit Informationen zu den erkannten Daten<br />
:*Beim Alexa SmartHome Skill sind die möglichen Sätze für die Spracherkennung relativ fest vorgegeben <br />
:*Beim Alexa Custom Skill kommen die dazu nötigen Informationen aus dem ''Interaction Model'' der Alexa Skills Configuration<br />
*Das Event wird an den unter ''Configuration'' in der Alexa Skills Configuration hinterlegten Endpoint geschickt<br />
:*Beim Alexa SmartHome Skill ist das zwingend eine AWS Lambda Routine<br />
:*Beim Alexa Custom Skill kann das im Prinzip auch ein eigener Web Service sein<br />
*Das Event wird vom <code>lambda.js</code> code an alexa-fhem weitergeleitet<br />
*alexa-fhem steuert FHEM und sendet ein Antwort-Event zurück<br />
*<code>lambda.js</code> nimmt diese Antwort entgegen und gibt sie an AVS zurück<br />
*AVS sogt dafür das der Echo 'antwortet' und dass die Card in der Alexa App erscheint<br />
<br />
===Anmerkungen===<br />
*Ein Skill hat keinen Zugriff auf die Audiodaten<br />
*Mit dem Skill API kann ein Skill zu zu keiner Zeit von sich aus aktiv werden und 'einfach' Daten an den Echo schicken oder ihn dazu bringen irgendetwas zu tun.<br />
*Wenn man berücksichtigt welchen Weg die Daten insgesamt gehen, ist es erstaunlich, wie schnell die Reaktion auf einen gesprochenen Satz erfolgt.<br />
<br />
=== Abgrenzung des '''Alexa Smart Home Skills''' und des '''Alexa Custom Skills''' ===<br />
<br />
Der [[Alexa-Fhem#Smart_Home|Alexa Smart Home Skill]] ist ein Amazon-Alexa-Standard-Skill, der wesentliche Basisfunktionalitäten bereitstellt. Zu diesen gehört im Wesentlichen die Funktionalität, durch Alexa-FHEM bereitgestellte Devices im Alexa-Account des Benutzers anzulegen. Der Alexa Smart Home Skill reagiert auf gesprochene Interaktion in einem beschränkten Umfang. Beispielsweise genügt ein "Alexa, schalte die Wohnzimmerlampe an" um eine Interaktion zwischen Alexa Smart Home Skill und FHEM-Alexa auszulösen. Nach erfolgreicher Einrichtung wird dieser Skill in der Alexa-App bzw. im Web in der Rubrik "Smart Home" als Skill angezeigt.<br />
<br />
Der [[Alexa-Fhem#Custom|Alexa Custom Skill]] ist kein Standard-Smart-Home-Skill, sondern ein individuell entwickelter Skill, so wie alle anderen Skills auch. Er wird daher auch nicht in der Alexa-App unter der Rubrik "Smart Home" angezeigt. Gesprochene Interaktion mit diesem Skill erfolgt dadurch, dass entweder der Skill explizit gestartet wird (z.B. "Alexa, starte [Name des Skills]") oder direkt angesprochen wird (z.B. "Alexa, frage [Name des Skills] wie ist der Status von [Device] "). Der Alexa Custom Skill befindet sich in Entwicklung und wird hinsichtlich seiner Funktionalitäten laufend weiterentwickelt. Die Einrichtung dieses Skills ist grundsätzlich optional, jedoch werden anspruchsvollere Steuerungsmöglichkeiten nur mit diesem realisiert werden können.<br />
<br />
==Installation==<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Da die einzelnen Schritte der Anleitung an verschiedenen Stellen unterbrochen und später fortgesetzt werden müssen, empfiehlt es sich, die Anleitung einmal vollständig gelesen zu haben. Während der Konfiguration sollten alle nachfolgenden Abschnitte parallel in gleichzeitig geöffneten Browserfenstern durchgeführt werden, die jeweils bis zum Abschluss geöffnet bleiben müssen. }}<br />
Grundvoraussetzung für alle folgenden Schritte ist das Vorhandensein eines Amazon-Accounts. Es wird davon ausgegangen, dass die Konten für alle im Folgenden genutzten Amazon-Dienste eingerichtet wurden.<br />
<br />
===node.js installieren===<br />
Zunächst wird das Betriebssystem (in diesem Falle Debian oder Ubuntu) auf den aktuellen Stand gebracht:<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
sudo apt-get update<br />
sudo apt-get upgrade<br />
sudo apt-get install build-essential libssl-dev</syntaxhighlight><br />
<br />
Nun muss NodeJS installiert werden. Leider ist die Version im Debian Repository deutlich zu alt, daher wird mit den folgenden Befehlen das Node Repository hinzugefügt und NodeJS (in der LTS Version) entsprechend installiert:<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -<br />
sudo apt-get install -y nodejs<br />
</syntaxhighlight><br />
<br />
=== Alexa-Fhem installieren ===<br />
'''Aus gegebenem Anlass: Dies ist weder eine Einführung in Linux, noch eine Anfängerdokumentation für FHEM.''' Also erst die Grundlagen lernen, und dann mit Alexa beginnen !<br />
<br />
Die aktuelle Version ist jeweils {{Link2Forum|Topic=60244|Message=540117|LinkText=hier}} zu finden.<br />
<br />
====Erstinstallation====<br />
Hier wird die Erstinstallation von Alexa-Fhem beschrieben.<br />
===== Linux =====<br />
# Die tgz-Datei unter Linux im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) entpacken (''nicht'' unter Windows, das zerstört die Rechteeinstellungen).<syntaxhighlight lang="bash" style="width:50%;">tar -xvzf dateiname.tgz</syntaxhighlight><br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen <syntaxhighlight lang="bash" style="width:50%;">mv package alexa-fhem</syntaxhighlight><br />
# Durch <syntaxhighlight lang="bash" style="width:50%;">cd alexa-fhem</syntaxhighlight> in das Verzeichnis wechseln<br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren (kein sudo!).<br />
# SSL Zertifikat erzeugen durch Aufruf von <syntaxhighlight lang="bash" style="width:50%;">./createKey.sh</syntaxhighlight> (kein sudo!). Hierbei beachten, dass ein Kennwort vergeben werden muss, das mindestens aus 4 Zeichen besteht, dieses Kennwort bitte merken.<br />
# Das Verzeichnis ''.alexa'' anlegen, ''und zwar im Home-Verzeichnis desjenigen Benutzers, unter dem Alexa-Fhem laufen soll.'' Insbesondere ist zu beachten, dass dieser Nutzer u.U. im Startskript explizit gesetzt wird. Mit dem untenstehenden Skript ist das ''nicht'' der User fhem, sondern der User ''pi''. Das Symbol ''~/'' verweist auf das Home-Verzeichnis des Benutzers, der gerade die Installation vornimmt.<br />
# Die Datei ''config-sample.json'' nach ''.alexa/config.json'' kopieren. Achtung: Installiert man alexa-fhem als root-user, zeigt das Symbol ''~/'' auf ''/root'' - und die Konfigurationsdatei wird ggf. bei einem manuellen Start von Alexa-Fhem nicht gefunden.<br />
# Achtung: Ggf. müssen auch die Dateien key.pem und cert.pem ins entsprechende Verzeichnis kopiert werden.<br />
===== Windows =====<br />
''Vor'' der Installation von Alexa-Fhem muss man folgende Anwendungen installieren:<br />
* Node.js (die aktuelle Version findet man unter https://nodejs.org/en/download/)<br />
* OpenSSL (http://slproweb.com/products/Win32OpenSSL.html oder https://www.heise.de/download/product/win32-openssl-47316/download)<br />
Erst dann fängt man mit Alexa-Fhem an.<br />
<br />
<br />
# Die tgz-Datei im Hauptverzeichnis von FHEM (z.B. <code>С:\Program Files (x86)\fhem</code>) entpacken.<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen<br />
# Windows-Shell (Kommandozeile, Eingabeaufforderung usw.) öffnen. "Start" -> "Ausführen" (oder [Windows-Taste]+[R]) -> cmd -> Ok. Durch <syntaxhighlight lang="bash" style="width:50%;">cd "<FHEM-Hauptverzeichis>\alexa-fhem"</syntaxhighlight> in das Verzeichnis wechseln. <br/>Dabei ist natürlich das <FHEM-Hauptverzeichis> durch den entsprechenden Pfad aus dem Schritt 1 zu ersetzen. Im o.g. Beispiel wäre es <code>cd "С:\Program Files (x86)\fhem\alexa-fhem"</code><br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren.<br/> Bei der Fehlermeldung wie "Der Befehl "npm" ist entweder falsch geschrieben oder konnte nicht gefunden werden." ist die Installation von Node.js zu überprüfen.<br />
# SSL Zertifikat erzeugen. Dafür muss man alle Befehle aus dem Skript ''createKey.sh'' nacheinander manuell ausführen. Hierbei beachten, dass ein Kennwort vergeben werden muss, das mindestens aus 4 Zeichen besteht, dieses Kennwort bitte merken. Der Windows-Welt unbekannter Befehl <code>mv</code> ist durch <code>move /y</code> zu ersetzen:<syntaxhighlight lang="bash" style="width:50%;">openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;">openssl rsa -in key.pem -out newkey.pem</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;">move /y newkey.pem key.pem</syntaxhighlight> Eventuelle Fehlermeldung "can't open config file: /usr/local/ssl/openssl.cnf" o.Ä. lässt sich durch Befehl <code>set OPENSSL_CONF=<OpenSSL-Verzeichnis>\bin\openssl.cfg</code> beheben, wobei <OpenSSL-Verzeichnis> durch den entsprechenden Installationspfad (typischerweise <code>c:\OpenSSL-Win32</code>) zu ersetzen ist.<br />
# Das Verzeichnis ''.alexa'' anlegen, ''und zwar im Benutzerverzeichnis desjenigen Benutzers, unter dem Alexa-Fhem laufen soll.'' In aktuellen Versionen von Windows (ab Windows 7 bzw. ab Windows Server 2008 R2) liegt das Verzeichnis unter <code>C:\Users\<Benutzername></code>, also z.B. für Benutzer "Administrator" - unter <code>C:\Users\Administrator</code>.<br/>Falls Windows sich weigert das Verzichniss mit dem Punkt am Anfang zu erstellen, kann man das aus der Kommandozeile machen:<syntaxhighlight lang="bash" style="width:50%;">cd "C:\Users\<Benutzername>"</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;"><br />
mkdir ".alexa"</syntaxhighlight><br />
# Die Datei ''config-sample.json'' nach ''C:\Users\<Benutzername>\.alexa\config.json'' kopieren.<br />
# Achtung: Ggf. müssen auch die Dateien key.pem und cert.pem ins entsprechende Verzeichnis (<code>"<FHEM-Hauptverzeichis>\alexa-fhem\bin</code>) kopiert werden.<br />
<br />
====Update====<br />
Hier wir das Update auf eine neue Version von Alexa-Fhem beschrieben<br />
===== Linux =====<br />
# Das Verzeichnis ''alexa-fhem'' im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) umbenennen in ''alexa-fhem.old''.<br />
# Die tgz-Datei der neuen Alexa-Fhem-Version unter Linux im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) entpacken (''nicht'' unter Windows, das zerstört die Rechteeinstellungen).<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen, in das Verzeichnis wechseln<br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren (kein sudo!).<br />
# Die Zertifikatsdateien key.pem und cert.pem aus dem alten Verzeichnis ''alexa-fhem.old'' ins neue Verzeichnis ''alexa-fhem'' kopieren.<br />
Natürlich dann den Dienst neu starten, auch müssen selbstredend irgendwelche Modifikationen an der Datei server.js in der neuen Version nachgezogen werden. Wenn alles läuft, kann das alte Verzeichnis ''alexa-fhem.old'' gelöscht werden.<br />
===== Windows =====<br />
# Das Verzeichnis ''alexa-fhem'' im Hauptverzeichnis von FHEM (z.B. <code>С:\Program Files (x86)\fhem</code>) umbenennen in ''alexa-fhem.old''.<br />
# Die tgz-Datei der neuen Alexa-Fhem-Version im Hauptverzeichnis von FHEM entpacken.<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen<br />
# Windows-Shell (Kommandozeile, Eingabeaufforderung usw.) öffnen. "Start" -> "Ausführen" (oder [Windows-Taste]+[R]) -> cmd -> Ok. Durch <syntaxhighlight lang="bash" style="width:50%;">cd "<FHEM-Hauptverzeichis>\alexa-fhem"</syntaxhighlight> in das Verzeichnis wechseln. <br/>Dabei ist natürlich das <FHEM-Hauptverzeichis> durch den entsprechenden Pfad aus dem Schritt 1 zu ersetzen. Im o.g. Beispiel wäre es <code>cd "С:\Program Files (x86)\fhem\alexa-fhem"</code><br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren.<br />
# Die Zertifikatsdateien key.pem und cert.pem aus dem alten Verzeichnis ''alexa-fhem.old'' ins neue Verzeichnis ''alexa-fhem'' kopieren.<br />
Natürlich dann den Dienst neu starten, auch müssen selbstredend irgendwelche Modifikationen an der Datei server.js in der neuen Version nachgezogen werden. Wenn alles läuft, kann das alte Verzeichnis ''alexa-fhem.old'' gelöscht werden.<br />
<br />
==== Alexa-Fhem konfigurieren ====<br />
Der Inhalt der Datei ''~/.alexa/config.json'' muss an die eigene Umgebung angepasst werden. <br />
# ''nat-pmp'' -> wenn nat-pmp verwendet werden soll: die ip des eigenen routers,<br />
# ''nat-upnp'' -> wenn nat-upnp verwendet werden soll: ''true'',<br />
# ''applicationId'' <br />
#:* Wenn man nur den SmartHome-Skill verwenden möchte, kann dieser Eintrag leer bleiben.<br />
#:* Ansonsten ist er mit der SkillID des Alexa Custom Skills zu belegen, siehe Abschnitt [[#Skill_Id_bestimmen | Skill Id bestimmen]]<br />
# ''oauthClientID'' -> ''Client ID'' dem Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
# ''server'' -> IP-Adresse des eigenen FHEM-Servers<br />
# ''port'' -> Portnummer des eigenen FHEM-Servers<br />
Beispiel:<br />
{<br />
"alexa": {<br />
"name": "Alexa TEST",<br />
"keyFile": "./key.pem",<br />
"certFile": "./cert.pem",<br />
"applicationId": "amzn1.ask.skill.xxxxxxxxxxxxxxxxxxxxxxxxxxxx",<br />
"oauthClientID": "amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"<br />
},<br />
"connections": [<br />
{<br />
"name": "FHEM",<br />
"server": "192.168.0.xxx.xxx",<br />
"port": "8083",<br />
"filter": "room=AlexaRoom"<br />
}<br />
]<br />
}<br />
<br />
Mehrere Custom Skills lassen sich mit der folgenden Syntax eintragen<br />
"applicationId": [ "amzn1.ask.skill.1" , "amzn1.ask.skill.2" ],<br />
"oauthClientID": [ "amzn1.application-oa2-client.1" , "amzn1.application-oa2-client.1" ]<br />
<br />
Danach durch Aufruf von <syntaxhighlight lang="bash" style="width:50%;">./bin/alexa</syntaxhighlight> den Dienst starten (kein sudo!)<br />
<br />
<br />
Unter Windows startet man Alexa-Dienst durch <syntaxhighlight lang="bash" style="width:50%;">node alexa</syntaxhighlight> aus der <code>alex-fhem/bin</code> (also erst z.B. durch <code>cd "<FHEM-Hauptverzeichis>\alexa-fhem\bin"</code> ins richtige Verzeichnis kommen)<br />
<br />
Der Start des Alexa-Dienstes auf der Console ist immer dann zu empfehlen, wenn man auf die Ausgaben des Dienstes angewiesen ist und beispielsweise sehen möchte, welche Devices durch den Dienst bereitgestellt werden oder ob Fehler auftreten. Beendet man die Console-Session wird auch der Dienst wieder beendet. Insofern ist die vorgenannte Vorgehensweise nur für ein Debugging zu empfehlen und nicht im Regelbetrieb. Nachfolgend ist beschrieben, wie man den Alexa-Dienst aus FHEM heraus starten / stoppen und neu starten kann.<br />
<br />
==== Alexa-Fhem aus FHEM heraus starten ====<br />
Zunächst das Start-up-Skript aus diesem Post herunterladen {{Link2Forum|Topic=60244|Message=517271|LinkText=https://forum.fhem.de/index.php/topic,60244.msg517271.html#msg517271}} und unter /etc/init.d/alexa speichern.<br />
<br />
Das Script geht davon aus, das der alexa-fhem script unter /opt/fhem/alexa-fhem liegt, und die logfiles später unter /opt/fhem/log. Sollte das nicht der Fall sein, muss das Skript angepasst werden.<br />
<br />
Nun folgende Kommandos ausführen:<br />
<syntaxhighlight lang="bash" style="width:50%;">sudo chmod 755 /etc/init.d/alexa<br />
sudo update-rc.d alexa defaults</syntaxhighlight><br />
<br />
In der Datei <code>/etc/sudoers</code> den User fhem für die Nutzung von sudo zulassen (<code>sudo nano /etc/sudoers</code>), z.B. durch Anfügen der nachfolgenden Zeile:<br />
<code>fhem ALL=(ALL) NOPASSWD: ALL</code><br />
<br />
Nun folgende Devices anlegen (ggf. einem Raum zuordnen, z.B. AlexaControl):<br />
<syntaxhighlight lang="bash" style="width:75%;">define FHEM.Alexa.Status dummy<br />
<br />
define FHEM.Alexa dummy<br />
attr FHEM.Alexa event-on-change-reading state<br />
attr FHEM.Alexa webCmd status:start:stop:restart<br />
<br />
define FHEM.Alexa.DOIF DOIF ([FHEM.Alexa] eq "start") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa start > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "stop")<br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa stop > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "restart") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa restart > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "status") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa status > /dev/null 2>&1 &")})</syntaxhighlight><br />
<br />
==== Alexa-Fhem als Service (systemd) installieren ====<br />
Auf neueren Installationen (z.B. RPi Jessie) wird init.d durch systemd ersetzt. Folgend die Anleitung um alexa-fhem als Service zu installieren auf einem Raspberry Pi mit Jessie.<br />
<br />
Zunächst einen neuen Benutzer anlegen unter dem alexa-fhem laufen soll, falls man nicht möchtet dass alexa-fhem z.B. mit dem fhem User ausgeführt wird:<br />
<br />
<code lang="bash" style="width:75%;"><br />
sudo useradd -M --system alexa<br />
</code><br />
<br />
Eigentlich braucht der Benutzer keine Gruppen, aber man kann den Benutzer auch der Gruppe <code>dialout</code> hinzufügen (<code>sudo usermod -a -G dialout alexa</code>)<br />
<br />
Datei "alexa.service" unter <code>/etc/systemd/system</code> anlegen:<br />
<br />
[Unit]<br />
Description=Node.js Alexa Server <br />
After=syslog.target network-online.target<br />
<br />
[Service]<br />
Type=simple<br />
User=alexa <br />
WorkingDirectory=/opt/alexa/alexa-fhem<br />
ExecStart=/opt/fhem/alexa-fhem/bin/alexa -U /home/alexa/.alexa<br />
Restart=on-failure<br />
RestartSec=10<br />
KillMode=process<br />
<br />
[Install]<br />
WantedBy=multi-user.target <br />
<br />
Den Pfad <code>/home/alexa/.alexa</code> an die Systemgegebenheiten anpassen. Letztendlich kann die config.json irgendwo liegen, hauptsache alexa-fhem weiß wo. <code><Homeverzeichnis des "User=">/.alexa</code> empfholen. <br />
<br />
Im WorkingDirectory wird der alexa Dienst die Zertifikate suchen.<br />
<br />
Achtung: Natürlich muss der Benutzer auch Zugriff auf das Verzeichnis mit der config als auch das alexa-fhem Verzeichnis und das WorkingDirectory haben.<br />
<br />
Um den Service zu aktiveren und zu starten helfen folgende Befehle:<br />
sudo systemctl daemon-reload<br />
sudo systemctl enable alexa<br />
sudo systemctl start alexa<br />
<br />
Status abfragen mit<br />
sudo systemctl status alexa<br />
<br />
Log einsehen?<br />
sudo journalctl -u alexa<br />
<br />
(mit <code>-f</code> kann man den follow Modus aktivieren, wie <code>tail -f</code>).<br />
Bei einen reboot startet alexa-fhem jetzt automatisch.<br />
<br />
==== Alexa-Fhem testen ====<br />
Node.Js stellt einen Web-Server am Port 3000 bereit, das oben erzeugte Zertifikat sichert diesen Zugang per SSL ab. Durch Aufruf der Adresse<br />
<code>https://<IP-Adresse des Servers>:3000</code> kann man testen, ob der Alexa-Fhem Service läuft - der Seitenaufruf liefert eine Zeile JSON-Code, beginnend mit<br />
<code>{"header":{"name":"UnsupportedOperationError"...</code><br />
<br />
=== Alexa Device anlegen ===<br />
<br />
Das Modul 39_alexa.pm stellt innerhalb von FHEM verschiedene Attribute z.B. alexaName oder alexaRoom zur Verfügung. Manche dieser Attribute (wie z.b. alexaName) werden in beiden Skills verwendet, andere werden ausschließlich bei einer Nutzung des Alexa Custom Skill verwendet.<br />
<br />
Die Einrichtung des Alexa Device geschieht durch die nachfolgende Definition:<br />
<syntaxhighlight lang="bash" style="width:70%;">define MyAlexa alexa</syntaxhighlight><br />
<br />
<hr><br />
<br />
=== Alexa Skills ===<br />
Für folgende Schritte muss man unter der Adresse http://developer.amazon.com angemeldet sein<br />
# Anmeldung auswählen<br />[[Datei:Developer.amazon.com-01-login2.png|200px]]<br />
# Anmeldedaten eingeben<br />[[Datei:Developer.amazon.com-02-userpass2.png|200px]]<br />
<br />
==== Security Profile anlegen ====<br />
Die Erzeugung eines Sicherheitsprofils muss nur einmal erfolgen, es wird dann für alle weiteren Skills verwendet.<br />
# Nach der Anmeldung Auswahl von ''APPS & SERVICES''<br />[[Datei:Developer.amazon.com-03-apps_and_services.png|200px]]<br />
# Anschließend auswählen ''Security Profiles''<br />[[Datei:Developer.amazon.com-05-apps_and_services_-_security_profiles.png|200px]]<br />
# Auswählen ''Create a New Security Profile'' aus<br />[[Datei:Developer.amazon.com-06-apps_and_services_-_create_a_new_security_profile.png|200px]]<br />
# Dann einen Namen und eine Beschreibung für das Profil eingeben und mit ''Save'' bestätigen<br />[[Datei:Developer.amazon.com-07-apps_and_services_-_security_profile_management.png|200px]]<br />
<br />
===== Login with Amazon =====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Hier wird beschrieben, wo ''Client Id'' und ''Client Secret'' zu finden sind}}<br />
# Oben rechts auf ''Login with Amazon'' klicken.<br/>[[Datei:Developer.amazon.com-08-login_with_amazon.png|200px]]<br />
# Auf der neu geladenen Seite auswählen ''Sign up''<br/>[[Datei:Developer.amazon.com-09-login_with_amazon_-_sign_up.png|200px]]<br />
# Anschließend im Dropdown Menü das vorher angelegte Profil auswählen und mit ''Confirm'' bestätigen<br/>[[Datei:Developer.amazon.com-10-login_with_amazon_-_create_new_profile.png|200px]] [[Datei:Developer.amazon.com-11-login_with_amazon_-_create_new_profile2.png|200px]]<br />
# Im folgenden Fenster die Adresse [https://www.amazon.com/gp/help/customer/display.html?nodeId=468496 https://www.amazon.com/gp/help/customer/display.html?nodeId=468496] eingeben und mit ''Save'' bestätigen. '''Todo Erklärungsbedarf: WARUM diese Adresse'''<br/>[[Datei:Developer.amazon.com-12-login_with_amazon_-_enter_consent_screen_information.png|200px]]<br />
# Anschließend bei dem neu angelegten Eintrag auf der rechten Seite auf das Zahnrad klicken und ''Web Settings'' auswählen<br/>[[Datei:Developer.amazon.com-13-login_with_amazon_-_web_settings.png|200px]]<br />
# Im neu geladenen Fenster anklicken von ''Edit''<br/>[[Datei:Developer.amazon.com-14-login_with_amazon_-_edit.png|200px]]<br />
# Anschließend bei ''Allowed Return URLs'' die folgenden drei Adressen eingeben. ''xxx'' muss hierbei durch den Wert ersetzt werden, der in den beiden Abschnitten [[#SmartHome_Skill_anlegen | SmartHome Skill anlegen]] bzw. [[#Custom_Skill_anlegen | Custom Skill anlegen]] jeweils unter Punkt 4 (Seite ''Configuration'') bei ''Redirect Urls'' am Ende der URLs angezeigt wird<br />
## [https://layla.amazon.co.uk/api/skill/link/xxx https://layla.amazon.co.uk/api/skill/link/xxx]<br />
## [https://pitangui.amazon.com/api/skill/link/xxx https://pitangui.amazon.com/api/skill/link/xxx]<br />
## [https://layla.amazon.com/api/skill/link/xxx https://layla.amazon.com/api/skill/link/xxx]<br />
.<br/>[[Datei:Developer.amazon.com-15-login_with_amazon_-_allowed_return_urls.png|200px]]<br />
<br />
==== Skills bearbeiten ====<br />
# Im Menü den Punkt ''ALEXA'' auswählen<br />[[Datei:Developer.amazon.com-03-apps_and_services.png|200px]]<br />
# Anschließend im Feld ''Alexa Skills Kit'' auf ''Get started'' klicken<br />[[Datei:Developer.amazon.com-17-alexa_-_alex_skills_kit_-_get_started.png|200px]]<br />
<br />
===== SmartHome Skill anlegen =====<br />
# Oben rechts ''Add a New Skill'' auswählen<br />[[Datei:Developer.amazon.com-18-alexa_-_alex_skills_kit_-_add_a_new_skill.png|200px]]<br />
# Auf der folgenden Seite eingeben und dann mit ''Next'' bestätigen:<br />
#:* ''Skill Type'' -> ''SmartHome Skill API'' <br />
#:* ''Language'' -> ''German''<br />
#:* ''Name'' -> beliebiger Name, z.B. "MySmartHome Basic")<br />
#:* ''Payload Version'' -> ''v2 (other devices)'' <br/>[[Datei:Developer.amazon.com-19-alexa_-_alex_skills_kit_-_skill_information.png|200px]]<br />
# Die folgende Seite einfach mit ''Next'' überspringen<br />[[Datei:Developer.amazon.com-20-alexa_-_alex_skills_kit_-_interaction_model.png|200px]]<br />
# Auf der Seite ''Configuration'' Folgendes eingeben:<br />
#:* ''Service Endpoint Type'' -> ''AWS Lambda'' ist vorausgewählt und kann nicht geändert werden.<br />
#:* ''Geographical Region'' -> ''Europe'' auswählen und im Textfeld die ARN aus Abschnitt [[#ARN_der_AWS_Lambda_Funktion_bestimmen | AWS Lambda Funktion]] eintragen. <br />
#:* ''Authorization URL'' -> <code>https://www.amazon.com/ap/oa</code><br />
#:* ''Client ID'' -> ''Client ID'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
#:* ''Scope'' -> <code>profile:user_id</code> (wörtlich 1:1 eintragen)<br />
#:* ''Redirect URLs'' - sollten vorbelegt sein<br />
#:* ''Authorization Grant Type'' -> ''Auth Code Grant'' auswählen<br />
#:* ''Access Token URI'' -> <code>https://api.amazon.com/auth/o2/token</code><br />
#:* ''Client Secret'' -> ''Client Secret'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
#:* ''Client Authentication Scheme'' -> ''HTTP Basic''<br />
#:* ''Privacy Policy URL'' -> <code>https://www.amazon.com/gp/help/customer/display.html?nodeId=468496</code><br /><br /><br />
<br />[[Datei:Developer.amazon.com-21-alexa_-_alex_skills_kit_-_configuration.png|200px]] [[Datei:Developer.amazon.com-22-alexa_-_alex_skills_kit_-_test.png|200px]]<br />
<br />
===== Custom Skill anlegen =====<br />
<ol><br />
<li> Oben rechts ''Add a New Skill'' auswählen<br />[[Datei:Developer.amazon.com-18-alexa_-_alex_skills_kit_-_add_a_new_skill.png|200px]]</li><br />
<li> Auf der folgenden Seite (''Skill Information'') die nachstehenden Daten eingeben und dann mit ''Next'' bestätigen:<br />
<ul><br />
<li> ''Skill Type'' -> ''Custom Interaction Model'' </li><br />
<li> ''Language'' -> ''German''</li><br />
<li> ''Name'' -> beliebiger Name, z.B. "MySmartHome Advanced". Dieser wird in der Alexa App unter "Meine Skills" angezeigt.</li><br />
<li> ''Invocation Name'' -> Aufruf des Skills, unter dem dieser später gestartet wird. Z.B. "Alexa, starte James"<br />[[Datei:CustomSkill_2.PNG|400px]]</li><br />
</ul></li><br />
<li>Auf der Seite ''Interaction Model'' folgende Eingaben tätigen und mit ''Next'' abschließen<br />
<ul><br />
<li>In einem separaten Browserfenster FHEM aufrufen, und für das bereits definierte Alexa-Gerät das Kommando <code>get MyAlexa interactionModel</code> aufrufen. Es erscheint ein Popup-Fenster mit ziemlich vielen Zeilen.<br />
<li>In die Box ''Intent Schema'' kopiert man den ersten Teil dieser FHEM-Ausgabe hinein, also:<br/><blockquote><br />
{ <br />
"intents" : [ <br />
<hier ziemlich viele Zeilen> <br />
]<br />
}<br />
</blockquote></li><br />
<li>Nun die ''Custom Slot Types'' einrichten. Dazu muss aus dem zweiten Teil der FHEM-Ausgabe jeweils der Slot-Type (z.B. <code>FHEM_article</code>) in das Feld ''TYPE'' eingetragen werden, das nach dem Anklicken von ''Add Slot Type'' erscheint. In das darunter liegende größere Textfeld kommen die möglichen Werte für diesen Slot, so wie sie aus der FHEM-Ausgabe abzulesen sind. Dann mit ''Save'' sichern. Als Custom Slot Type erscheint dann für diesen Beispiel-Slot<br />
FHEM_article der | die | das | den<br />
d.h., die Zeilenumbrüche bei den möglichen Werten werden als "|" dargestellt.</li><br />
<li>Hier muss nun ein Bruch im Arbeitsfluss durchgeführt werden, denn bei der Erstellung des Custom Skills kommt es auf die Reihenfolge der Einträge an. Deshalb zunächst diese FHEM-Ausgabe schließen, und für dasselbe FHEM-Device <code>get MyAlexa customSlotTypes</code> ausführen. Auch diese Ausgabe wird, wie oben beschriebeen, in Custom Slot Types eingetragen (erst der TYPE, dann die möglichen Werte)<br />
<li>Anschließend erneut die FHEM-Ausgabe schließen und erneut für das bereits definierte Alexa-Gerät das Kommando <code>get MyAlexa interactionModel</code> aufrufen.<br />
<li>Unter ''Sample Utterances'' nun den Text aus dem dritten Teil dieser FHEM-Ausgabe hineinkopieren<br />[[Datei:CustomSkill_5.PNG|400px]]</li><br />
</ul></li><br />
<li>Auf der Seite ''Configuration'' Folgendes eingeben und mit ''Next'' bestätigen:<br />
<ul><br />
<li>''Service Endpoint Type'' -> ''AWS Lambda'' auswählen</li><br />
<li>''Geographical Region'' -> ''Europe'' auswählen und im Textfeld den Wert aus Abschnitt [[#AWS_Lambda_Funktion_anlegen | AWS Lambda Funktion anlegen]] (Punkt 12) eintragen. </li><br />
<li>''Do you allow users to create an account or link to an existing account with you?'' -> ''Yes''</li><br />
<li>''Authorization URL'' -> <code>https://www.amazon.com/ap/oa</code></li><br />
<li>''Client ID'' -> ''Client ID'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1</li><br />
<li>''Scope'' -> <code>profile:user_id</code> (wörtlich 1:1 eintragen)</li><br />
<li>''Redirect URLs'' - sollten vorbelegt sein</li><br />
<li>''Authorization Grant Type'' -> ''Auth Code Grant'' auswählen</li><br />
<li>''Access Token URI'' -> <code>https://api.amazon.com/auth/o2/token</code></li><br />
<li>''Client Secret'' -> ''Client Secret'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1</li><br />
<li>''Client Authentication Scheme'' -> ''HTTP Basic''</li><br />
<li>''Privacy Policy URL'' -> <code>https://www.amazon.com/gp/help/customer/display.html?nodeId=468496</code></li><br />
</ul><br />
Beim Sichern dieser Seite mit ''Next'' kann es zu einer Fehlermeldung kommen, wenn man seine Skill-Definitionen mit dem einfachen SmartHome-Skill begonnen hat. Deshalb muss noch der entsprechende Trigger für die [[#AWS_Lambda-Funktion | AWS Lambda Funktion]] nachgetragen werden, dies wird in Abschnitt [[#Trigger_f.C3.BCr_Custom_Skill_hinzuf.C3.BCgen | Trigger für Custom Skill hinzufügen]] beschrieben.<br />
<br />[[Datei:CustomSkill_6.PNG|400px]] [[Datei:CustomSkill_7.PNG|400px]]</li><br />
<br />
==== Testen ====<br />
Hat man den Custom Skill angelegt, bietet dieser auch eine komfortable Testmöglichkeit. Dazu wählt man in der Übersichtsseite ''All Skills'' den Button ''Edit'' des Alexa Custom Skill aus. Auf der nachfolgenden Seite dann links ''Test''. <br />
Die Testseite enthält <br />
* ein Feld ''Voice Simulator'', mit dem man die Sprachsausgabe testen kann, <br />
* ein Feld ''Service Simulator'', mit dem die Verarbeitung von Alexa-Kommandois getestet werden kann. Hier kann man z.B. eintragen<br />
"Alexa, sage <Custom Skill Invocation Name>: Stelle Weckzeit auf Neunzehn Siebenundzwanzig Uhr"<br />
"Alexa, frage <Custom Skill Invocation Name> nach dem Status von Weckzeit"<br />
Dabei ist natürlich der ''Custom Skill Invocation Name'' durch den Wert zu ersetzen, den man im Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]] unter Punkt 2 eingetragen hat.<br />
<br />
==== Skill Id bestimmen ====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Hier wird beschrieben, wo die ''Alexa Skill Id'' zu finden ist}}<br />
Für das [[#AWS_Lamba_Funktion_anlegen | Anlegen einer ''AWS Lambda Funktion'']] bzw für die [[#Alexa-Fhem_konfigurieren | Konfiguration von Alexa-Fhem]] wird die ''Alexa Skill Id'' benötigt. An diese kommt man wie folgt:<br />
# Anmelden wie unter [[#Alexa_Skills | Alexa Skills]] beschrieben.<br />
# Menüpunkt ''ALEXA'' auswählen, wie [[#Skills_bearbeiten | Skills bearbeiten]] erklärt.<br />
# Beim gewünschten Eintrag auf ''Edit'' klicken<br />[[Datei:Developer.amazon.com-23-alexa_-_alex_skills_kit_-_overview.png|200px]]<br />
# Die Id, die nun oben angezeigt wird, ist die gesuchte. Sie hat typischerweise das Format <code>amzn1.ask.skill.[Zahlen und Bindestriche]</code><br />[[Datei:Aws.amazon.com-06-configure_triggers2.png|200px]]<br />
<br />
<hr><br />
<br />
=== AWS Lambda Funktion ===<br />
Für folgende Schritte muss man unter der Adresse http://aws.amazon.com angemeldet sein<br />
# Anmeldung auswählen<br />[[Datei:Aws.amazon.com-01-site.png|200px]]<br />
# Anmeldedaten eingeben<br />[[Datei:Aws.amazon.com-02-login.png|200px]]<br />
# Den Punkt ''Lambda'' links auf der Startseite auswählen, bzw. im Menü ''Services'' unter ''Compute'' den Menüpunkt ''Lambda'' auswählen<br />[[Datei:Aws.amazon.com-03-lambda.png|200px]]<br />
==== AWS Lambda Funktion anlegen ====<br />
# Für eine erste Lambda-Funktion den Punkt ''Get Started Now'' auswählen<br />[[Datei:Aws.amazon.com-04-get_started_now.png|200px]]<br />
# Den Blueprint ''Blank function'' auswählen<br />[[Datei:Aws.amazon.com-05-select_blueprint.png|200px]]<br />
# Im neuen Fenster dann auf den gestrichelten Kasten klicken und ''Alexa Smart Home'' auswählen und mit ''Next'' bestätigen<br />[[Datei:Aws.amazon.com-06-configure_triggers1.png|200px]]<br />
## Achtung, es ist möglich, dass dabei ''Alexa Smart Home'' überhaupt nicht angeboten wird. Dann bitte ganz rechts oben in der Ecke nachsehen, welche Region bzw. welches Land ausgewählt ist. Empfohlen wird, ''Ireland'' auszuwählen. Dann erscheint bei den Funktionen auch ''Alexa Smart Home''.<br />
# Bei ''Application Id'' den Wert eintragen, dessen Ermittlung im Abschnitt [[#Skill_Id_bestimmen | Skill Id bestimmen]] beschrieben wird, den Haken bei ''Enable trigger'' setzen und mit ''Next'' bestätigen <br />[[Datei:Aws.amazon.com-06-configure_triggers3.png|200px]]<br />
# Auf der Konfigurationsseite eingeben:<br />
## ''Name'' -> ''FHEM''<br />
## ''Runtime'' -> Node.js 4.3. <br />
## ''Role'' -> ''Choose an existing role'' <br />
### Achtung: wenn es noch keine existing role gibt, zuerst ''Create a custom role'' -> in dem Popup dann ''lambda_basic_execution'' auswählen und auf ''Allow'' klicken sowie bei ''Existing role'' dann ''x'' wählen.<br />
# Auf der Code-Seite wird bzw. im großen Textfeld ist dann der Code aus der Datei ''lambda.js'' im Paket [[#Alexa-Fhem_installieren | Alexa-Fhem]] vollständig einzufügen. Dabei muss noch der Hostname im Quellcode an den eigenen Hostnamen angepasst werden. <br />
# Anschließend alles mit ''Next'' bestätigen.<br />[[Datei:Aws.amazon.com-07-configure_function.png|200px]]<br />
# Auf der Übersichtsseite dann ''Create function'' anklicken<br />[[Datei:Aws.amazon.com-08-review.png|200px]]<br />
<br />
==== Trigger für Custom Skill hinzufügen ====<br />
Editiert man eine Lambda-Funktion, werden auf der Seite ''Triggers'' diejenigen Dienste angezeigt, die diese Funktion aufrufen.<br />
* Hier taucht der Trigger ''Alexa Smart Home'' zusammen mit der ''Application Id'' auf, der bei der Einrichtung des SmartHome-Skills eingetragen wurde.<br />
* Zur Verbindung mit dem Custom Skill ist es nötig, einen zweiten Trigger hinzuzufügen. Durch Anklicken von ''Add Trigger'' wird eine Auswahlseite eingeblendet. Im neuen Fenster dann auf den gestrichelten Kasten klicken und ''Alexa Skills Kit' auswählen und mit ''Next'' bestätigen<br />
<br />
==== ARN der AWS Lambda Funktion bestimmen ====<br />
# Auf der Übersichtsseite oben links den Menüpunkt ''Functions'' aúswählen<br />[[Datei:Aws.amazon.com-09-go_overview.png|200px]]<br />
# Anschließend den Radiobutton der angelegten Funktion ''FHEM'' markieren und im Menü ''Action'' den Punkt ''Show ARN'' auswählen<br />[[Datei:Aws.amazon.com-10-1-show_arn.png|200px]]<br />
# Es wird nun eine ARN Adresse angezeigt, die für den Abschnitt [[#SmartHome_Skill_anlegen| SmartHome Skill anlegen]] benötigt wird<br />[[Datei:Aws.amazon.com-10-2-arn.png|200px]]<br />
<br />
=== Absichern des Zugriffs ===<br />
Natürlich muss der Zugriff auf den von Alexa-Fhem verwendeten Port (default: 3000, Bestandteil des Codes in der AWS Lambda-Funktion) durch die Firewall freigeschaltet werden (auf einer FritzBox unter "Portfreigaben").<br />
<br />
==== Absicherung direkt in Alexa-FHEM ====<br />
Die Kommunikation zwischen Amazon AWS und Alexa-FHEM ist auf die folgenden Arten gesichert:<br />
* Die Verbindung erfolgt per HTTPS<br />
* Es werden nur Verbindung angenommen auf denen ein gültiges Alexa-Event gesendet wird. <br />
* Es werden nur Verbindungen angenommen die ein gültiges und noch nicht abgelaufenes OAuth-Token enthalten. Jedes neue Token wird live bei Amazon auf Gültigkeit geprüft. <br />
* Es werden nur Verbindungen mit lokal konfigurierter Skill-ID angenommen.<br />
* Es ist nicht möglich von außen beliebige FHEM Kommandos zu senden. Die FHEM Kommandos werden nur lokal erzeugt.<br />
<br />
Wer möchte kann Alexa-FHEM natürlich noch weiter absichern. Es gilt aber, dass nicht jedes zusätzliche Glied in der Kette die Sicherheit sondern unter Umständen nur die Angriffsfläche erhöht. Ein falsch konfigurierter und nach aussen offener Apache (oder anderer ReverseProxy) ist unter Umständen ein größeres Risiko als Alexa-FHEM alleine.<br />
<br />
==== Absicherung per ReverseProxy ====<br />
<s>Die Kommunikation zwischen Amazon und FHEM ist wegen der Verwendung von SSL schon verschlüsselt - prinzipiell kann aber jeder von außen mit Alexa-Fhem kommunizieren. Man sollte sich deshalb im Klaren darüber sein, dass dies eine Sicherheitslücke darstellt:</s> Jeder offene Port verleitet zu Angriffen, und mit zunehmender Verbreitung von Alexa steigt auch das Risiko. Es wird deshalb empfohlen, vor den eigentlichen Alexa-Server zur Absicherung einen Apache-Webserver als ReverseProxy zu setzen. Nicht nur ist der Apache eine hervorragend stabile und seit Jahrzehnten getestete Software, sondern die Konfiguration als ReverseProxy erlaubt auch, den Zugriff auf den Alexa-Fhem-Rechner auf die Amazon-Maschinen zu beschränken.<br />
<br />
'''Achtung: Dies ist keine allgemeine Anleitung in Sachen Computersicherheit.''' Im Folgenden gehen wir davon aus, dass <br />
* Grundbegriffe wie Firewall, IP-Ports, SSL und Dynamic DNS vertraut sind<br />
* Ein Apache Webserver (idealerweise auf einer zweiten Maschine) bereits installiert ist und die Konfiguration verstanden wurde (wenn nicht: Es gibt im Netz ''tausende'' von Anleitungen dafür...)<br />
* Ein Servername von einem DynDNS-Anbieter - sagen wir ''myhome.is-my-castle.com'' - bereits von ''außen'' auf unser SmartHome zeigt.<br />
* Alexa-Fhem in einer der oben beschriebenen Basiskonfigurationen läuft, d.h. der Zugriff auf <code>https://myhome.is-my-castle.com:3000</code> ergibt, wie im Punkt [[#Alexa-Fhem_testen|Alexa-Fhem testen]] beschrieben, eine Antwort des Node.js Servers.<br />
<br />
Als erster Schritt zur Absicherung muss das ReverseProxy Modul für den Apache installiert und mit <code>a2enmod</code> aktiviert werden, hierzu sei auf [https://www.digitalocean.com/community/tutorials/how-to-use-apache-http-server-as-reverse-proxy-using-mod_proxy-extension diese Anleitung] verwiesen. Der zweite Schritt besteht darin, den SSL-Zugriff durch ein Passwort abzusichern. Dazu wird auf dem Apache-Rechner das Programm <br />
htpasswd <passwdfile> <username><br />
ausgeführt, das Programm fragt dann nach dem gewünschten Passwort. Wir nehmen im Folgenden an, dass das Passwortfile ''/etc/apache2/htpasswd'' ist, der gesetzte Username ''alexa'' lautet und das Passwort ''my_smarthome'' ist.<br />
<br />
Im dritten Schritt wird nun in das Apache-Konfigurationsfile die Weiterleitung auf den eigentlichen Alexa-Fhem-Rechner eingetragen. Dazu wählen wir, dass von außen der Standard-SSL-Port 443 benutzt werden soll, sowie als Verzeichnisname ''/alexa''. '''Achtung:''' Dieser Code soll '''nicht''' in die Default-Konfiguration des Apache-Webservers. Sondern in eine separate Datei (Dateiname z.B. "fhem"), die ins Unterverzeichnis /etc/apache2/conf.d gestellt wird.<br />
<br />
<VirtualHost *:443><br />
ServerName myhome.is-my-castle.com<br />
SSLEngine on<br />
SSLProxyEngine on<br />
SSLProxyCheckPeerCN off<br />
SSLProxyCheckPeerName off<br />
SSLCertificateKeyFile /etc/apache2/mycert/server.key<br />
SSLCertificateFile /etc/apache2/mycert/server.crt<br />
<Location /alexa><br />
AuthType Basic<br />
AuthName "Authentication Required"<br />
AuthUserFile "/etc/apache2/htpasswd"<br />
Require valid-user<br />
ProxyPass https://<hier IP-Adresse des Alexa-Fhem-Rechners>:3000/<br />
ProxyPassReverse https://<hier IP-Adresse des Alexa-Fhem-Rechners>:3000/<br />
Order deny,allow<br />
Allow from All<br />
</Location><br />
(... Hier eventuell weitere Umleitungen)<br />
</VirtualHost><br />
Nach einem Neustart des Apache-Servers, dem Schließen des Ports 3000 in der Firewall sowie dem Öffnen des Ports 443 ist der Alexa-Fhem-Rechner von außen nur noch erreichbar durch den Aufruf von <code>https://myhome.is-my-castle.com/alexa</code> und verlangt unmittelbar die Eingabe von Username und Passwort.<br />
<br />
Der vierte Schritt ist nun, den Code der AWS Lambda-Funktion an fünf Stellen zu verändern<br />
'''const PORT=443;'''<br />
const HOST='myhome.is-my-castle.com';<br />
'''const PATH='/alexa';'''<br />
'''const AUTH='alexa:my_smarthome';'''<br />
// entry<br />
exports.handler = function(event, context, callback) {<br />
console.log(`EVENT: ${event}`);<br />
console.log(`CONTEXT: ${context}`); <br />
var post_data = JSON.stringify(event);<br />
var options = {<br />
hostname: HOST,<br />
port: PORT,<br />
//family: 6,<br />
'''path: PATH,'''<br />
method: 'POST',<br />
'''auth: AUTH,'''<br />
rejectUnauthorized: false, // accept self-signed<br />
(etc., Rest des Codes wie gehabt)<br />
Natürlich muss der Zugriff getestet werden. Bei Beachtung aller dieser Schritte werden alle un-autorisierten Zugriffe von außen abgewehrt. Eine noch weiter gehende Sicherung ist möglich, dazu kann in der Serverkonfiguration der Zugriff auf die Amazon-Domains beschränkt werden. Das ganze Alexa-System ist aber noch in konstanter Weiterentwicklung, diese Domain-Namen können sich also noch ändern.<br />
<br />
== Einrichtung in der Alexa App==<br />
Nachdem die Alexa Skills angelegt wurden, müssen diese noch in der Alexa App eingerichtet werden.<br />
Dafür jeweils per Desktop-Browser auf [http://alexa.amazon.de alexa.amazon.de] anmelden, nicht die App unter iOS oder Android verwenden. Diese hat Probleme mit der OAuth Verknüpfung.<br />
<br />
=== Alexa Skill ===<br />
# Auf ''Skills'' klicken<br />[[Datei:Alexa.amazon.de-01-startseite.png|200px]]<br />
# Oben rechts ''Meine Skills'' bzw. ''Ihre Skills'' auswählen<br />[[Datei:Alexa.amazon.de-03-meine_skills.png|200px]]<br />
# In der Liste der Skills sollte das angelegte FHEM Skill angezeigt werden. Dieses anklicken<br />[[Datei:Alexa.amazon.de-02-liste_skills.png|200px]]<br />
# Oben Rechts in den Details des Skills auf ''Skill aktivieren'' klicken<br />[[Datei:Alexa.amazon.de-04-skill_details.png|200px]]<br />
# In dem neu geöffneten Fenster die Autorisierung bestätigen<br />[[Datei:Alexa.amazon.de-05-amazon_auth.png|200px]]<br />
# Anschließend sollte die Verbindung erfolgreich aufgebaut worden sein <br />[[Datei:Alexa.amazon.de-06-success.png|200px]]<br />
<br />
=== Geräte ===<br />
# Auf http://alexa.amazon.de anmelden<br />
# Auf ''Smart Home'' klicken<br />[[Datei:Alexa.amazon.de-01-startseite.png|200px]]<br />
# Anschließend den Punkt ''Geräte suchen'' anklicken<br />[[Datei:Alexa.amazon.de-07-Gerätesuche.png|200px]]<br />
# Wurde soweit alles korrekt eingerichtet, werden nun die gefundenen Geräte angezeigt.<br />
<br />
Tip: Es macht Sinn, unter ''Meine Gruppen'' Gruppen benannt nach den Räumen einzurichten. Hierdurch kann Alexa die Geräte besser auseinander halten, vor allem wenn die den gleichen Alias (z.B. "Licht") haben.<br />
<br />
== Einrichtung unter FHEM ==<br />
Im Folgenden werden exemplarisch ein paar Geräte beschrieben, die man nutzbringend mit FHEM einsetzen kann.<br />
<br />
Bei Verwendung des Custom Skills übersetzt die Kombination der Attribute ''alexaMapping'' und ''homebridgeMapping'' Sprachbefehle ("Intents") in gerätespezifische Kommandos. <br />
* Das Attribut alexaMapping wird am Alexa-Device gesetzt und dient dazu, erkannte Sprachkommandos in abstrakte Characteristiken zu überführen. Für den einfacheren SmartHome Skill hat darum das Attribut ''alexaMapping'' keine Bedeutung, sondern nur der ''genericDeviceType'' des zu steuernden Gerätes.<br />
* Das Attribut homebridgeMapping wird für beide Skills am zu steuernden Gerät gesetzt und übersetzt diese Charakteristiken in die konkreten Befehle, die das Gerät versteht. Der inhalt des Attributs wird von links nach rechts ausgewertet und ist wie folgt aufgebaut:<br />
** Das Attribut enthält eine durch Leerzeichen getrennte Liste aus Konfigurationen für jeweils eine Characteristik<br />
** Jede einzelne der Characteristik-Konfigurationen besteht aus dem Namen der Characteristik, gefolgt von "=" und einer kommaseparierten Liste von Parametern.<br />
attr <device> homebridgeMapping <Characteristic1>=<param1.1>,<param1.2>,... <Characteristic2>=<param2.1>,<param2.2>,...<br />
** Jeder Parameter besteht entweder aus<br />
*** <code><cmd>:<device>:<reading></code>, hier können nicht verwendete Elemente von links nach rechts weg gelassen werden.<br />
*** <code><name>=<value></code>, hier kann <code><value></code> entweder ein Wert oder semikolonseparierte Liste sein.<br />
*** Oder dem schlüsselwort <code>clear</code>, welches alle vorhandenen (default) Parameter dieser Characteristik löscht. <code>clear</code> kann auch an Stelle einer ganzen Characteristik-Konfiguration stehen<br />
Weiter führende Dokumentation zum homebridgeMapping findet sich unter https://forum.fhem.de/index.php/topic,48558.0.html<br />
<br />
=== Einfacher Schalter ===<br />
* Ein einfacher Schalter, der die set-Kommandos ''on'' und ''off'' kennt, kann direkt mit Alexa-Fhem gekoppelt werden <br />
* Für kompliziertere Aktionen, etwa das Übermitteln eines spezifischen Schaltbefehls an FHEM, ist die Einrichtung eines Dummies zu empfehlen. <br />
Ob Dummy oder nicht, wichtig sind die drei fett gedruckten Zeilen<br />
define Alexa.Party dummy<br />
'''attr Alexa.Party alexaName party'''<br />
'''attr Alexa.Party alexaRoom alexaroom'''<br />
'''attr Alexa.Party genericDeviceType switch'''<br />
attr Alexa.Party group AlexaGeräte<br />
attr Alexa.Party room AlexaRoom<br />
'''attr Alexa.Party setList on off'''<br />
Selbstverständlich kann man diesen Dummy mit einem notify oder DOIF abfangen, um die gewünschte Schaltaktion auszuführen. <br />
<br />
Ein Alternative zum Dummy ist das Anlegen eines readingsProxy, dem die entsprechenden Attribute gegeben werden.<br />
<br />
Weil es sich hierbei um eines der einfachen Geräte handelt, die Alexa selbst im SmartHome Skill bearbeiten kann, ist auch der zweite Schritt bei der Einrichtung in der Alexa App sinnvoll: Der Schalter wird dann im Bereich Smart Home der Alexa App erkannt. Wer ihn auch mit dem Custon Skill bedienen möchte, muss natürlich Sorge tragen, dass der Alexa-Name ''party'' bei den FHEM_Devices auftaucht und die entsprechenden weiteren Slot Types und Example Utterances in der Konfiguration des Custom Skills vorhanden sind (siehe Abschnitt [[##Custom_Skill_anlegen | Custom Skill Anlegen]]).<br />
<br />
=== Wecker ===<br />
Dieses Gerät kann man nur mit dem Custom Skill bedienen, es wird also '''nicht''' im Bereich Smart Home der Alexa App auftauchen. Wir richten einen Dummy ein, wichtig sind wieder die fett gedruckten Zeilen:<br />
define Alexa.Weckzeit dummy<br />
'''attr Alexa.Weckzeit alexaName weckzeit'''<br />
'''attr Alexa.Weckzeit alexaRoom alexaroom'''<br />
attr Alexa.Weckzeit genericDeviceType clock<br />
attr Alexa.Weckzeit group AlexaGeräte<br />
'''attr Alexa.Weckzeit homebridgeMapping Weckzeit=state,cmd=+'''<br />
attr Alexa.Weckzeit room AlexaRoom<br />
'''attr Alexa.Weckzeit setList Weckzeit:time'''<br />
Das Attribut ''genericDeviceTye'' ist nicht wichtig, weil es ein generisches Device dieser Art gar nicht gibt. Wichtig hingegen ist das Attribut ''homebridgeMapping'' <br />
<br />
Für das Gerät ''MyAlexa'', das in Abschnitt definiert wurde, muss im Attribut ''alexaMapping'' auftauchen<br />
Weckzeit=verb=stelle,valuePrefix=für;auf,values=AMAZON.TIME,valueSuffix=uhr<br />
Darüber hinaus muss der Alexa-Name ''weckzeit'' bei den FHEM_Devices auftauchen und die entsprechenden weiteren Slot Types und Example Utterances in der Konfiguration des Custom Skills vorhanden sein (siehe Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]]).<br />
<br />
Der Aufruf dieses Gerätes mit Alexa erfolgt dann z.B. mit den Sätzen<br />
<pre style="width:50%;"><br />
"Alexa, sage <Custom Skill Invocation Name>: Stelle Weckzeit auf Neunzehn Uhr Siebenundzwanzig"<br />
"Alexa, frage <Custom Skill Invocation Name> nach dem Status von Weckzeit"<br />
</pre><br />
Dabei ist natürlich der ''Custom Skill Invocation Name'' durch den Wert zu ersetzen, den man im Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]] unter Punkt 2 eingetragen hat.<br />
<br />
Zur weiteren Bearbeitung kann man jetzt mit einem DOIF Statusänderungen des Dummies abfangen und durch eine kleine Helperfunktion ins "echte" FHEM weiterleiten.<br />
define Alexa.Weckzeit.N DOIF (["Alexa.Weckzeit:.*"])({AlexaHelper("Alexa.Weckzeit","$EVENT")}) <br />
Die Helperfunktion (z.B. in 99_myUtils.pm) stellt aus der übergebenen Zeit (immer im Format dd:mm) eine sprachkompatible Nachricht $nc und einen mit den FHEM-Zeitangaben kompatiblen String $nt zusammen und reicht beide an eine Routine ''changeWakeTime'' weiter (dokumentiert in den [https://www.dpunkt.de/buecher/12387/9783960090120-smarthome-hacks.html Smart Home Hacks]).<br />
sub AlexaHelper($$){<br />
my ($name,$event)=@_;<br />
if( $name eq "Alexa.Weckzeit" ){ <br />
my ($nc,$nt);<br />
#-- volle Stunde----------------------------------------<br />
if( $event =~ /(\d+):00/ ){<br />
$nc=sprintf("%d Uhr",$1);<br />
$nt=sprintf("%02d:00:00",$1);<br />
#-- nicht volle Stunde---------------------------------<br />
}elsif( $event =~ /(\d+):(\d+)/ ){<br />
$nc=sprintf("%d Uhr %d",$1,$2);<br />
$nt=sprintf("%02d:%02d:00",$1,$2);<br />
}<br />
changeWakeTime(\'GalaxyTab.EG\',\'$nc\',\'$nt\');<br />
}<br />
}<br />
<br />
<hr><br />
<br />
=== Lichtszene ===<br />
Eine Lichtszene wird mit dem Modul LightScene angelegt. Wir gehen davon aus, dass in der Lichtszene die beiden Szenen Alle_An und Alle_Aus, sowie mindestens eine weitere Szene (hier: Sitzgruppe) definiert wurde.<br />
* Nachfolgend wird ein Beispiel beschrieben, wie man eine Lichtszene mit dem einfachen SmartHome Skill steuern kann. Die verwendeten Kommandos sind dann<br />
<pre><br />
"Alexa, schalte (die) Beleuchtung an" -> LightScene Alle_An wird ausgewählt<br />
"Alexa, schalte (die) Beleuchtungsitzgruppe an" -> LightScene Sitzgruppe wird ausgewählt<br />
...<br />
"Alexa, schalte (die) Beleuchtung aus" -> LightScene Alle_Aus wird ausgewählt<br />
</pre><br />
* Künftig wird man LightScene mit dem Custom Skill eventuell direkt steuern können - allerdings hat das einen geringeren WAF, als die Steuerung über den SmartHome Skill: Der Einschaltsatz muss dann mindestens lauten<br />
<pre><br />
"Alexa, sage <Custom Skill Invocation Name>: schalte (die) Beleuchtung an" -> LightScene Alle_An wird ausgewählt<br />
</pre><br />
Dafür wird es aber auch möglich sein direkt die SzenenNamen im gesprochenen Kommando zu verwenden und so auf die Umwege über dummys und ähnliches zu verzichten.<br />
<br />
<br />
Im ersten Schritt wird ein Dummy für die Gesamtbeleuchtung eingerichtet:<br />
define Alexa.Beleuchtung dummy <br />
attr Beleuchtung setList on off<br />
'''attr Alexa.Beleuchtung alexaName beleuchtung'''<br />
'''attr Alexa.Beleuchtung alexaRoom alexaroom'''<br />
'''attr Alexa.Beleuchtung genericDeviceType switch'''<br />
Anschließend wird für jede vorhandene Lichtszene (außer Alle_An und Alle_Aus) ein weiterer Dummy angelegt:<br />
define Alexa.Beleuchtung.Sitzgruppe dummy <br />
attr Beleuchtung setList on off<br />
'''attr Alexa.Beleuchtung.Sitzgruppe alexaName beleuchtungsitzgruppe'''<br />
'''attr Alexa.Beleuchtung.Sitzgruppe alexaRoom alexaroom'''<br />
'''attr Alexa.Beleuchtung.Sitzgruppe genericDeviceType switch''' <br />
Die eigentliche Steuerung übernimmt dann ein DOIF<br />
define Alexa.Beleuchtung.N DOIF<br />
(["Alexa.Beleuchtung.Sitzgruppe:on"])<br />
(set <devicename der Lichtszene> scene Sitzgruppe,<br />
set Alexa.Beleuchtung off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
DOELSIF<br />
... <weitere on-Events der anderen Szenen werden abgefangen><br />
DOELSEIF<br />
(["Alexa.Beleuchtung:on"])<br />
(set <devicename der Lichtszene> scene Alle_An,<br />
set Alexa.Beleuchtung.Sitzgruppe off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
DOELSEIF<br />
(["Alexa.Beleuchtung:off"])<br />
(set <devicename der Lichtszene> scene Alle_Aus,<br />
set Alexa.Beleuchtung.Sitzgruppe off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
Mit diesem DOIF wird ein Radiobutton simuliert, d.h. wie bei den Stationstasten vor Uralt-Radios sorgt die Auswahl einer Szene immer dafür, dass alle anderen Dummies ausgeschaltet werden.<br />
Natürlich kann man das auch mit einem kleinen Perl-Programm erreichen.<br />
<br />
<br />
Zwei andere Ansätze Lichtszenen zu schalten die ohne DOIF auskommen sind im Folgenden beschrieben:<br />
<br />
* Wenn es von Interesse ist die Steuerung mit einer Darstellung in FTUI zu verbinden: Statt der oben beschriebenen dummy Devices kann man readingsProxy Devices mit passenden setFn und valueFn analog zum [[Harmony#Button_f.C3.BCr_eine_bestimmte_Activity_im_Frontend_und_Homekit_.C3.BCber_readingsProxy|diesem Beispiel für harmony aktivitäten]] verwenden.<br />
<br />
* Für jede zu schaltende Szene wird ein dummy angelegt dessen homebridgeMapping direkt auf das LightScene Device zeigt:<br />
<br />
define <dummy> dummy<br />
attr <dummy> setList on off<br />
attr <dummy> genericDeviceType switch<br />
attr <dummy> homebridgeMapping On=<light scene>::state,valueOn=<szene>,cmdOn=scene+<szene>,cmdOff=scene+<szene aus><br />
<br />
Bei der zweiten Variante wird davon ausgegangen das der aktuelle status nicht abgefragt oder angezeigt werden soll. Deshalb gibt es keine direkte RadioButton Funktionalität.<br />
<br />
== Nutzung ==<br />
Um den Namen zu bestimmen, unter dem ein Gerät mit Alexa angesprochen wird, verwendet Alexa-Fhem mit absteigender Priorität:<br />
* das alexaName Attribut<br />
* das alias Attribut<br />
* das NAME Internal<br />
Damit Alexa ein Gerät eindeutig identifizieren kann, sollten eindeutige Gerätenamen verwendet werden, bestehed möglichst aus einem Wort und ohne Ziffern. Wenn Alexa einen Namen nicht versteht, kann man unter [http://alexa.amazon.de/spa/index.html] nachsehen was tatsächlich verstanden wurde und den Gerätenamen ggf. anpassen.<br />
<br />
=== SmartHome Skill ===<br />
Gruppen (Räume) müssen in der Alexa App konfiguriert werden. Über das API lassen sich nur der Name und die Schalteigenschaften übergeben.<br />
<br />
Nach erfolgreicher Einrichtung des SmartHome Skills sollte Alexa mit den folgenden Befehlen nutzbar sein:<br />
<pre style="width:50%;"><br />
“alexa, schalte <gerät/gruppe> ein”<br />
“alexa, schalte <gerät/gruppe> aus”<br />
“alexa, stelle <gerät/gruppe> auf <wert> prozent”<br />
“alexa, stelle <gerät/gruppe> auf <anzahl> grad”<br />
“alexa, erhöhe <gerät/gruppe> um <anzahl> prozent”<br />
“alexa, reduziere <gerät/gruppe> um <anzahl> prozent”<br />
“alexa, erhöhe <gerät/gruppe> um <anzahl> grad”<br />
“alexa, reduziere <gerät/gruppe> um <anzahl> grad”<br />
</pre><br />
<br />
=== Custom Skill ===<br />
Der Custom Skill erlaubt im Gegensatz zum SmartHome Skill eine weitreichende Konfiguration der möglichen Kommandos.<br />
<br />
Das Prinzip der Kommandokonfiguration ist {{Link2Forum|Topic=60244|Message=532513|LinkText=im Forum}} beschrieben.<br />
<br />
TODO: Abfragen, Attribute (alexaMapping, alexaTypes, fhemIntents, articles, prepositions)<br />
<br />
== Troubleshooting ==<br />
<br />
====Allgemeiner Hinweis====<br />
Besonders wichtig ist, dass man sich sehr genau an diese Anleitung hält. Ein häufiger Fehler ist, dass die einfachen Anführungszeichen in der Anleitung unter '''AWS Lambda Funktion anlegen''' Punkt 8 einfach weggelassen werden. Diese sind zwingend notwendig. Es darf auch nur der reine Hostname eingetragen werden. Also kein ''http://'' davor. Entweder eine feste IP Adresse oder den Hostnamen, um den Rechner zu erreichen, den ihr über den Port 3000 freigegeben habt. Das sollte dann so aussehen:<br />
<pre style="width:50%;"><br />
const PORT=3000;<br />
const HOST='mein.host.name';<br />
</pre><br />
<br />
====Freigabe von Port 3000====<br />
{{Randnotiz|RNTyp=Fehl|RNText=Derzeit müsst ihr über einen echten IPv4 Anschluss verfügen, damit der Amazon Lambda-Server euch erreichen kann. DS-Lite Anschlüsse wie die von <b>UnityMedia</b> z.B. funktionieren derzeit leider nicht. Eine möglicher "Workaround" wird hier beschrieben: https://forum.fhem.de/index.php/topic,60244.msg518276.html#msg518276}}<br />
<br />
Auf dem Router muss der Port 3000 Protokoll TCP freigegeben werden. D.h. von außen muss man wenn man den Port 3000 aufruft, auf dem intern laufenden node.js Alexa-Dienst zugreifen können.<br />
Je nach Router gestaltet sich das Portforwarding bzw. die Portumleitung etwas schwieriger.<br />
<br />
Bei einem Speedport Router der Telekom beispielsweise, muss der Router komplett neu gestartet werden, wenn die Portfreigabe eingerichtet wurde. <br />
<br />
Bei der Fritz!Box ist das nicht nötig, bei dieser finden die Freigabe unter ''Internet -> Freigaben -> Portfreigaben'' statt. Dort wählt man dann den Rechner aus und richtet eine neue Freigabe ein. Wichtig hierbei ist, dass man Portfreigabe auswählt und nicht MyFRITZ!-Freigabe. Bei Port von bis trägt man 3000 ein, bei Port extern ebenfalls.<br />
<br />
Um die Portweiterleitung zu testen, solltet ihr euch auch nicht im gleichen Netz befinden. Viele Router blockieren den Netzaufruf aus dem gleichen Netz. Am besten testet ihr es, wenn ihr an eurem Mobiltelefon W-LAN deaktiviert und im Browser folgende Seite aufruft: ''https://mein.hostname:3000''. Wenn ihr im Browser dann einen Quellcode von Alexa seht, funktioniert die Portumleitung.<br />
<br />
Wenn bis hier alles funktioniert und es läuft dennoch nicht rund, liegt das Problem woanders. Kommt z.B. bei der Gerätesuche kein Request rein (sichtbar auf dem Bildschirm, wenn bin/alexa gestartet wurden), kann evtl. der Lambda-Dienst falsch konfiguriert sein.<br />
<br />
====Probleme mit node.js - npm install====<br />
<br />
Falls eine Fehlermeldung auftritt, dass "npm" nicht gefunden werden kann, bitte NodeJS entsprechend der Anleitung im Homebridge-Artikel vorgehen: [[Homebridge_einrichten#NodeJS_installieren|NodeJS installieren]] sowie [[Homebridge_einrichten#Python.2C_g.2B.2B.2C_MDNS_installieren|Python, g++, MDNS installieren]], siehe auch folgenden Abschnitt.<br />
<br />
====Es kommen diverse Fehlermeldungen beim Starten von alexa-fhem und es beendet sich====<br />
Wenn man auf der Konsole angemeldet ist, den Befehl<syntaxhighlight lang="bash" style="width:50%;">node -v</syntaxhighlight>eingeben. Ist die Version niedriger als die geforderte 0.12, muss eine neuere installiert werden. Hier darf man dann im Wiki unter [[Homebridge_einrichten#NodeJS_installieren]] nachschauen. NodeJS V4 sollte hierbei schon ausreichen. Solange die node.js Version nicht passt, gar nicht groß rum experimentieren! Bitte beachtet, dass alle Voraussetzungen unter [[Alexa-Fhem#Voraussetzungen]] erfüllt sind! Keine Experimente mit Versionen die darunter liegen.<br />
<br />
====Fehlermeldung ''NAT-PMP failed: Error: timeout'' Fehler angezeigt beim Start von alexa-fhem====<br />
Wenn ihr dann alexa-fhem über die Konsole startet und bekommt folgenden Fehler: ''NAT-PMP failed: Error: timeout'', lasst euch davon nicht irritieren. Das bedeutet lediglich, dass der Port nicht automatich freigegeben wurde über uPNP. Alternativ prüft, ob die Funktion der Portfreigabe via uPNP auf eurem Router aktiviert ist.<br />
<br />
====Nach Start auf der Console beendet sich Alexa-FHEM sofort wieder====<br />
Unmittelbar nach dem Start von Alexa-FHEM werden ein paar UPNP Fehlermeldungen ausgegeben. Unmittelbar danach beendet sich Alexa-FHEM wieder. <br />
<br />
Viele scheinen ein Problem mit UPNP auf dem Raspberry Pi zu haben. Wenn dieses Problem auftritt einfach in der <code>~/.alexa/config.json</code> die folgenden Zeilen rauslöschen:<br />
<br />
<pre><br />
"nat-pmp": "10.0.1.1",<br />
"nat-upnp": true,<br />
</pre><br />
<br />
Jetzt erneut Alexa-FHEM starten. Sollte nun laufen.<br />
<br />
====Was ist zu tun, wenn alexa-fhem keine Geräte findet?====<br />
Zunächst müssen die Geräte, die angesprochen werden wollen, unter FHEM ein neues Attribut zugewiesen bekommen. Dazu das Gerät in FHEM öffnen und das Attribut ''genericDeviceType switch'' hinzufügen, wenn es ein Schalter mit der Funktiona AN/AUS sein soll. Wenn man will, kann man dem Gerät jetzt noch über das Attribut ''alias'' eine besseren Namen geben, mit dem Alexa das Gerät dann auch finden kann.<br />
Anschließend muss alexa-fhem neu gestartet werden und die definierten Geräte sollten nun gefunden werden.<br />
<br />
====Was ist zu tun, wenn Alexa zwar Geräte findet, diese aber nicht angesprochen werden können?====<br />
Zuerst die Informationen zum Datenfluss ganz oben ansehen. Dann am besten von hinten nach vorne vorgehen:<br />
* wenn nichts bei alexa-fhem ankommt: port forwarding prüfen<br />
* wenn lambda.js nichts los wird: im cloudwatch log nachsehen<br />
* wenn bei lambda.js nichts ankommt: den trigger prüfen<br />
<br />
<br />
Zunächst sollte man sich unter ''http://aws.amazon.com'' das Logfile seiner erstellten Funktion anschauen. Ist überhaupt ein Logfile vorhanden? Falls nicht, liegt es vermutlich am Trigger.<br />
Den solltet ihr überprüfen. Scheinbar kommt es hin und wieder vor, dass dieser nicht gesetzt ist. Dazu einfach auf ''Triggers'' klicken und mit ''Add trigger'' erneut einen anlegen. Hier muss, wie in der Anleitung unter '''AWS Lambda Funktion anlegen''' Punkt 7, die ''Application Id'' stehen und der Haken bei ''Enable trigger'' gesetzt sein. Dann alexa-fhem neu starten.<br />
Wenn ihr Änderugen gemacht habt und den alexa-fhem Dienst noch nicht neu gestartet habt, wäre jetzt der richtige Zeitpunkt.<br />
<br />
====Was ist zu tun, wenn sich der Alexa-Service nicht starten lässt?====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Der User in der User= Directive von alexa.service muss Ausführungsrecht auf dem alexa binary haben (x), so wie auch mind. Lesezugriff auf dem Verzeichnis nach -U Option in der ExecStart= Directive und auch auf dem WorkingDirectory }}<br />
Schaut bitte in das Unterverzeichnis [alexa-fhem (also dort, wo Ihr Alexa-FHEM instelliert habt]/bin. Die dort befindliche Datei ''alexa'' muss ausführbar sein. Also z.B. so:<br />
<syntaxhighlight lang="bash" style="width:70%;">2755327 4 -rwxr-xr-x 1 pi pi 339 Nov 26 23:20 alexa</syntaxhighlight><br />
Sollte dies nicht der Fall sein bitte mit:<br />
<syntaxhighlight lang="bash" style="width:70%;">chmod +x alexa</syntaxhighlight><br />
die Datei ausführbar machen. Sofern der User "pi" Eigentümer ist, ist kein sudo erforderlich.<br />
<br />
Eine lauffähige Konfiguration ist {{Link2Forum|Topic=71612|Message=668383|LinkText=hier}} zu sehen.<br />
<br />
Ein Fehler in der Rechtekonfiguration führt in der Regel zu folgendem Ergebnis nach <code>sudo systemctl status alexa</code>:<br />
<br />
<syntaxhighlight lang="bash"> Loaded: loaded (/etc/systemd/system/alexa.service; enabled)<br />
Active: activating (auto-restart) (Result: exit-code) since mer. 2017-09-06 02:33:23 CEST; 3s ago<br />
Process: 18332 ExecStart=/opt/fhem/alexa-fhem/bin/alexa -U /home/alexa/.alexa (code=exited, status=217/USER)<br />
Main PID: 18332 (code=exited, status=217/USER)</syntaxhighlight><br />
<br />
====Wie kann ich via Alexa-FHEM auf FHEM zugreifen, wenn der Port mit Benutzername/Kennwort geschützt ist?====<br />
<br />
Hierzu muss die Datei <code>~/.alexa/config.json</code> geöffnet werden und der Abschnitt "connections" um folgende Zeile ergänzt werden:<pre><br />
"auth": {"user": "fhem", "pass": "fhempassword"},</pre><br />
Bei Verwendung von SSL bei FHEM muss auch noch <pre><br />
"ssl": true,</pre> hinzugefügt werden<br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Sprachsteuerung]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=Alexa-Fhem&diff=22493Alexa-Fhem2017-09-06T01:12:45Z<p>Amenomade: /* Was ist zu tun, wenn sich der Alexa-Service nicht starten lässt? */</p>
<hr />
<div>'''Alexa-Fhem''' ist eine in JavaScript geschriebene und auf NodeJS basierende Software, welche es ermöglicht, der digitalen Amazon Assistentin Alexa zusätzliche Skills für die Heimautomatisierung via FHEM beizubringen. Eine erste funktionierende Version wurde von [https://forum.fhem.de/index.php?action=profile;u=430 justme1968] im {{Link2Forum|Topic=60244|LinkText=Forum}} veröffentlicht.<br />
Das ist eine erste Version der Dokumentation zur Installation und Einrichtung, eine Erweiterung wird sicherlich in nächster Zeit noch folgen.<br />
{{Infobox Modul<br />
|ModPurpose=Anbindung von FHEM an Amazon Assistent Alexa<br />
|ModType=x<br />
|ModTechName=<br />
|ModForumArea=Frontends/Sprachsteuerung<br />
|ModOwner=justme1968<br />
}} <br />
<br />
<br />
==Einführung==<br />
===Glossar===<br />
*Echo bzw. Echo Dot (im Folgenden maskulin bezeichnet) sind die derzeit verfügbaren Geräte des Alexa-Systems '''BILDER EINSTELLEN - Achtung Urheberrecht'''<br />
*AVS ist der Amazon Voice Service, d.h. die Spracherkennungskomponente des Systems.{{Randnotiz|RNTyp=r|RNText=Für die Nutzung der Amazon AWS-Dienste müssen zwingend die Daten einer Kreditkarte angegeben werden. Nach gegenwärtigem Kenntnisstand sollen jedoch keine Kosten für die Nutzung der im Rahmen dieses How To beschriebenen Dienste anfallen, sofern diese in einem Rahmen genutzt werden, der selbst eine intensive private Nutzung nicht überschreitet. Der Benutzer sei an dieser Stelle auf die von Amazon veröffentlichten Preislisten verwiesen. Die Autoren dieser Anleitung und der darin beschriebenen Module übernehmen keine Haftung für eventuelle Kosten, die aus der Nutzung der AWS entstehen. }}<br />
*AWS sind die Amazon Web Services, also per URL erreichbare Dienste zur Ausführung von Berechnungen etc. Im Rahmen von Alexa-Fhem wird bei AWS eine eigene JavaScript-Funktion hinterlegt, die zur Kommunikation mit dem FHEM-Server dient. Im Jargon von Amazon ist dies eine so genannte Lambda-Funktion '''WARUM ? Nachlesen bei Amazon'''.<br />
*Card bezeichnet einen Eintrag in der Alexa-App, der die erkannte Sprachnachricht sowie weiter gehenden Informationen über die Reaktion von Alexa enzthält und Rückmeldung an Amazon erlaubt.<br />
*Skill (engl. für Fähigkeit) ist die Bezeichnung für eine per Spracherkennung bediente Funktionalität des Alexa-Systems, z.B. zur Nachrichtenansage, zur Wettervorhersage oder zur Steuerung von FHEM<br />
<br />
===Arbeitsweise und Datenfluss===<br />
[[Datei:2gpXyLN.jpg|200px|thumb|right|Grafische Darstellung der beteiligten Komponenten]]<br />
Echo -> AVS -> AWS Lambda -> alexa-fhem -> AWS Lambda -> AVS -> Echo<br />
<br />
*Der Echo (oder ein anderes Alexa/AVS fähiges Gerät) nimmt Audiodaten auf und schickt diese an AVS (Amazon Voice Service) zur Erkennung<br />
*AVS führt die Spracherkennung durch und erzeugt ein Event mit Informationen zu den erkannten Daten<br />
:*Beim Alexa SmartHome Skill sind die möglichen Sätze für die Spracherkennung relativ fest vorgegeben <br />
:*Beim Alexa Custom Skill kommen die dazu nötigen Informationen aus dem ''Interaction Model'' der Alexa Skills Configuration<br />
*Das Event wird an den unter ''Configuration'' in der Alexa Skills Configuration hinterlegten Endpoint geschickt<br />
:*Beim Alexa SmartHome Skill ist das zwingend eine AWS Lambda Routine<br />
:*Beim Alexa Custom Skill kann das im Prinzip auch ein eigener Web Service sein<br />
*Das Event wird vom <code>lambda.js</code> code an alexa-fhem weitergeleitet<br />
*alexa-fhem steuert FHEM und sendet ein Antwort-Event zurück<br />
*<code>lambda.js</code> nimmt diese Antwort entgegen und gibt sie an AVS zurück<br />
*AVS sogt dafür das der Echo 'antwortet' und dass die Card in der Alexa App erscheint<br />
<br />
===Anmerkungen===<br />
*Ein Skill hat keinen Zugriff auf die Audiodaten<br />
*Mit dem Skill API kann ein Skill zu zu keiner Zeit von sich aus aktiv werden und 'einfach' Daten an den Echo schicken oder ihn dazu bringen irgendetwas zu tun.<br />
*Wenn man berücksichtigt welchen Weg die Daten insgesamt gehen, ist es erstaunlich, wie schnell die Reaktion auf einen gesprochenen Satz erfolgt.<br />
<br />
=== Abgrenzung des '''Alexa Smart Home Skills''' und des '''Alexa Custom Skills''' ===<br />
<br />
Der [[Alexa-Fhem#Smart_Home|Alexa Smart Home Skill]] ist ein Amazon-Alexa-Standard-Skill, der wesentliche Basisfunktionalitäten bereitstellt. Zu diesen gehört im Wesentlichen die Funktionalität, durch Alexa-FHEM bereitgestellte Devices im Alexa-Account des Benutzers anzulegen. Der Alexa Smart Home Skill reagiert auf gesprochene Interaktion in einem beschränkten Umfang. Beispielsweise genügt ein "Alexa, schalte die Wohnzimmerlampe an" um eine Interaktion zwischen Alexa Smart Home Skill und FHEM-Alexa auszulösen. Nach erfolgreicher Einrichtung wird dieser Skill in der Alexa-App bzw. im Web in der Rubrik "Smart Home" als Skill angezeigt.<br />
<br />
Der [[Alexa-Fhem#Custom|Alexa Custom Skill]] ist kein Standard-Smart-Home-Skill, sondern ein individuell entwickelter Skill, so wie alle anderen Skills auch. Er wird daher auch nicht in der Alexa-App unter der Rubrik "Smart Home" angezeigt. Gesprochene Interaktion mit diesem Skill erfolgt dadurch, dass entweder der Skill explizit gestartet wird (z.B. "Alexa, starte [Name des Skills]") oder direkt angesprochen wird (z.B. "Alexa, frage [Name des Skills] wie ist der Status von [Device] "). Der Alexa Custom Skill befindet sich in Entwicklung und wird hinsichtlich seiner Funktionalitäten laufend weiterentwickelt. Die Einrichtung dieses Skills ist grundsätzlich optional, jedoch werden anspruchsvollere Steuerungsmöglichkeiten nur mit diesem realisiert werden können.<br />
<br />
==Installation==<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Da die einzelnen Schritte der Anleitung an verschiedenen Stellen unterbrochen und später fortgesetzt werden müssen, empfiehlt es sich, die Anleitung einmal vollständig gelesen zu haben. Während der Konfiguration sollten alle nachfolgenden Abschnitte parallel in gleichzeitig geöffneten Browserfenstern durchgeführt werden, die jeweils bis zum Abschluss geöffnet bleiben müssen. }}<br />
Grundvoraussetzung für alle folgenden Schritte ist das Vorhandensein eines Amazon-Accounts. Es wird davon ausgegangen, dass die Konten für alle im Folgenden genutzten Amazon-Dienste eingerichtet wurden.<br />
<br />
===node.js installieren===<br />
Zunächst wird das Betriebssystem (in diesem Falle Debian oder Ubuntu) auf den aktuellen Stand gebracht:<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
sudo apt-get update<br />
sudo apt-get upgrade<br />
sudo apt-get install build-essential libssl-dev</syntaxhighlight><br />
<br />
Nun muss NodeJS installiert werden. Leider ist die Version im Debian Repository deutlich zu alt, daher wird mit den folgenden Befehlen das Node Repository hinzugefügt und NodeJS (in der LTS Version) entsprechend installiert:<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -<br />
sudo apt-get install -y nodejs<br />
</syntaxhighlight><br />
<br />
=== Alexa-Fhem installieren ===<br />
'''Aus gegebenem Anlass: Dies ist weder eine Einführung in Linux, noch eine Anfängerdokumentation für FHEM.''' Also erst die Grundlagen lernen, und dann mit Alexa beginnen !<br />
<br />
Die aktuelle Version ist jeweils {{Link2Forum|Topic=60244|Message=540117|LinkText=hier}} zu finden.<br />
<br />
====Erstinstallation====<br />
Hier wird die Erstinstallation von Alexa-Fhem beschrieben.<br />
===== Linux =====<br />
# Die tgz-Datei unter Linux im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) entpacken (''nicht'' unter Windows, das zerstört die Rechteeinstellungen).<syntaxhighlight lang="bash" style="width:50%;">tar -xvzf dateiname.tgz</syntaxhighlight><br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen <syntaxhighlight lang="bash" style="width:50%;">mv package alexa-fhem</syntaxhighlight><br />
# Durch <syntaxhighlight lang="bash" style="width:50%;">cd alexa-fhem</syntaxhighlight> in das Verzeichnis wechseln<br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren (kein sudo!).<br />
# SSL Zertifikat erzeugen durch Aufruf von <syntaxhighlight lang="bash" style="width:50%;">./createKey.sh</syntaxhighlight> (kein sudo!). Hierbei beachten, dass ein Kennwort vergeben werden muss, das mindestens aus 4 Zeichen besteht, dieses Kennwort bitte merken.<br />
# Das Verzeichnis ''.alexa'' anlegen, ''und zwar im Home-Verzeichnis desjenigen Benutzers, unter dem Alexa-Fhem laufen soll.'' Insbesondere ist zu beachten, dass dieser Nutzer u.U. im Startskript explizit gesetzt wird. Mit dem untenstehenden Skript ist das ''nicht'' der User fhem, sondern der User ''pi''. Das Symbol ''~/'' verweist auf das Home-Verzeichnis des Benutzers, der gerade die Installation vornimmt.<br />
# Die Datei ''config-sample.json'' nach ''.alexa/config.json'' kopieren. Achtung: Installiert man alexa-fhem als root-user, zeigt das Symbol ''~/'' auf ''/root'' - und die Konfigurationsdatei wird ggf. bei einem manuellen Start von Alexa-Fhem nicht gefunden.<br />
# Achtung: Ggf. müssen auch die Dateien key.pem und cert.pem ins entsprechende Verzeichnis kopiert werden.<br />
===== Windows =====<br />
''Vor'' der Installation von Alexa-Fhem muss man folgende Anwendungen installieren:<br />
* Node.js (die aktuelle Version findet man unter https://nodejs.org/en/download/)<br />
* OpenSSL (http://slproweb.com/products/Win32OpenSSL.html oder https://www.heise.de/download/product/win32-openssl-47316/download)<br />
Erst dann fängt man mit Alexa-Fhem an.<br />
<br />
<br />
# Die tgz-Datei im Hauptverzeichnis von FHEM (z.B. <code>С:\Program Files (x86)\fhem</code>) entpacken.<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen<br />
# Windows-Shell (Kommandozeile, Eingabeaufforderung usw.) öffnen. "Start" -> "Ausführen" (oder [Windows-Taste]+[R]) -> cmd -> Ok. Durch <syntaxhighlight lang="bash" style="width:50%;">cd "<FHEM-Hauptverzeichis>\alexa-fhem"</syntaxhighlight> in das Verzeichnis wechseln. <br/>Dabei ist natürlich das <FHEM-Hauptverzeichis> durch den entsprechenden Pfad aus dem Schritt 1 zu ersetzen. Im o.g. Beispiel wäre es <code>cd "С:\Program Files (x86)\fhem\alexa-fhem"</code><br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren.<br/> Bei der Fehlermeldung wie "Der Befehl "npm" ist entweder falsch geschrieben oder konnte nicht gefunden werden." ist die Installation von Node.js zu überprüfen.<br />
# SSL Zertifikat erzeugen. Dafür muss man alle Befehle aus dem Skript ''createKey.sh'' nacheinander manuell ausführen. Hierbei beachten, dass ein Kennwort vergeben werden muss, das mindestens aus 4 Zeichen besteht, dieses Kennwort bitte merken. Der Windows-Welt unbekannter Befehl <code>mv</code> ist durch <code>move /y</code> zu ersetzen:<syntaxhighlight lang="bash" style="width:50%;">openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;">openssl rsa -in key.pem -out newkey.pem</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;">move /y newkey.pem key.pem</syntaxhighlight> Eventuelle Fehlermeldung "can't open config file: /usr/local/ssl/openssl.cnf" o.Ä. lässt sich durch Befehl <code>set OPENSSL_CONF=<OpenSSL-Verzeichnis>\bin\openssl.cfg</code> beheben, wobei <OpenSSL-Verzeichnis> durch den entsprechenden Installationspfad (typischerweise <code>c:\OpenSSL-Win32</code>) zu ersetzen ist.<br />
# Das Verzeichnis ''.alexa'' anlegen, ''und zwar im Benutzerverzeichnis desjenigen Benutzers, unter dem Alexa-Fhem laufen soll.'' In aktuellen Versionen von Windows (ab Windows 7 bzw. ab Windows Server 2008 R2) liegt das Verzeichnis unter <code>C:\Users\<Benutzername></code>, also z.B. für Benutzer "Administrator" - unter <code>C:\Users\Administrator</code>.<br/>Falls Windows sich weigert das Verzichniss mit dem Punkt am Anfang zu erstellen, kann man das aus der Kommandozeile machen:<syntaxhighlight lang="bash" style="width:50%;">cd "C:\Users\<Benutzername>"</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;"><br />
mkdir ".alexa"</syntaxhighlight><br />
# Die Datei ''config-sample.json'' nach ''C:\Users\<Benutzername>\.alexa\config.json'' kopieren.<br />
# Achtung: Ggf. müssen auch die Dateien key.pem und cert.pem ins entsprechende Verzeichnis (<code>"<FHEM-Hauptverzeichis>\alexa-fhem\bin</code>) kopiert werden.<br />
<br />
====Update====<br />
Hier wir das Update auf eine neue Version von Alexa-Fhem beschrieben<br />
===== Linux =====<br />
# Das Verzeichnis ''alexa-fhem'' im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) umbenennen in ''alexa-fhem.old''.<br />
# Die tgz-Datei der neuen Alexa-Fhem-Version unter Linux im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) entpacken (''nicht'' unter Windows, das zerstört die Rechteeinstellungen).<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen, in das Verzeichnis wechseln<br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren (kein sudo!).<br />
# Die Zertifikatsdateien key.pem und cert.pem aus dem alten Verzeichnis ''alexa-fhem.old'' ins neue Verzeichnis ''alexa-fhem'' kopieren.<br />
Natürlich dann den Dienst neu starten, auch müssen selbstredend irgendwelche Modifikationen an der Datei server.js in der neuen Version nachgezogen werden. Wenn alles läuft, kann das alte Verzeichnis ''alexa-fhem.old'' gelöscht werden.<br />
===== Windows =====<br />
# Das Verzeichnis ''alexa-fhem'' im Hauptverzeichnis von FHEM (z.B. <code>С:\Program Files (x86)\fhem</code>) umbenennen in ''alexa-fhem.old''.<br />
# Die tgz-Datei der neuen Alexa-Fhem-Version im Hauptverzeichnis von FHEM entpacken.<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen<br />
# Windows-Shell (Kommandozeile, Eingabeaufforderung usw.) öffnen. "Start" -> "Ausführen" (oder [Windows-Taste]+[R]) -> cmd -> Ok. Durch <syntaxhighlight lang="bash" style="width:50%;">cd "<FHEM-Hauptverzeichis>\alexa-fhem"</syntaxhighlight> in das Verzeichnis wechseln. <br/>Dabei ist natürlich das <FHEM-Hauptverzeichis> durch den entsprechenden Pfad aus dem Schritt 1 zu ersetzen. Im o.g. Beispiel wäre es <code>cd "С:\Program Files (x86)\fhem\alexa-fhem"</code><br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren.<br />
# Die Zertifikatsdateien key.pem und cert.pem aus dem alten Verzeichnis ''alexa-fhem.old'' ins neue Verzeichnis ''alexa-fhem'' kopieren.<br />
Natürlich dann den Dienst neu starten, auch müssen selbstredend irgendwelche Modifikationen an der Datei server.js in der neuen Version nachgezogen werden. Wenn alles läuft, kann das alte Verzeichnis ''alexa-fhem.old'' gelöscht werden.<br />
<br />
==== Alexa-Fhem konfigurieren ====<br />
Der Inhalt der Datei ''~/.alexa/config.json'' muss an die eigene Umgebung angepasst werden. <br />
# ''nat-pmp'' -> wenn nat-pmp verwendet werden soll: die ip des eigenen routers,<br />
# ''nat-upnp'' -> wenn nat-upnp verwendet werden soll: ''true'',<br />
# ''applicationId'' <br />
#:* Wenn man nur den SmartHome-Skill verwenden möchte, kann dieser Eintrag leer bleiben.<br />
#:* Ansonsten ist er mit der SkillID des Alexa Custom Skills zu belegen, siehe Abschnitt [[#Skill_Id_bestimmen | Skill Id bestimmen]]<br />
# ''oauthClientID'' -> ''Client ID'' dem Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
# ''server'' -> IP-Adresse des eigenen FHEM-Servers<br />
# ''port'' -> Portnummer des eigenen FHEM-Servers<br />
Beispiel:<br />
{<br />
"alexa": {<br />
"name": "Alexa TEST",<br />
"keyFile": "./key.pem",<br />
"certFile": "./cert.pem",<br />
"applicationId": "amzn1.ask.skill.xxxxxxxxxxxxxxxxxxxxxxxxxxxx",<br />
"oauthClientID": "amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"<br />
},<br />
"connections": [<br />
{<br />
"name": "FHEM",<br />
"server": "192.168.0.xxx.xxx",<br />
"port": "8083",<br />
"filter": "room=AlexaRoom"<br />
}<br />
]<br />
}<br />
<br />
Mehrere Custom Skills lassen sich mit der folgenden Syntax eintragen<br />
"applicationId": [ "amzn1.ask.skill.1" , "amzn1.ask.skill.2" ],<br />
"oauthClientID": [ "amzn1.application-oa2-client.1" , "amzn1.application-oa2-client.1" ]<br />
<br />
Danach durch Aufruf von <syntaxhighlight lang="bash" style="width:50%;">./bin/alexa</syntaxhighlight> den Dienst starten (kein sudo!)<br />
<br />
<br />
Unter Windows startet man Alexa-Dienst durch <syntaxhighlight lang="bash" style="width:50%;">node alexa</syntaxhighlight> aus der <code>alex-fhem/bin</code> (also erst z.B. durch <code>cd "<FHEM-Hauptverzeichis>\alexa-fhem\bin"</code> ins richtige Verzeichnis kommen)<br />
<br />
Der Start des Alexa-Dienstes auf der Console ist immer dann zu empfehlen, wenn man auf die Ausgaben des Dienstes angewiesen ist und beispielsweise sehen möchte, welche Devices durch den Dienst bereitgestellt werden oder ob Fehler auftreten. Beendet man die Console-Session wird auch der Dienst wieder beendet. Insofern ist die vorgenannte Vorgehensweise nur für ein Debugging zu empfehlen und nicht im Regelbetrieb. Nachfolgend ist beschrieben, wie man den Alexa-Dienst aus FHEM heraus starten / stoppen und neu starten kann.<br />
<br />
==== Alexa-Fhem aus FHEM heraus starten ====<br />
Zunächst das Start-up-Skript aus diesem Post herunterladen {{Link2Forum|Topic=60244|Message=517271|LinkText=https://forum.fhem.de/index.php/topic,60244.msg517271.html#msg517271}} und unter /etc/init.d/alexa speichern.<br />
<br />
Das Script geht davon aus, das der alexa-fhem script unter /opt/fhem/alexa-fhem liegt, und die logfiles später unter /opt/fhem/log. Sollte das nicht der Fall sein, muss das Skript angepasst werden.<br />
<br />
Nun folgende Kommandos ausführen:<br />
<syntaxhighlight lang="bash" style="width:50%;">sudo chmod 755 /etc/init.d/alexa<br />
sudo update-rc.d alexa defaults</syntaxhighlight><br />
<br />
In der Datei <code>/etc/sudoers</code> den User fhem für die Nutzung von sudo zulassen (<code>sudo nano /etc/sudoers</code>), z.B. durch Anfügen der nachfolgenden Zeile:<br />
<code>fhem ALL=(ALL) NOPASSWD: ALL</code><br />
<br />
Nun folgende Devices anlegen (ggf. einem Raum zuordnen, z.B. AlexaControl):<br />
<syntaxhighlight lang="bash" style="width:75%;">define FHEM.Alexa.Status dummy<br />
<br />
define FHEM.Alexa dummy<br />
attr FHEM.Alexa event-on-change-reading state<br />
attr FHEM.Alexa webCmd status:start:stop:restart<br />
<br />
define FHEM.Alexa.DOIF DOIF ([FHEM.Alexa] eq "start") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa start > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "stop")<br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa stop > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "restart") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa restart > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "status") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa status > /dev/null 2>&1 &")})</syntaxhighlight><br />
<br />
==== Alexa-Fhem als Service (systemd) installieren ====<br />
Auf neueren Installationen (z.B. RPi Jessie) wird init.d durch systemd ersetzt. Folgend die Anleitung um alexa-fhem als Service zu installieren auf einem Raspberry Pi mit Jessie.<br />
<br />
Zunächst einen neuen Benutzer anlegen unter dem alexa-fhem laufen soll, falls man nicht möchtet dass alexa-fhem z.B. mit dem fhem User ausgeführt wird:<br />
<br />
<code lang="bash" style="width:75%;"><br />
sudo useradd -M --system alexa<br />
</code><br />
<br />
Eigentlich braucht der Benutzer keine Gruppen, aber man kann den Benutzer auch der Gruppe <code>dialout</code> hinzufügen (<code>sudo usermod -a -G dialout alexa</code>)<br />
<br />
Datei "alexa.service" unter <code>/etc/systemd/system</code> anlegen:<br />
<br />
[Unit]<br />
Description=Node.js Alexa Server <br />
After=syslog.target network-online.target<br />
<br />
[Service]<br />
Type=simple<br />
User=alexa <br />
WorkingDirectory=/opt/alexa/alexa-fhem<br />
ExecStart=/opt/fhem/alexa-fhem/bin/alexa -U /home/alexa/.alexa<br />
Restart=on-failure<br />
RestartSec=10<br />
KillMode=process<br />
<br />
[Install]<br />
WantedBy=multi-user.target <br />
<br />
Den Pfad <code>/home/alexa/.alexa</code> an die Systemgegebenheiten anpassen. Letztendlich kann die config.json irgendwo liegen, hauptsache alexa-fhem weiß wo. <code><Homeverzeichnis des "User=">/.alexa</code> empfholen. <br />
<br />
Im WorkingDirectory wird der alexa Dienst die Zertifikate suchen.<br />
<br />
Achtung: Natürlich muss der Benutzer auch Zugriff auf das Verzeichnis mit der config als auch das alexa-fhem Verzeichnis und das WorkingDirectory haben.<br />
<br />
Um den Service zu aktiveren und zu starten helfen folgende Befehle:<br />
sudo systemctl daemon-reload<br />
sudo systemctl enable alexa<br />
sudo systemctl start alexa<br />
<br />
Status abfragen mit<br />
sudo systemctl status alexa<br />
<br />
Log einsehen?<br />
sudo journalctl -u alexa<br />
<br />
(mit <code>-f</code> kann man den follow Modus aktivieren, wie <code>tail -f</code>).<br />
Bei einen reboot startet alexa-fhem jetzt automatisch.<br />
<br />
==== Alexa-Fhem testen ====<br />
Node.Js stellt einen Web-Server am Port 3000 bereit, das oben erzeugte Zertifikat sichert diesen Zugang per SSL ab. Durch Aufruf der Adresse<br />
<code>https://<IP-Adresse des Servers>:3000</code> kann man testen, ob der Alexa-Fhem Service läuft - der Seitenaufruf liefert eine Zeile JSON-Code, beginnend mit<br />
<code>{"header":{"name":"UnsupportedOperationError"...</code><br />
<br />
=== Alexa Device anlegen ===<br />
<br />
Das Modul 39_alexa.pm stellt innerhalb von FHEM verschiedene Attribute z.B. alexaName oder alexaRoom zur Verfügung. Manche dieser Attribute (wie z.b. alexaName) werden in beiden Skills verwendet, andere werden ausschließlich bei einer Nutzung des Alexa Custom Skill verwendet.<br />
<br />
Die Einrichtung des Alexa Device geschieht durch die nachfolgende Definition:<br />
<syntaxhighlight lang="bash" style="width:70%;">define MyAlexa alexa</syntaxhighlight><br />
<br />
<hr><br />
<br />
=== Alexa Skills ===<br />
Für folgende Schritte muss man unter der Adresse http://developer.amazon.com angemeldet sein<br />
# Anmeldung auswählen<br />[[Datei:Developer.amazon.com-01-login2.png|200px]]<br />
# Anmeldedaten eingeben<br />[[Datei:Developer.amazon.com-02-userpass2.png|200px]]<br />
<br />
==== Security Profile anlegen ====<br />
Die Erzeugung eines Sicherheitsprofils muss nur einmal erfolgen, es wird dann für alle weiteren Skills verwendet.<br />
# Nach der Anmeldung Auswahl von ''APPS & SERVICES''<br />[[Datei:Developer.amazon.com-03-apps_and_services.png|200px]]<br />
# Anschließend auswählen ''Security Profiles''<br />[[Datei:Developer.amazon.com-05-apps_and_services_-_security_profiles.png|200px]]<br />
# Auswählen ''Create a New Security Profile'' aus<br />[[Datei:Developer.amazon.com-06-apps_and_services_-_create_a_new_security_profile.png|200px]]<br />
# Dann einen Namen und eine Beschreibung für das Profil eingeben und mit ''Save'' bestätigen<br />[[Datei:Developer.amazon.com-07-apps_and_services_-_security_profile_management.png|200px]]<br />
<br />
===== Login with Amazon =====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Hier wird beschrieben, wo ''Client Id'' und ''Client Secret'' zu finden sind}}<br />
# Oben rechts auf ''Login with Amazon'' klicken.<br/>[[Datei:Developer.amazon.com-08-login_with_amazon.png|200px]]<br />
# Auf der neu geladenen Seite auswählen ''Sign up''<br/>[[Datei:Developer.amazon.com-09-login_with_amazon_-_sign_up.png|200px]]<br />
# Anschließend im Dropdown Menü das vorher angelegte Profil auswählen und mit ''Confirm'' bestätigen<br/>[[Datei:Developer.amazon.com-10-login_with_amazon_-_create_new_profile.png|200px]] [[Datei:Developer.amazon.com-11-login_with_amazon_-_create_new_profile2.png|200px]]<br />
# Im folgenden Fenster die Adresse [https://www.amazon.com/gp/help/customer/display.html?nodeId=468496 https://www.amazon.com/gp/help/customer/display.html?nodeId=468496] eingeben und mit ''Save'' bestätigen. '''Todo Erklärungsbedarf: WARUM diese Adresse'''<br/>[[Datei:Developer.amazon.com-12-login_with_amazon_-_enter_consent_screen_information.png|200px]]<br />
# Anschließend bei dem neu angelegten Eintrag auf der rechten Seite auf das Zahnrad klicken und ''Web Settings'' auswählen<br/>[[Datei:Developer.amazon.com-13-login_with_amazon_-_web_settings.png|200px]]<br />
# Im neu geladenen Fenster anklicken von ''Edit''<br/>[[Datei:Developer.amazon.com-14-login_with_amazon_-_edit.png|200px]]<br />
# Anschließend bei ''Allowed Return URLs'' die folgenden drei Adressen eingeben. ''xxx'' muss hierbei durch den Wert ersetzt werden, der in den beiden Abschnitten [[#SmartHome_Skill_anlegen | SmartHome Skill anlegen]] bzw. [[#Custom_Skill_anlegen | Custom Skill anlegen]] jeweils unter Punkt 4 (Seite ''Configuration'') bei ''Redirect Urls'' am Ende der URLs angezeigt wird<br />
## [https://layla.amazon.co.uk/api/skill/link/xxx https://layla.amazon.co.uk/api/skill/link/xxx]<br />
## [https://pitangui.amazon.com/api/skill/link/xxx https://pitangui.amazon.com/api/skill/link/xxx]<br />
## [https://layla.amazon.com/api/skill/link/xxx https://layla.amazon.com/api/skill/link/xxx]<br />
.<br/>[[Datei:Developer.amazon.com-15-login_with_amazon_-_allowed_return_urls.png|200px]]<br />
<br />
==== Skills bearbeiten ====<br />
# Im Menü den Punkt ''ALEXA'' auswählen<br />[[Datei:Developer.amazon.com-03-apps_and_services.png|200px]]<br />
# Anschließend im Feld ''Alexa Skills Kit'' auf ''Get started'' klicken<br />[[Datei:Developer.amazon.com-17-alexa_-_alex_skills_kit_-_get_started.png|200px]]<br />
<br />
===== SmartHome Skill anlegen =====<br />
# Oben rechts ''Add a New Skill'' auswählen<br />[[Datei:Developer.amazon.com-18-alexa_-_alex_skills_kit_-_add_a_new_skill.png|200px]]<br />
# Auf der folgenden Seite eingeben und dann mit ''Next'' bestätigen:<br />
#:* ''Skill Type'' -> ''SmartHome Skill API'' <br />
#:* ''Language'' -> ''German''<br />
#:* ''Name'' -> beliebiger Name, z.B. "MySmartHome Basic")<br />
#:* ''Payload Version'' -> ''v2 (other devices)'' <br/>[[Datei:Developer.amazon.com-19-alexa_-_alex_skills_kit_-_skill_information.png|200px]]<br />
# Die folgende Seite einfach mit ''Next'' überspringen<br />[[Datei:Developer.amazon.com-20-alexa_-_alex_skills_kit_-_interaction_model.png|200px]]<br />
# Auf der Seite ''Configuration'' Folgendes eingeben:<br />
#:* ''Service Endpoint Type'' -> ''AWS Lambda'' ist vorausgewählt und kann nicht geändert werden.<br />
#:* ''Geographical Region'' -> ''Europe'' auswählen und im Textfeld die ARN aus Abschnitt [[#ARN_der_AWS_Lambda_Funktion_bestimmen | AWS Lambda Funktion]] eintragen. <br />
#:* ''Authorization URL'' -> <code>https://www.amazon.com/ap/oa</code><br />
#:* ''Client ID'' -> ''Client ID'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
#:* ''Scope'' -> <code>profile:user_id</code> (wörtlich 1:1 eintragen)<br />
#:* ''Redirect URLs'' - sollten vorbelegt sein<br />
#:* ''Authorization Grant Type'' -> ''Auth Code Grant'' auswählen<br />
#:* ''Access Token URI'' -> <code>https://api.amazon.com/auth/o2/token</code><br />
#:* ''Client Secret'' -> ''Client Secret'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
#:* ''Client Authentication Scheme'' -> ''HTTP Basic''<br />
#:* ''Privacy Policy URL'' -> <code>https://www.amazon.com/gp/help/customer/display.html?nodeId=468496</code><br /><br /><br />
<br />[[Datei:Developer.amazon.com-21-alexa_-_alex_skills_kit_-_configuration.png|200px]] [[Datei:Developer.amazon.com-22-alexa_-_alex_skills_kit_-_test.png|200px]]<br />
<br />
===== Custom Skill anlegen =====<br />
<ol><br />
<li> Oben rechts ''Add a New Skill'' auswählen<br />[[Datei:Developer.amazon.com-18-alexa_-_alex_skills_kit_-_add_a_new_skill.png|200px]]</li><br />
<li> Auf der folgenden Seite (''Skill Information'') die nachstehenden Daten eingeben und dann mit ''Next'' bestätigen:<br />
<ul><br />
<li> ''Skill Type'' -> ''Custom Interaction Model'' </li><br />
<li> ''Language'' -> ''German''</li><br />
<li> ''Name'' -> beliebiger Name, z.B. "MySmartHome Advanced". Dieser wird in der Alexa App unter "Meine Skills" angezeigt.</li><br />
<li> ''Invocation Name'' -> Aufruf des Skills, unter dem dieser später gestartet wird. Z.B. "Alexa, starte James"<br />[[Datei:CustomSkill_2.PNG|400px]]</li><br />
</ul></li><br />
<li>Auf der Seite ''Interaction Model'' folgende Eingaben tätigen und mit ''Next'' abschließen<br />
<ul><br />
<li>In einem separaten Browserfenster FHEM aufrufen, und für das bereits definierte Alexa-Gerät das Kommando <code>get MyAlexa interactionModel</code> aufrufen. Es erscheint ein Popup-Fenster mit ziemlich vielen Zeilen.<br />
<li>In die Box ''Intent Schema'' kopiert man den ersten Teil dieser FHEM-Ausgabe hinein, also:<br/><blockquote><br />
{ <br />
"intents" : [ <br />
<hier ziemlich viele Zeilen> <br />
]<br />
}<br />
</blockquote></li><br />
<li>Nun die ''Custom Slot Types'' einrichten. Dazu muss aus dem zweiten Teil der FHEM-Ausgabe jeweils der Slot-Type (z.B. <code>FHEM_article</code>) in das Feld ''TYPE'' eingetragen werden, das nach dem Anklicken von ''Add Slot Type'' erscheint. In das darunter liegende größere Textfeld kommen die möglichen Werte für diesen Slot, so wie sie aus der FHEM-Ausgabe abzulesen sind. Dann mit ''Save'' sichern. Als Custom Slot Type erscheint dann für diesen Beispiel-Slot<br />
FHEM_article der | die | das | den<br />
d.h., die Zeilenumbrüche bei den möglichen Werten werden als "|" dargestellt.</li><br />
<li>Hier muss nun ein Bruch im Arbeitsfluss durchgeführt werden, denn bei der Erstellung des Custom Skills kommt es auf die Reihenfolge der Einträge an. Deshalb zunächst diese FHEM-Ausgabe schließen, und für dasselbe FHEM-Device <code>get MyAlexa customSlotTypes</code> ausführen. Auch diese Ausgabe wird, wie oben beschriebeen, in Custom Slot Types eingetragen (erst der TYPE, dann die möglichen Werte)<br />
<li>Anschließend erneut die FHEM-Ausgabe schließen und erneut für das bereits definierte Alexa-Gerät das Kommando <code>get MyAlexa interactionModel</code> aufrufen.<br />
<li>Unter ''Sample Utterances'' nun den Text aus dem dritten Teil dieser FHEM-Ausgabe hineinkopieren<br />[[Datei:CustomSkill_5.PNG|400px]]</li><br />
</ul></li><br />
<li>Auf der Seite ''Configuration'' Folgendes eingeben und mit ''Next'' bestätigen:<br />
<ul><br />
<li>''Service Endpoint Type'' -> ''AWS Lambda'' auswählen</li><br />
<li>''Geographical Region'' -> ''Europe'' auswählen und im Textfeld den Wert aus Abschnitt [[#AWS_Lambda_Funktion_anlegen | AWS Lambda Funktion anlegen]] (Punkt 12) eintragen. </li><br />
<li>''Do you allow users to create an account or link to an existing account with you?'' -> ''Yes''</li><br />
<li>''Authorization URL'' -> <code>https://www.amazon.com/ap/oa</code></li><br />
<li>''Client ID'' -> ''Client ID'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1</li><br />
<li>''Scope'' -> <code>profile:user_id</code> (wörtlich 1:1 eintragen)</li><br />
<li>''Redirect URLs'' - sollten vorbelegt sein</li><br />
<li>''Authorization Grant Type'' -> ''Auth Code Grant'' auswählen</li><br />
<li>''Access Token URI'' -> <code>https://api.amazon.com/auth/o2/token</code></li><br />
<li>''Client Secret'' -> ''Client Secret'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1</li><br />
<li>''Client Authentication Scheme'' -> ''HTTP Basic''</li><br />
<li>''Privacy Policy URL'' -> <code>https://www.amazon.com/gp/help/customer/display.html?nodeId=468496</code></li><br />
</ul><br />
Beim Sichern dieser Seite mit ''Next'' kann es zu einer Fehlermeldung kommen, wenn man seine Skill-Definitionen mit dem einfachen SmartHome-Skill begonnen hat. Deshalb muss noch der entsprechende Trigger für die [[#AWS_Lambda-Funktion | AWS Lambda Funktion]] nachgetragen werden, dies wird in Abschnitt [[#Trigger_f.C3.BCr_Custom_Skill_hinzuf.C3.BCgen | Trigger für Custom Skill hinzufügen]] beschrieben.<br />
<br />[[Datei:CustomSkill_6.PNG|400px]] [[Datei:CustomSkill_7.PNG|400px]]</li><br />
<br />
==== Testen ====<br />
Hat man den Custom Skill angelegt, bietet dieser auch eine komfortable Testmöglichkeit. Dazu wählt man in der Übersichtsseite ''All Skills'' den Button ''Edit'' des Alexa Custom Skill aus. Auf der nachfolgenden Seite dann links ''Test''. <br />
Die Testseite enthält <br />
* ein Feld ''Voice Simulator'', mit dem man die Sprachsausgabe testen kann, <br />
* ein Feld ''Service Simulator'', mit dem die Verarbeitung von Alexa-Kommandois getestet werden kann. Hier kann man z.B. eintragen<br />
"Alexa, sage <Custom Skill Invocation Name>: Stelle Weckzeit auf Neunzehn Siebenundzwanzig Uhr"<br />
"Alexa, frage <Custom Skill Invocation Name> nach dem Status von Weckzeit"<br />
Dabei ist natürlich der ''Custom Skill Invocation Name'' durch den Wert zu ersetzen, den man im Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]] unter Punkt 2 eingetragen hat.<br />
<br />
==== Skill Id bestimmen ====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Hier wird beschrieben, wo die ''Alexa Skill Id'' zu finden ist}}<br />
Für das [[#AWS_Lamba_Funktion_anlegen | Anlegen einer ''AWS Lambda Funktion'']] bzw für die [[#Alexa-Fhem_konfigurieren | Konfiguration von Alexa-Fhem]] wird die ''Alexa Skill Id'' benötigt. An diese kommt man wie folgt:<br />
# Anmelden wie unter [[#Alexa_Skills | Alexa Skills]] beschrieben.<br />
# Menüpunkt ''ALEXA'' auswählen, wie [[#Skills_bearbeiten | Skills bearbeiten]] erklärt.<br />
# Beim gewünschten Eintrag auf ''Edit'' klicken<br />[[Datei:Developer.amazon.com-23-alexa_-_alex_skills_kit_-_overview.png|200px]]<br />
# Die Id, die nun oben angezeigt wird, ist die gesuchte. Sie hat typischerweise das Format <code>amzn1.ask.skill.[Zahlen und Bindestriche]</code><br />[[Datei:Aws.amazon.com-06-configure_triggers2.png|200px]]<br />
<br />
<hr><br />
<br />
=== AWS Lambda Funktion ===<br />
Für folgende Schritte muss man unter der Adresse http://aws.amazon.com angemeldet sein<br />
# Anmeldung auswählen<br />[[Datei:Aws.amazon.com-01-site.png|200px]]<br />
# Anmeldedaten eingeben<br />[[Datei:Aws.amazon.com-02-login.png|200px]]<br />
# Den Punkt ''Lambda'' links auf der Startseite auswählen, bzw. im Menü ''Services'' unter ''Compute'' den Menüpunkt ''Lambda'' auswählen<br />[[Datei:Aws.amazon.com-03-lambda.png|200px]]<br />
==== AWS Lambda Funktion anlegen ====<br />
# Für eine erste Lambda-Funktion den Punkt ''Get Started Now'' auswählen<br />[[Datei:Aws.amazon.com-04-get_started_now.png|200px]]<br />
# Den Blueprint ''Blank function'' auswählen<br />[[Datei:Aws.amazon.com-05-select_blueprint.png|200px]]<br />
# Im neuen Fenster dann auf den gestrichelten Kasten klicken und ''Alexa Smart Home'' auswählen und mit ''Next'' bestätigen<br />[[Datei:Aws.amazon.com-06-configure_triggers1.png|200px]]<br />
## Achtung, es ist möglich, dass dabei ''Alexa Smart Home'' überhaupt nicht angeboten wird. Dann bitte ganz rechts oben in der Ecke nachsehen, welche Region bzw. welches Land ausgewählt ist. Empfohlen wird, ''Ireland'' auszuwählen. Dann erscheint bei den Funktionen auch ''Alexa Smart Home''.<br />
# Bei ''Application Id'' den Wert eintragen, dessen Ermittlung im Abschnitt [[#Skill_Id_bestimmen | Skill Id bestimmen]] beschrieben wird, den Haken bei ''Enable trigger'' setzen und mit ''Next'' bestätigen <br />[[Datei:Aws.amazon.com-06-configure_triggers3.png|200px]]<br />
# Auf der Konfigurationsseite eingeben:<br />
## ''Name'' -> ''FHEM''<br />
## ''Runtime'' -> Node.js 4.3. <br />
## ''Role'' -> ''Choose an existing role'' <br />
### Achtung: wenn es noch keine existing role gibt, zuerst ''Create a custom role'' -> in dem Popup dann ''lambda_basic_execution'' auswählen und auf ''Allow'' klicken sowie bei ''Existing role'' dann ''x'' wählen.<br />
# Auf der Code-Seite wird bzw. im großen Textfeld ist dann der Code aus der Datei ''lambda.js'' im Paket [[#Alexa-Fhem_installieren | Alexa-Fhem]] vollständig einzufügen. Dabei muss noch der Hostname im Quellcode an den eigenen Hostnamen angepasst werden. <br />
# Anschließend alles mit ''Next'' bestätigen.<br />[[Datei:Aws.amazon.com-07-configure_function.png|200px]]<br />
# Auf der Übersichtsseite dann ''Create function'' anklicken<br />[[Datei:Aws.amazon.com-08-review.png|200px]]<br />
<br />
==== Trigger für Custom Skill hinzufügen ====<br />
Editiert man eine Lambda-Funktion, werden auf der Seite ''Triggers'' diejenigen Dienste angezeigt, die diese Funktion aufrufen.<br />
* Hier taucht der Trigger ''Alexa Smart Home'' zusammen mit der ''Application Id'' auf, der bei der Einrichtung des SmartHome-Skills eingetragen wurde.<br />
* Zur Verbindung mit dem Custom Skill ist es nötig, einen zweiten Trigger hinzuzufügen. Durch Anklicken von ''Add Trigger'' wird eine Auswahlseite eingeblendet. Im neuen Fenster dann auf den gestrichelten Kasten klicken und ''Alexa Skills Kit' auswählen und mit ''Next'' bestätigen<br />
<br />
==== ARN der AWS Lambda Funktion bestimmen ====<br />
# Auf der Übersichtsseite oben links den Menüpunkt ''Functions'' aúswählen<br />[[Datei:Aws.amazon.com-09-go_overview.png|200px]]<br />
# Anschließend den Radiobutton der angelegten Funktion ''FHEM'' markieren und im Menü ''Action'' den Punkt ''Show ARN'' auswählen<br />[[Datei:Aws.amazon.com-10-1-show_arn.png|200px]]<br />
# Es wird nun eine ARN Adresse angezeigt, die für den Abschnitt [[#SmartHome_Skill_anlegen| SmartHome Skill anlegen]] benötigt wird<br />[[Datei:Aws.amazon.com-10-2-arn.png|200px]]<br />
<br />
=== Absichern des Zugriffs ===<br />
Natürlich muss der Zugriff auf den von Alexa-Fhem verwendeten Port (default: 3000, Bestandteil des Codes in der AWS Lambda-Funktion) durch die Firewall freigeschaltet werden (auf einer FritzBox unter "Portfreigaben").<br />
<br />
==== Absicherung direkt in Alexa-FHEM ====<br />
Die Kommunikation zwischen Amazon AWS und Alexa-FHEM ist auf die folgenden Arten gesichert:<br />
* Die Verbindung erfolgt per HTTPS<br />
* Es werden nur Verbindung angenommen auf denen ein gültiges Alexa-Event gesendet wird. <br />
* Es werden nur Verbindungen angenommen die ein gültiges und noch nicht abgelaufenes OAuth-Token enthalten. Jedes neue Token wird live bei Amazon auf Gültigkeit geprüft. <br />
* Es werden nur Verbindungen mit lokal konfigurierter Skill-ID angenommen.<br />
* Es ist nicht möglich von außen beliebige FHEM Kommandos zu senden. Die FHEM Kommandos werden nur lokal erzeugt.<br />
<br />
Wer möchte kann Alexa-FHEM natürlich noch weiter absichern. Es gilt aber, dass nicht jedes zusätzliche Glied in der Kette die Sicherheit sondern unter Umständen nur die Angriffsfläche erhöht. Ein falsch konfigurierter und nach aussen offener Apache (oder anderer ReverseProxy) ist unter Umständen ein größeres Risiko als Alexa-FHEM alleine.<br />
<br />
==== Absicherung per ReverseProxy ====<br />
<s>Die Kommunikation zwischen Amazon und FHEM ist wegen der Verwendung von SSL schon verschlüsselt - prinzipiell kann aber jeder von außen mit Alexa-Fhem kommunizieren. Man sollte sich deshalb im Klaren darüber sein, dass dies eine Sicherheitslücke darstellt:</s> Jeder offene Port verleitet zu Angriffen, und mit zunehmender Verbreitung von Alexa steigt auch das Risiko. Es wird deshalb empfohlen, vor den eigentlichen Alexa-Server zur Absicherung einen Apache-Webserver als ReverseProxy zu setzen. Nicht nur ist der Apache eine hervorragend stabile und seit Jahrzehnten getestete Software, sondern die Konfiguration als ReverseProxy erlaubt auch, den Zugriff auf den Alexa-Fhem-Rechner auf die Amazon-Maschinen zu beschränken.<br />
<br />
'''Achtung: Dies ist keine allgemeine Anleitung in Sachen Computersicherheit.''' Im Folgenden gehen wir davon aus, dass <br />
* Grundbegriffe wie Firewall, IP-Ports, SSL und Dynamic DNS vertraut sind<br />
* Ein Apache Webserver (idealerweise auf einer zweiten Maschine) bereits installiert ist und die Konfiguration verstanden wurde (wenn nicht: Es gibt im Netz ''tausende'' von Anleitungen dafür...)<br />
* Ein Servername von einem DynDNS-Anbieter - sagen wir ''myhome.is-my-castle.com'' - bereits von ''außen'' auf unser SmartHome zeigt.<br />
* Alexa-Fhem in einer der oben beschriebenen Basiskonfigurationen läuft, d.h. der Zugriff auf <code>https://myhome.is-my-castle.com:3000</code> ergibt, wie im Punkt [[#Alexa-Fhem_testen|Alexa-Fhem testen]] beschrieben, eine Antwort des Node.js Servers.<br />
<br />
Als erster Schritt zur Absicherung muss das ReverseProxy Modul für den Apache installiert und mit <code>a2enmod</code> aktiviert werden, hierzu sei auf [https://www.digitalocean.com/community/tutorials/how-to-use-apache-http-server-as-reverse-proxy-using-mod_proxy-extension diese Anleitung] verwiesen. Der zweite Schritt besteht darin, den SSL-Zugriff durch ein Passwort abzusichern. Dazu wird auf dem Apache-Rechner das Programm <br />
htpasswd <passwdfile> <username><br />
ausgeführt, das Programm fragt dann nach dem gewünschten Passwort. Wir nehmen im Folgenden an, dass das Passwortfile ''/etc/apache2/htpasswd'' ist, der gesetzte Username ''alexa'' lautet und das Passwort ''my_smarthome'' ist.<br />
<br />
Im dritten Schritt wird nun in das Apache-Konfigurationsfile die Weiterleitung auf den eigentlichen Alexa-Fhem-Rechner eingetragen. Dazu wählen wir, dass von außen der Standard-SSL-Port 443 benutzt werden soll, sowie als Verzeichnisname ''/alexa''. '''Achtung:''' Dieser Code soll '''nicht''' in die Default-Konfiguration des Apache-Webservers. Sondern in eine separate Datei (Dateiname z.B. "fhem"), die ins Unterverzeichnis /etc/apache2/conf.d gestellt wird.<br />
<br />
<VirtualHost *:443><br />
ServerName myhome.is-my-castle.com<br />
SSLEngine on<br />
SSLProxyEngine on<br />
SSLProxyCheckPeerCN off<br />
SSLProxyCheckPeerName off<br />
SSLCertificateKeyFile /etc/apache2/mycert/server.key<br />
SSLCertificateFile /etc/apache2/mycert/server.crt<br />
<Location /alexa><br />
AuthType Basic<br />
AuthName "Authentication Required"<br />
AuthUserFile "/etc/apache2/htpasswd"<br />
Require valid-user<br />
ProxyPass https://<hier IP-Adresse des Alexa-Fhem-Rechners>:3000/<br />
ProxyPassReverse https://<hier IP-Adresse des Alexa-Fhem-Rechners>:3000/<br />
Order deny,allow<br />
Allow from All<br />
</Location><br />
(... Hier eventuell weitere Umleitungen)<br />
</VirtualHost><br />
Nach einem Neustart des Apache-Servers, dem Schließen des Ports 3000 in der Firewall sowie dem Öffnen des Ports 443 ist der Alexa-Fhem-Rechner von außen nur noch erreichbar durch den Aufruf von <code>https://myhome.is-my-castle.com/alexa</code> und verlangt unmittelbar die Eingabe von Username und Passwort.<br />
<br />
Der vierte Schritt ist nun, den Code der AWS Lambda-Funktion an fünf Stellen zu verändern<br />
'''const PORT=443;'''<br />
const HOST='myhome.is-my-castle.com';<br />
'''const PATH='/alexa';'''<br />
'''const AUTH='alexa:my_smarthome';'''<br />
// entry<br />
exports.handler = function(event, context, callback) {<br />
console.log(`EVENT: ${event}`);<br />
console.log(`CONTEXT: ${context}`); <br />
var post_data = JSON.stringify(event);<br />
var options = {<br />
hostname: HOST,<br />
port: PORT,<br />
//family: 6,<br />
'''path: PATH,'''<br />
method: 'POST',<br />
'''auth: AUTH,'''<br />
rejectUnauthorized: false, // accept self-signed<br />
(etc., Rest des Codes wie gehabt)<br />
Natürlich muss der Zugriff getestet werden. Bei Beachtung aller dieser Schritte werden alle un-autorisierten Zugriffe von außen abgewehrt. Eine noch weiter gehende Sicherung ist möglich, dazu kann in der Serverkonfiguration der Zugriff auf die Amazon-Domains beschränkt werden. Das ganze Alexa-System ist aber noch in konstanter Weiterentwicklung, diese Domain-Namen können sich also noch ändern.<br />
<br />
== Einrichtung in der Alexa App==<br />
Nachdem die Alexa Skills angelegt wurden, müssen diese noch in der Alexa App eingerichtet werden.<br />
Dafür jeweils per Desktop-Browser auf [http://alexa.amazon.de alexa.amazon.de] anmelden, nicht die App unter iOS oder Android verwenden. Diese hat Probleme mit der OAuth Verknüpfung.<br />
<br />
=== Alexa Skill ===<br />
# Auf ''Skills'' klicken<br />[[Datei:Alexa.amazon.de-01-startseite.png|200px]]<br />
# Oben rechts ''Meine Skills'' bzw. ''Ihre Skills'' auswählen<br />[[Datei:Alexa.amazon.de-03-meine_skills.png|200px]]<br />
# In der Liste der Skills sollte das angelegte FHEM Skill angezeigt werden. Dieses anklicken<br />[[Datei:Alexa.amazon.de-02-liste_skills.png|200px]]<br />
# Oben Rechts in den Details des Skills auf ''Skill aktivieren'' klicken<br />[[Datei:Alexa.amazon.de-04-skill_details.png|200px]]<br />
# In dem neu geöffneten Fenster die Autorisierung bestätigen<br />[[Datei:Alexa.amazon.de-05-amazon_auth.png|200px]]<br />
# Anschließend sollte die Verbindung erfolgreich aufgebaut worden sein <br />[[Datei:Alexa.amazon.de-06-success.png|200px]]<br />
<br />
=== Geräte ===<br />
# Auf http://alexa.amazon.de anmelden<br />
# Auf ''Smart Home'' klicken<br />[[Datei:Alexa.amazon.de-01-startseite.png|200px]]<br />
# Anschließend den Punkt ''Geräte suchen'' anklicken<br />[[Datei:Alexa.amazon.de-07-Gerätesuche.png|200px]]<br />
# Wurde soweit alles korrekt eingerichtet, werden nun die gefundenen Geräte angezeigt.<br />
<br />
Tip: Es macht Sinn, unter ''Meine Gruppen'' Gruppen benannt nach den Räumen einzurichten. Hierdurch kann Alexa die Geräte besser auseinander halten, vor allem wenn die den gleichen Alias (z.B. "Licht") haben.<br />
<br />
== Einrichtung unter FHEM ==<br />
Im Folgenden werden exemplarisch ein paar Geräte beschrieben, die man nutzbringend mit FHEM einsetzen kann.<br />
<br />
Bei Verwendung des Custom Skills übersetzt die Kombination der Attribute ''alexaMapping'' und ''homebridgeMapping'' Sprachbefehle ("Intents") in gerätespezifische Kommandos. <br />
* Das Attribut alexaMapping wird am Alexa-Device gesetzt und dient dazu, erkannte Sprachkommandos in abstrakte Characteristiken zu überführen. Für den einfacheren SmartHome Skill hat darum das Attribut ''alexaMapping'' keine Bedeutung, sondern nur der ''genericDeviceType'' des zu steuernden Gerätes.<br />
* Das Attribut homebridgeMapping wird für beide Skills am zu steuernden Gerät gesetzt und übersetzt diese Charakteristiken in die konkreten Befehle, die das Gerät versteht. Der inhalt des Attributs wird von links nach rechts ausgewertet und ist wie folgt aufgebaut:<br />
** Das Attribut enthält eine durch Leerzeichen getrennte Liste aus Konfigurationen für jeweils eine Characteristik<br />
** Jede einzelne der Characteristik-Konfigurationen besteht aus dem Namen der Characteristik, gefolgt von "=" und einer kommaseparierten Liste von Parametern.<br />
attr <device> homebridgeMapping <Characteristic1>=<param1.1>,<param1.2>,... <Characteristic2>=<param2.1>,<param2.2>,...<br />
** Jeder Parameter besteht entweder aus<br />
*** <code><cmd>:<device>:<reading></code>, hier können nicht verwendete Elemente von links nach rechts weg gelassen werden.<br />
*** <code><name>=<value></code>, hier kann <code><value></code> entweder ein Wert oder semikolonseparierte Liste sein.<br />
*** Oder dem schlüsselwort <code>clear</code>, welches alle vorhandenen (default) Parameter dieser Characteristik löscht. <code>clear</code> kann auch an Stelle einer ganzen Characteristik-Konfiguration stehen<br />
Weiter führende Dokumentation zum homebridgeMapping findet sich unter https://forum.fhem.de/index.php/topic,48558.0.html<br />
<br />
=== Einfacher Schalter ===<br />
* Ein einfacher Schalter, der die set-Kommandos ''on'' und ''off'' kennt, kann direkt mit Alexa-Fhem gekoppelt werden <br />
* Für kompliziertere Aktionen, etwa das Übermitteln eines spezifischen Schaltbefehls an FHEM, ist die Einrichtung eines Dummies zu empfehlen. <br />
Ob Dummy oder nicht, wichtig sind die drei fett gedruckten Zeilen<br />
define Alexa.Party dummy<br />
'''attr Alexa.Party alexaName party'''<br />
'''attr Alexa.Party alexaRoom alexaroom'''<br />
'''attr Alexa.Party genericDeviceType switch'''<br />
attr Alexa.Party group AlexaGeräte<br />
attr Alexa.Party room AlexaRoom<br />
'''attr Alexa.Party setList on off'''<br />
Selbstverständlich kann man diesen Dummy mit einem notify oder DOIF abfangen, um die gewünschte Schaltaktion auszuführen. <br />
<br />
Ein Alternative zum Dummy ist das Anlegen eines readingsProxy, dem die entsprechenden Attribute gegeben werden.<br />
<br />
Weil es sich hierbei um eines der einfachen Geräte handelt, die Alexa selbst im SmartHome Skill bearbeiten kann, ist auch der zweite Schritt bei der Einrichtung in der Alexa App sinnvoll: Der Schalter wird dann im Bereich Smart Home der Alexa App erkannt. Wer ihn auch mit dem Custon Skill bedienen möchte, muss natürlich Sorge tragen, dass der Alexa-Name ''party'' bei den FHEM_Devices auftaucht und die entsprechenden weiteren Slot Types und Example Utterances in der Konfiguration des Custom Skills vorhanden sind (siehe Abschnitt [[##Custom_Skill_anlegen | Custom Skill Anlegen]]).<br />
<br />
=== Wecker ===<br />
Dieses Gerät kann man nur mit dem Custom Skill bedienen, es wird also '''nicht''' im Bereich Smart Home der Alexa App auftauchen. Wir richten einen Dummy ein, wichtig sind wieder die fett gedruckten Zeilen:<br />
define Alexa.Weckzeit dummy<br />
'''attr Alexa.Weckzeit alexaName weckzeit'''<br />
'''attr Alexa.Weckzeit alexaRoom alexaroom'''<br />
attr Alexa.Weckzeit genericDeviceType clock<br />
attr Alexa.Weckzeit group AlexaGeräte<br />
'''attr Alexa.Weckzeit homebridgeMapping Weckzeit=state,cmd=+'''<br />
attr Alexa.Weckzeit room AlexaRoom<br />
'''attr Alexa.Weckzeit setList Weckzeit:time'''<br />
Das Attribut ''genericDeviceTye'' ist nicht wichtig, weil es ein generisches Device dieser Art gar nicht gibt. Wichtig hingegen ist das Attribut ''homebridgeMapping'' <br />
<br />
Für das Gerät ''MyAlexa'', das in Abschnitt definiert wurde, muss im Attribut ''alexaMapping'' auftauchen<br />
Weckzeit=verb=stelle,valuePrefix=für;auf,values=AMAZON.TIME,valueSuffix=uhr<br />
Darüber hinaus muss der Alexa-Name ''weckzeit'' bei den FHEM_Devices auftauchen und die entsprechenden weiteren Slot Types und Example Utterances in der Konfiguration des Custom Skills vorhanden sein (siehe Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]]).<br />
<br />
Der Aufruf dieses Gerätes mit Alexa erfolgt dann z.B. mit den Sätzen<br />
<pre style="width:50%;"><br />
"Alexa, sage <Custom Skill Invocation Name>: Stelle Weckzeit auf Neunzehn Uhr Siebenundzwanzig"<br />
"Alexa, frage <Custom Skill Invocation Name> nach dem Status von Weckzeit"<br />
</pre><br />
Dabei ist natürlich der ''Custom Skill Invocation Name'' durch den Wert zu ersetzen, den man im Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]] unter Punkt 2 eingetragen hat.<br />
<br />
Zur weiteren Bearbeitung kann man jetzt mit einem DOIF Statusänderungen des Dummies abfangen und durch eine kleine Helperfunktion ins "echte" FHEM weiterleiten.<br />
define Alexa.Weckzeit.N DOIF (["Alexa.Weckzeit:.*"])({AlexaHelper("Alexa.Weckzeit","$EVENT")}) <br />
Die Helperfunktion (z.B. in 99_myUtils.pm) stellt aus der übergebenen Zeit (immer im Format dd:mm) eine sprachkompatible Nachricht $nc und einen mit den FHEM-Zeitangaben kompatiblen String $nt zusammen und reicht beide an eine Routine ''changeWakeTime'' weiter (dokumentiert in den [https://www.dpunkt.de/buecher/12387/9783960090120-smarthome-hacks.html Smart Home Hacks]).<br />
sub AlexaHelper($$){<br />
my ($name,$event)=@_;<br />
if( $name eq "Alexa.Weckzeit" ){ <br />
my ($nc,$nt);<br />
#-- volle Stunde----------------------------------------<br />
if( $event =~ /(\d+):00/ ){<br />
$nc=sprintf("%d Uhr",$1);<br />
$nt=sprintf("%02d:00:00",$1);<br />
#-- nicht volle Stunde---------------------------------<br />
}elsif( $event =~ /(\d+):(\d+)/ ){<br />
$nc=sprintf("%d Uhr %d",$1,$2);<br />
$nt=sprintf("%02d:%02d:00",$1,$2);<br />
}<br />
changeWakeTime(\'GalaxyTab.EG\',\'$nc\',\'$nt\');<br />
}<br />
}<br />
<br />
<hr><br />
<br />
=== Lichtszene ===<br />
Eine Lichtszene wird mit dem Modul LightScene angelegt. Wir gehen davon aus, dass in der Lichtszene die beiden Szenen Alle_An und Alle_Aus, sowie mindestens eine weitere Szene (hier: Sitzgruppe) definiert wurde.<br />
* Nachfolgend wird ein Beispiel beschrieben, wie man eine Lichtszene mit dem einfachen SmartHome Skill steuern kann. Die verwendeten Kommandos sind dann<br />
<pre><br />
"Alexa, schalte (die) Beleuchtung an" -> LightScene Alle_An wird ausgewählt<br />
"Alexa, schalte (die) Beleuchtungsitzgruppe an" -> LightScene Sitzgruppe wird ausgewählt<br />
...<br />
"Alexa, schalte (die) Beleuchtung aus" -> LightScene Alle_Aus wird ausgewählt<br />
</pre><br />
* Künftig wird man LightScene mit dem Custom Skill eventuell direkt steuern können - allerdings hat das einen geringeren WAF, als die Steuerung über den SmartHome Skill: Der Einschaltsatz muss dann mindestens lauten<br />
<pre><br />
"Alexa, sage <Custom Skill Invocation Name>: schalte (die) Beleuchtung an" -> LightScene Alle_An wird ausgewählt<br />
</pre><br />
Dafür wird es aber auch möglich sein direkt die SzenenNamen im gesprochenen Kommando zu verwenden und so auf die Umwege über dummys und ähnliches zu verzichten.<br />
<br />
<br />
Im ersten Schritt wird ein Dummy für die Gesamtbeleuchtung eingerichtet:<br />
define Alexa.Beleuchtung dummy <br />
attr Beleuchtung setList on off<br />
'''attr Alexa.Beleuchtung alexaName beleuchtung'''<br />
'''attr Alexa.Beleuchtung alexaRoom alexaroom'''<br />
'''attr Alexa.Beleuchtung genericDeviceType switch'''<br />
Anschließend wird für jede vorhandene Lichtszene (außer Alle_An und Alle_Aus) ein weiterer Dummy angelegt:<br />
define Alexa.Beleuchtung.Sitzgruppe dummy <br />
attr Beleuchtung setList on off<br />
'''attr Alexa.Beleuchtung.Sitzgruppe alexaName beleuchtungsitzgruppe'''<br />
'''attr Alexa.Beleuchtung.Sitzgruppe alexaRoom alexaroom'''<br />
'''attr Alexa.Beleuchtung.Sitzgruppe genericDeviceType switch''' <br />
Die eigentliche Steuerung übernimmt dann ein DOIF<br />
define Alexa.Beleuchtung.N DOIF<br />
(["Alexa.Beleuchtung.Sitzgruppe:on"])<br />
(set <devicename der Lichtszene> scene Sitzgruppe,<br />
set Alexa.Beleuchtung off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
DOELSIF<br />
... <weitere on-Events der anderen Szenen werden abgefangen><br />
DOELSEIF<br />
(["Alexa.Beleuchtung:on"])<br />
(set <devicename der Lichtszene> scene Alle_An,<br />
set Alexa.Beleuchtung.Sitzgruppe off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
DOELSEIF<br />
(["Alexa.Beleuchtung:off"])<br />
(set <devicename der Lichtszene> scene Alle_Aus,<br />
set Alexa.Beleuchtung.Sitzgruppe off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
Mit diesem DOIF wird ein Radiobutton simuliert, d.h. wie bei den Stationstasten vor Uralt-Radios sorgt die Auswahl einer Szene immer dafür, dass alle anderen Dummies ausgeschaltet werden.<br />
Natürlich kann man das auch mit einem kleinen Perl-Programm erreichen.<br />
<br />
<br />
Zwei andere Ansätze Lichtszenen zu schalten die ohne DOIF auskommen sind im Folgenden beschrieben:<br />
<br />
* Wenn es von Interesse ist die Steuerung mit einer Darstellung in FTUI zu verbinden: Statt der oben beschriebenen dummy Devices kann man readingsProxy Devices mit passenden setFn und valueFn analog zum [[Harmony#Button_f.C3.BCr_eine_bestimmte_Activity_im_Frontend_und_Homekit_.C3.BCber_readingsProxy|diesem Beispiel für harmony aktivitäten]] verwenden.<br />
<br />
* Für jede zu schaltende Szene wird ein dummy angelegt dessen homebridgeMapping direkt auf das LightScene Device zeigt:<br />
<br />
define <dummy> dummy<br />
attr <dummy> setList on off<br />
attr <dummy> genericDeviceType switch<br />
attr <dummy> homebridgeMapping On=<light scene>::state,valueOn=<szene>,cmdOn=scene+<szene>,cmdOff=scene+<szene aus><br />
<br />
Bei der zweiten Variante wird davon ausgegangen das der aktuelle status nicht abgefragt oder angezeigt werden soll. Deshalb gibt es keine direkte RadioButton Funktionalität.<br />
<br />
== Nutzung ==<br />
Um den Namen zu bestimmen, unter dem ein Gerät mit Alexa angesprochen wird, verwendet Alexa-Fhem mit absteigender Priorität:<br />
* das alexaName Attribut<br />
* das alias Attribut<br />
* das NAME Internal<br />
Damit Alexa ein Gerät eindeutig identifizieren kann, sollten eindeutige Gerätenamen verwendet werden, bestehed möglichst aus einem Wort und ohne Ziffern. Wenn Alexa einen Namen nicht versteht, kann man unter [http://alexa.amazon.de/spa/index.html] nachsehen was tatsächlich verstanden wurde und den Gerätenamen ggf. anpassen.<br />
<br />
=== SmartHome Skill ===<br />
Gruppen (Räume) müssen in der Alexa App konfiguriert werden. Über das API lassen sich nur der Name und die Schalteigenschaften übergeben.<br />
<br />
Nach erfolgreicher Einrichtung des SmartHome Skills sollte Alexa mit den folgenden Befehlen nutzbar sein:<br />
<pre style="width:50%;"><br />
“alexa, schalte <gerät/gruppe> ein”<br />
“alexa, schalte <gerät/gruppe> aus”<br />
“alexa, stelle <gerät/gruppe> auf <wert> prozent”<br />
“alexa, stelle <gerät/gruppe> auf <anzahl> grad”<br />
“alexa, erhöhe <gerät/gruppe> um <anzahl> prozent”<br />
“alexa, reduziere <gerät/gruppe> um <anzahl> prozent”<br />
“alexa, erhöhe <gerät/gruppe> um <anzahl> grad”<br />
“alexa, reduziere <gerät/gruppe> um <anzahl> grad”<br />
</pre><br />
<br />
=== Custom Skill ===<br />
Der Custom Skill erlaubt im Gegensatz zum SmartHome Skill eine weitreichende Konfiguration der möglichen Kommandos.<br />
<br />
Das Prinzip der Kommandokonfiguration ist {{Link2Forum|Topic=60244|Message=532513|LinkText=im Forum}} beschrieben.<br />
<br />
TODO: Abfragen, Attribute (alexaMapping, alexaTypes, fhemIntents, articles, prepositions)<br />
<br />
== Troubleshooting ==<br />
<br />
====Allgemeiner Hinweis====<br />
Besonders wichtig ist, dass man sich sehr genau an diese Anleitung hält. Ein häufiger Fehler ist, dass die einfachen Anführungszeichen in der Anleitung unter '''AWS Lambda Funktion anlegen''' Punkt 8 einfach weggelassen werden. Diese sind zwingend notwendig. Es darf auch nur der reine Hostname eingetragen werden. Also kein ''http://'' davor. Entweder eine feste IP Adresse oder den Hostnamen, um den Rechner zu erreichen, den ihr über den Port 3000 freigegeben habt. Das sollte dann so aussehen:<br />
<pre style="width:50%;"><br />
const PORT=3000;<br />
const HOST='mein.host.name';<br />
</pre><br />
<br />
====Freigabe von Port 3000====<br />
{{Randnotiz|RNTyp=Fehl|RNText=Derzeit müsst ihr über einen echten IPv4 Anschluss verfügen, damit der Amazon Lambda-Server euch erreichen kann. DS-Lite Anschlüsse wie die von <b>UnityMedia</b> z.B. funktionieren derzeit leider nicht. Eine möglicher "Workaround" wird hier beschrieben: https://forum.fhem.de/index.php/topic,60244.msg518276.html#msg518276}}<br />
<br />
Auf dem Router muss der Port 3000 Protokoll TCP freigegeben werden. D.h. von außen muss man wenn man den Port 3000 aufruft, auf dem intern laufenden node.js Alexa-Dienst zugreifen können.<br />
Je nach Router gestaltet sich das Portforwarding bzw. die Portumleitung etwas schwieriger.<br />
<br />
Bei einem Speedport Router der Telekom beispielsweise, muss der Router komplett neu gestartet werden, wenn die Portfreigabe eingerichtet wurde. <br />
<br />
Bei der Fritz!Box ist das nicht nötig, bei dieser finden die Freigabe unter ''Internet -> Freigaben -> Portfreigaben'' statt. Dort wählt man dann den Rechner aus und richtet eine neue Freigabe ein. Wichtig hierbei ist, dass man Portfreigabe auswählt und nicht MyFRITZ!-Freigabe. Bei Port von bis trägt man 3000 ein, bei Port extern ebenfalls.<br />
<br />
Um die Portweiterleitung zu testen, solltet ihr euch auch nicht im gleichen Netz befinden. Viele Router blockieren den Netzaufruf aus dem gleichen Netz. Am besten testet ihr es, wenn ihr an eurem Mobiltelefon W-LAN deaktiviert und im Browser folgende Seite aufruft: ''https://mein.hostname:3000''. Wenn ihr im Browser dann einen Quellcode von Alexa seht, funktioniert die Portumleitung.<br />
<br />
Wenn bis hier alles funktioniert und es läuft dennoch nicht rund, liegt das Problem woanders. Kommt z.B. bei der Gerätesuche kein Request rein (sichtbar auf dem Bildschirm, wenn bin/alexa gestartet wurden), kann evtl. der Lambda-Dienst falsch konfiguriert sein.<br />
<br />
====Probleme mit node.js - npm install====<br />
<br />
Falls eine Fehlermeldung auftritt, dass "npm" nicht gefunden werden kann, bitte NodeJS entsprechend der Anleitung im Homebridge-Artikel vorgehen: [[Homebridge_einrichten#NodeJS_installieren|NodeJS installieren]] sowie [[Homebridge_einrichten#Python.2C_g.2B.2B.2C_MDNS_installieren|Python, g++, MDNS installieren]], siehe auch folgenden Abschnitt.<br />
<br />
====Es kommen diverse Fehlermeldungen beim Starten von alexa-fhem und es beendet sich====<br />
Wenn man auf der Konsole angemeldet ist, den Befehl<syntaxhighlight lang="bash" style="width:50%;">node -v</syntaxhighlight>eingeben. Ist die Version niedriger als die geforderte 0.12, muss eine neuere installiert werden. Hier darf man dann im Wiki unter [[Homebridge_einrichten#NodeJS_installieren]] nachschauen. NodeJS V4 sollte hierbei schon ausreichen. Solange die node.js Version nicht passt, gar nicht groß rum experimentieren! Bitte beachtet, dass alle Voraussetzungen unter [[Alexa-Fhem#Voraussetzungen]] erfüllt sind! Keine Experimente mit Versionen die darunter liegen.<br />
<br />
====Fehlermeldung ''NAT-PMP failed: Error: timeout'' Fehler angezeigt beim Start von alexa-fhem====<br />
Wenn ihr dann alexa-fhem über die Konsole startet und bekommt folgenden Fehler: ''NAT-PMP failed: Error: timeout'', lasst euch davon nicht irritieren. Das bedeutet lediglich, dass der Port nicht automatich freigegeben wurde über uPNP. Alternativ prüft, ob die Funktion der Portfreigabe via uPNP auf eurem Router aktiviert ist.<br />
<br />
====Nach Start auf der Console beendet sich Alexa-FHEM sofort wieder====<br />
Unmittelbar nach dem Start von Alexa-FHEM werden ein paar UPNP Fehlermeldungen ausgegeben. Unmittelbar danach beendet sich Alexa-FHEM wieder. <br />
<br />
Viele scheinen ein Problem mit UPNP auf dem Raspberry Pi zu haben. Wenn dieses Problem auftritt einfach in der <code>~/.alexa/config.json</code> die folgenden Zeilen rauslöschen:<br />
<br />
<pre><br />
"nat-pmp": "10.0.1.1",<br />
"nat-upnp": true,<br />
</pre><br />
<br />
Jetzt erneut Alexa-FHEM starten. Sollte nun laufen.<br />
<br />
====Was ist zu tun, wenn alexa-fhem keine Geräte findet?====<br />
Zunächst müssen die Geräte, die angesprochen werden wollen, unter FHEM ein neues Attribut zugewiesen bekommen. Dazu das Gerät in FHEM öffnen und das Attribut ''genericDeviceType switch'' hinzufügen, wenn es ein Schalter mit der Funktiona AN/AUS sein soll. Wenn man will, kann man dem Gerät jetzt noch über das Attribut ''alias'' eine besseren Namen geben, mit dem Alexa das Gerät dann auch finden kann.<br />
Anschließend muss alexa-fhem neu gestartet werden und die definierten Geräte sollten nun gefunden werden.<br />
<br />
====Was ist zu tun, wenn Alexa zwar Geräte findet, diese aber nicht angesprochen werden können?====<br />
Zuerst die Informationen zum Datenfluss ganz oben ansehen. Dann am besten von hinten nach vorne vorgehen:<br />
* wenn nichts bei alexa-fhem ankommt: port forwarding prüfen<br />
* wenn lambda.js nichts los wird: im cloudwatch log nachsehen<br />
* wenn bei lambda.js nichts ankommt: den trigger prüfen<br />
<br />
<br />
Zunächst sollte man sich unter ''http://aws.amazon.com'' das Logfile seiner erstellten Funktion anschauen. Ist überhaupt ein Logfile vorhanden? Falls nicht, liegt es vermutlich am Trigger.<br />
Den solltet ihr überprüfen. Scheinbar kommt es hin und wieder vor, dass dieser nicht gesetzt ist. Dazu einfach auf ''Triggers'' klicken und mit ''Add trigger'' erneut einen anlegen. Hier muss, wie in der Anleitung unter '''AWS Lambda Funktion anlegen''' Punkt 7, die ''Application Id'' stehen und der Haken bei ''Enable trigger'' gesetzt sein. Dann alexa-fhem neu starten.<br />
Wenn ihr Änderugen gemacht habt und den alexa-fhem Dienst noch nicht neu gestartet habt, wäre jetzt der richtige Zeitpunkt.<br />
<br />
====Was ist zu tun, wenn sich der Alexa-Service nicht starten lässt?====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Der User in der User= Directive von alexa.service muss Ausführungsrecht auf dem alexa binary haben (x), so wie auch mind. Lesezugriff auf dem Verzeichnis nach -U Option in der ExecStart= Directive und auch auf dem WorkingDirectory }}<br />
Schaut bitte in das Unterverzeichnis [alexa-fhem (also dort, wo Ihr Alexa-FHEM instelliert habt]/bin. Die dort befindliche Datei ''alexa'' muss ausführbar sein. Also z.B. so:<br />
<syntaxhighlight lang="bash" style="width:70%;">2755327 4 -rwxr-xr-x 1 pi pi 339 Nov 26 23:20 alexa</syntaxhighlight><br />
Sollte dies nicht der Fall sein bitte mit:<br />
<syntaxhighlight lang="bash" style="width:70%;">chmod +x alexa</syntaxhighlight><br />
die Datei ausführbar machen. Sofern der User "pi" Eigentümer ist, ist kein sudo erforderlich.<br />
<br />
Eine lauffähige Konfiguration ist {{Link2Forum|Topic=71612|Message=668383|LinkText=hier}} zu sehen.<br />
<br />
====Wie kann ich via Alexa-FHEM auf FHEM zugreifen, wenn der Port mit Benutzername/Kennwort geschützt ist?====<br />
<br />
Hierzu muss die Datei <code>~/.alexa/config.json</code> geöffnet werden und der Abschnitt "connections" um folgende Zeile ergänzt werden:<pre><br />
"auth": {"user": "fhem", "pass": "fhempassword"},</pre><br />
Bei Verwendung von SSL bei FHEM muss auch noch <pre><br />
"ssl": true,</pre> hinzugefügt werden<br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Sprachsteuerung]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=Alexa-Fhem&diff=22492Alexa-Fhem2017-09-06T01:11:58Z<p>Amenomade: /* Was ist zu tun, wenn sich der Alexa-Service nicht starten lässt? */ Ergänzung: Berechtigungen</p>
<hr />
<div>'''Alexa-Fhem''' ist eine in JavaScript geschriebene und auf NodeJS basierende Software, welche es ermöglicht, der digitalen Amazon Assistentin Alexa zusätzliche Skills für die Heimautomatisierung via FHEM beizubringen. Eine erste funktionierende Version wurde von [https://forum.fhem.de/index.php?action=profile;u=430 justme1968] im {{Link2Forum|Topic=60244|LinkText=Forum}} veröffentlicht.<br />
Das ist eine erste Version der Dokumentation zur Installation und Einrichtung, eine Erweiterung wird sicherlich in nächster Zeit noch folgen.<br />
{{Infobox Modul<br />
|ModPurpose=Anbindung von FHEM an Amazon Assistent Alexa<br />
|ModType=x<br />
|ModTechName=<br />
|ModForumArea=Frontends/Sprachsteuerung<br />
|ModOwner=justme1968<br />
}} <br />
<br />
<br />
==Einführung==<br />
===Glossar===<br />
*Echo bzw. Echo Dot (im Folgenden maskulin bezeichnet) sind die derzeit verfügbaren Geräte des Alexa-Systems '''BILDER EINSTELLEN - Achtung Urheberrecht'''<br />
*AVS ist der Amazon Voice Service, d.h. die Spracherkennungskomponente des Systems.{{Randnotiz|RNTyp=r|RNText=Für die Nutzung der Amazon AWS-Dienste müssen zwingend die Daten einer Kreditkarte angegeben werden. Nach gegenwärtigem Kenntnisstand sollen jedoch keine Kosten für die Nutzung der im Rahmen dieses How To beschriebenen Dienste anfallen, sofern diese in einem Rahmen genutzt werden, der selbst eine intensive private Nutzung nicht überschreitet. Der Benutzer sei an dieser Stelle auf die von Amazon veröffentlichten Preislisten verwiesen. Die Autoren dieser Anleitung und der darin beschriebenen Module übernehmen keine Haftung für eventuelle Kosten, die aus der Nutzung der AWS entstehen. }}<br />
*AWS sind die Amazon Web Services, also per URL erreichbare Dienste zur Ausführung von Berechnungen etc. Im Rahmen von Alexa-Fhem wird bei AWS eine eigene JavaScript-Funktion hinterlegt, die zur Kommunikation mit dem FHEM-Server dient. Im Jargon von Amazon ist dies eine so genannte Lambda-Funktion '''WARUM ? Nachlesen bei Amazon'''.<br />
*Card bezeichnet einen Eintrag in der Alexa-App, der die erkannte Sprachnachricht sowie weiter gehenden Informationen über die Reaktion von Alexa enzthält und Rückmeldung an Amazon erlaubt.<br />
*Skill (engl. für Fähigkeit) ist die Bezeichnung für eine per Spracherkennung bediente Funktionalität des Alexa-Systems, z.B. zur Nachrichtenansage, zur Wettervorhersage oder zur Steuerung von FHEM<br />
<br />
===Arbeitsweise und Datenfluss===<br />
[[Datei:2gpXyLN.jpg|200px|thumb|right|Grafische Darstellung der beteiligten Komponenten]]<br />
Echo -> AVS -> AWS Lambda -> alexa-fhem -> AWS Lambda -> AVS -> Echo<br />
<br />
*Der Echo (oder ein anderes Alexa/AVS fähiges Gerät) nimmt Audiodaten auf und schickt diese an AVS (Amazon Voice Service) zur Erkennung<br />
*AVS führt die Spracherkennung durch und erzeugt ein Event mit Informationen zu den erkannten Daten<br />
:*Beim Alexa SmartHome Skill sind die möglichen Sätze für die Spracherkennung relativ fest vorgegeben <br />
:*Beim Alexa Custom Skill kommen die dazu nötigen Informationen aus dem ''Interaction Model'' der Alexa Skills Configuration<br />
*Das Event wird an den unter ''Configuration'' in der Alexa Skills Configuration hinterlegten Endpoint geschickt<br />
:*Beim Alexa SmartHome Skill ist das zwingend eine AWS Lambda Routine<br />
:*Beim Alexa Custom Skill kann das im Prinzip auch ein eigener Web Service sein<br />
*Das Event wird vom <code>lambda.js</code> code an alexa-fhem weitergeleitet<br />
*alexa-fhem steuert FHEM und sendet ein Antwort-Event zurück<br />
*<code>lambda.js</code> nimmt diese Antwort entgegen und gibt sie an AVS zurück<br />
*AVS sogt dafür das der Echo 'antwortet' und dass die Card in der Alexa App erscheint<br />
<br />
===Anmerkungen===<br />
*Ein Skill hat keinen Zugriff auf die Audiodaten<br />
*Mit dem Skill API kann ein Skill zu zu keiner Zeit von sich aus aktiv werden und 'einfach' Daten an den Echo schicken oder ihn dazu bringen irgendetwas zu tun.<br />
*Wenn man berücksichtigt welchen Weg die Daten insgesamt gehen, ist es erstaunlich, wie schnell die Reaktion auf einen gesprochenen Satz erfolgt.<br />
<br />
=== Abgrenzung des '''Alexa Smart Home Skills''' und des '''Alexa Custom Skills''' ===<br />
<br />
Der [[Alexa-Fhem#Smart_Home|Alexa Smart Home Skill]] ist ein Amazon-Alexa-Standard-Skill, der wesentliche Basisfunktionalitäten bereitstellt. Zu diesen gehört im Wesentlichen die Funktionalität, durch Alexa-FHEM bereitgestellte Devices im Alexa-Account des Benutzers anzulegen. Der Alexa Smart Home Skill reagiert auf gesprochene Interaktion in einem beschränkten Umfang. Beispielsweise genügt ein "Alexa, schalte die Wohnzimmerlampe an" um eine Interaktion zwischen Alexa Smart Home Skill und FHEM-Alexa auszulösen. Nach erfolgreicher Einrichtung wird dieser Skill in der Alexa-App bzw. im Web in der Rubrik "Smart Home" als Skill angezeigt.<br />
<br />
Der [[Alexa-Fhem#Custom|Alexa Custom Skill]] ist kein Standard-Smart-Home-Skill, sondern ein individuell entwickelter Skill, so wie alle anderen Skills auch. Er wird daher auch nicht in der Alexa-App unter der Rubrik "Smart Home" angezeigt. Gesprochene Interaktion mit diesem Skill erfolgt dadurch, dass entweder der Skill explizit gestartet wird (z.B. "Alexa, starte [Name des Skills]") oder direkt angesprochen wird (z.B. "Alexa, frage [Name des Skills] wie ist der Status von [Device] "). Der Alexa Custom Skill befindet sich in Entwicklung und wird hinsichtlich seiner Funktionalitäten laufend weiterentwickelt. Die Einrichtung dieses Skills ist grundsätzlich optional, jedoch werden anspruchsvollere Steuerungsmöglichkeiten nur mit diesem realisiert werden können.<br />
<br />
==Installation==<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Da die einzelnen Schritte der Anleitung an verschiedenen Stellen unterbrochen und später fortgesetzt werden müssen, empfiehlt es sich, die Anleitung einmal vollständig gelesen zu haben. Während der Konfiguration sollten alle nachfolgenden Abschnitte parallel in gleichzeitig geöffneten Browserfenstern durchgeführt werden, die jeweils bis zum Abschluss geöffnet bleiben müssen. }}<br />
Grundvoraussetzung für alle folgenden Schritte ist das Vorhandensein eines Amazon-Accounts. Es wird davon ausgegangen, dass die Konten für alle im Folgenden genutzten Amazon-Dienste eingerichtet wurden.<br />
<br />
===node.js installieren===<br />
Zunächst wird das Betriebssystem (in diesem Falle Debian oder Ubuntu) auf den aktuellen Stand gebracht:<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
sudo apt-get update<br />
sudo apt-get upgrade<br />
sudo apt-get install build-essential libssl-dev</syntaxhighlight><br />
<br />
Nun muss NodeJS installiert werden. Leider ist die Version im Debian Repository deutlich zu alt, daher wird mit den folgenden Befehlen das Node Repository hinzugefügt und NodeJS (in der LTS Version) entsprechend installiert:<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -<br />
sudo apt-get install -y nodejs<br />
</syntaxhighlight><br />
<br />
=== Alexa-Fhem installieren ===<br />
'''Aus gegebenem Anlass: Dies ist weder eine Einführung in Linux, noch eine Anfängerdokumentation für FHEM.''' Also erst die Grundlagen lernen, und dann mit Alexa beginnen !<br />
<br />
Die aktuelle Version ist jeweils {{Link2Forum|Topic=60244|Message=540117|LinkText=hier}} zu finden.<br />
<br />
====Erstinstallation====<br />
Hier wird die Erstinstallation von Alexa-Fhem beschrieben.<br />
===== Linux =====<br />
# Die tgz-Datei unter Linux im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) entpacken (''nicht'' unter Windows, das zerstört die Rechteeinstellungen).<syntaxhighlight lang="bash" style="width:50%;">tar -xvzf dateiname.tgz</syntaxhighlight><br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen <syntaxhighlight lang="bash" style="width:50%;">mv package alexa-fhem</syntaxhighlight><br />
# Durch <syntaxhighlight lang="bash" style="width:50%;">cd alexa-fhem</syntaxhighlight> in das Verzeichnis wechseln<br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren (kein sudo!).<br />
# SSL Zertifikat erzeugen durch Aufruf von <syntaxhighlight lang="bash" style="width:50%;">./createKey.sh</syntaxhighlight> (kein sudo!). Hierbei beachten, dass ein Kennwort vergeben werden muss, das mindestens aus 4 Zeichen besteht, dieses Kennwort bitte merken.<br />
# Das Verzeichnis ''.alexa'' anlegen, ''und zwar im Home-Verzeichnis desjenigen Benutzers, unter dem Alexa-Fhem laufen soll.'' Insbesondere ist zu beachten, dass dieser Nutzer u.U. im Startskript explizit gesetzt wird. Mit dem untenstehenden Skript ist das ''nicht'' der User fhem, sondern der User ''pi''. Das Symbol ''~/'' verweist auf das Home-Verzeichnis des Benutzers, der gerade die Installation vornimmt.<br />
# Die Datei ''config-sample.json'' nach ''.alexa/config.json'' kopieren. Achtung: Installiert man alexa-fhem als root-user, zeigt das Symbol ''~/'' auf ''/root'' - und die Konfigurationsdatei wird ggf. bei einem manuellen Start von Alexa-Fhem nicht gefunden.<br />
# Achtung: Ggf. müssen auch die Dateien key.pem und cert.pem ins entsprechende Verzeichnis kopiert werden.<br />
===== Windows =====<br />
''Vor'' der Installation von Alexa-Fhem muss man folgende Anwendungen installieren:<br />
* Node.js (die aktuelle Version findet man unter https://nodejs.org/en/download/)<br />
* OpenSSL (http://slproweb.com/products/Win32OpenSSL.html oder https://www.heise.de/download/product/win32-openssl-47316/download)<br />
Erst dann fängt man mit Alexa-Fhem an.<br />
<br />
<br />
# Die tgz-Datei im Hauptverzeichnis von FHEM (z.B. <code>С:\Program Files (x86)\fhem</code>) entpacken.<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen<br />
# Windows-Shell (Kommandozeile, Eingabeaufforderung usw.) öffnen. "Start" -> "Ausführen" (oder [Windows-Taste]+[R]) -> cmd -> Ok. Durch <syntaxhighlight lang="bash" style="width:50%;">cd "<FHEM-Hauptverzeichis>\alexa-fhem"</syntaxhighlight> in das Verzeichnis wechseln. <br/>Dabei ist natürlich das <FHEM-Hauptverzeichis> durch den entsprechenden Pfad aus dem Schritt 1 zu ersetzen. Im o.g. Beispiel wäre es <code>cd "С:\Program Files (x86)\fhem\alexa-fhem"</code><br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren.<br/> Bei der Fehlermeldung wie "Der Befehl "npm" ist entweder falsch geschrieben oder konnte nicht gefunden werden." ist die Installation von Node.js zu überprüfen.<br />
# SSL Zertifikat erzeugen. Dafür muss man alle Befehle aus dem Skript ''createKey.sh'' nacheinander manuell ausführen. Hierbei beachten, dass ein Kennwort vergeben werden muss, das mindestens aus 4 Zeichen besteht, dieses Kennwort bitte merken. Der Windows-Welt unbekannter Befehl <code>mv</code> ist durch <code>move /y</code> zu ersetzen:<syntaxhighlight lang="bash" style="width:50%;">openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;">openssl rsa -in key.pem -out newkey.pem</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;">move /y newkey.pem key.pem</syntaxhighlight> Eventuelle Fehlermeldung "can't open config file: /usr/local/ssl/openssl.cnf" o.Ä. lässt sich durch Befehl <code>set OPENSSL_CONF=<OpenSSL-Verzeichnis>\bin\openssl.cfg</code> beheben, wobei <OpenSSL-Verzeichnis> durch den entsprechenden Installationspfad (typischerweise <code>c:\OpenSSL-Win32</code>) zu ersetzen ist.<br />
# Das Verzeichnis ''.alexa'' anlegen, ''und zwar im Benutzerverzeichnis desjenigen Benutzers, unter dem Alexa-Fhem laufen soll.'' In aktuellen Versionen von Windows (ab Windows 7 bzw. ab Windows Server 2008 R2) liegt das Verzeichnis unter <code>C:\Users\<Benutzername></code>, also z.B. für Benutzer "Administrator" - unter <code>C:\Users\Administrator</code>.<br/>Falls Windows sich weigert das Verzichniss mit dem Punkt am Anfang zu erstellen, kann man das aus der Kommandozeile machen:<syntaxhighlight lang="bash" style="width:50%;">cd "C:\Users\<Benutzername>"</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;"><br />
mkdir ".alexa"</syntaxhighlight><br />
# Die Datei ''config-sample.json'' nach ''C:\Users\<Benutzername>\.alexa\config.json'' kopieren.<br />
# Achtung: Ggf. müssen auch die Dateien key.pem und cert.pem ins entsprechende Verzeichnis (<code>"<FHEM-Hauptverzeichis>\alexa-fhem\bin</code>) kopiert werden.<br />
<br />
====Update====<br />
Hier wir das Update auf eine neue Version von Alexa-Fhem beschrieben<br />
===== Linux =====<br />
# Das Verzeichnis ''alexa-fhem'' im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) umbenennen in ''alexa-fhem.old''.<br />
# Die tgz-Datei der neuen Alexa-Fhem-Version unter Linux im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) entpacken (''nicht'' unter Windows, das zerstört die Rechteeinstellungen).<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen, in das Verzeichnis wechseln<br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren (kein sudo!).<br />
# Die Zertifikatsdateien key.pem und cert.pem aus dem alten Verzeichnis ''alexa-fhem.old'' ins neue Verzeichnis ''alexa-fhem'' kopieren.<br />
Natürlich dann den Dienst neu starten, auch müssen selbstredend irgendwelche Modifikationen an der Datei server.js in der neuen Version nachgezogen werden. Wenn alles läuft, kann das alte Verzeichnis ''alexa-fhem.old'' gelöscht werden.<br />
===== Windows =====<br />
# Das Verzeichnis ''alexa-fhem'' im Hauptverzeichnis von FHEM (z.B. <code>С:\Program Files (x86)\fhem</code>) umbenennen in ''alexa-fhem.old''.<br />
# Die tgz-Datei der neuen Alexa-Fhem-Version im Hauptverzeichnis von FHEM entpacken.<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen<br />
# Windows-Shell (Kommandozeile, Eingabeaufforderung usw.) öffnen. "Start" -> "Ausführen" (oder [Windows-Taste]+[R]) -> cmd -> Ok. Durch <syntaxhighlight lang="bash" style="width:50%;">cd "<FHEM-Hauptverzeichis>\alexa-fhem"</syntaxhighlight> in das Verzeichnis wechseln. <br/>Dabei ist natürlich das <FHEM-Hauptverzeichis> durch den entsprechenden Pfad aus dem Schritt 1 zu ersetzen. Im o.g. Beispiel wäre es <code>cd "С:\Program Files (x86)\fhem\alexa-fhem"</code><br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren.<br />
# Die Zertifikatsdateien key.pem und cert.pem aus dem alten Verzeichnis ''alexa-fhem.old'' ins neue Verzeichnis ''alexa-fhem'' kopieren.<br />
Natürlich dann den Dienst neu starten, auch müssen selbstredend irgendwelche Modifikationen an der Datei server.js in der neuen Version nachgezogen werden. Wenn alles läuft, kann das alte Verzeichnis ''alexa-fhem.old'' gelöscht werden.<br />
<br />
==== Alexa-Fhem konfigurieren ====<br />
Der Inhalt der Datei ''~/.alexa/config.json'' muss an die eigene Umgebung angepasst werden. <br />
# ''nat-pmp'' -> wenn nat-pmp verwendet werden soll: die ip des eigenen routers,<br />
# ''nat-upnp'' -> wenn nat-upnp verwendet werden soll: ''true'',<br />
# ''applicationId'' <br />
#:* Wenn man nur den SmartHome-Skill verwenden möchte, kann dieser Eintrag leer bleiben.<br />
#:* Ansonsten ist er mit der SkillID des Alexa Custom Skills zu belegen, siehe Abschnitt [[#Skill_Id_bestimmen | Skill Id bestimmen]]<br />
# ''oauthClientID'' -> ''Client ID'' dem Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
# ''server'' -> IP-Adresse des eigenen FHEM-Servers<br />
# ''port'' -> Portnummer des eigenen FHEM-Servers<br />
Beispiel:<br />
{<br />
"alexa": {<br />
"name": "Alexa TEST",<br />
"keyFile": "./key.pem",<br />
"certFile": "./cert.pem",<br />
"applicationId": "amzn1.ask.skill.xxxxxxxxxxxxxxxxxxxxxxxxxxxx",<br />
"oauthClientID": "amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"<br />
},<br />
"connections": [<br />
{<br />
"name": "FHEM",<br />
"server": "192.168.0.xxx.xxx",<br />
"port": "8083",<br />
"filter": "room=AlexaRoom"<br />
}<br />
]<br />
}<br />
<br />
Mehrere Custom Skills lassen sich mit der folgenden Syntax eintragen<br />
"applicationId": [ "amzn1.ask.skill.1" , "amzn1.ask.skill.2" ],<br />
"oauthClientID": [ "amzn1.application-oa2-client.1" , "amzn1.application-oa2-client.1" ]<br />
<br />
Danach durch Aufruf von <syntaxhighlight lang="bash" style="width:50%;">./bin/alexa</syntaxhighlight> den Dienst starten (kein sudo!)<br />
<br />
<br />
Unter Windows startet man Alexa-Dienst durch <syntaxhighlight lang="bash" style="width:50%;">node alexa</syntaxhighlight> aus der <code>alex-fhem/bin</code> (also erst z.B. durch <code>cd "<FHEM-Hauptverzeichis>\alexa-fhem\bin"</code> ins richtige Verzeichnis kommen)<br />
<br />
Der Start des Alexa-Dienstes auf der Console ist immer dann zu empfehlen, wenn man auf die Ausgaben des Dienstes angewiesen ist und beispielsweise sehen möchte, welche Devices durch den Dienst bereitgestellt werden oder ob Fehler auftreten. Beendet man die Console-Session wird auch der Dienst wieder beendet. Insofern ist die vorgenannte Vorgehensweise nur für ein Debugging zu empfehlen und nicht im Regelbetrieb. Nachfolgend ist beschrieben, wie man den Alexa-Dienst aus FHEM heraus starten / stoppen und neu starten kann.<br />
<br />
==== Alexa-Fhem aus FHEM heraus starten ====<br />
Zunächst das Start-up-Skript aus diesem Post herunterladen {{Link2Forum|Topic=60244|Message=517271|LinkText=https://forum.fhem.de/index.php/topic,60244.msg517271.html#msg517271}} und unter /etc/init.d/alexa speichern.<br />
<br />
Das Script geht davon aus, das der alexa-fhem script unter /opt/fhem/alexa-fhem liegt, und die logfiles später unter /opt/fhem/log. Sollte das nicht der Fall sein, muss das Skript angepasst werden.<br />
<br />
Nun folgende Kommandos ausführen:<br />
<syntaxhighlight lang="bash" style="width:50%;">sudo chmod 755 /etc/init.d/alexa<br />
sudo update-rc.d alexa defaults</syntaxhighlight><br />
<br />
In der Datei <code>/etc/sudoers</code> den User fhem für die Nutzung von sudo zulassen (<code>sudo nano /etc/sudoers</code>), z.B. durch Anfügen der nachfolgenden Zeile:<br />
<code>fhem ALL=(ALL) NOPASSWD: ALL</code><br />
<br />
Nun folgende Devices anlegen (ggf. einem Raum zuordnen, z.B. AlexaControl):<br />
<syntaxhighlight lang="bash" style="width:75%;">define FHEM.Alexa.Status dummy<br />
<br />
define FHEM.Alexa dummy<br />
attr FHEM.Alexa event-on-change-reading state<br />
attr FHEM.Alexa webCmd status:start:stop:restart<br />
<br />
define FHEM.Alexa.DOIF DOIF ([FHEM.Alexa] eq "start") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa start > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "stop")<br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa stop > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "restart") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa restart > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "status") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa status > /dev/null 2>&1 &")})</syntaxhighlight><br />
<br />
==== Alexa-Fhem als Service (systemd) installieren ====<br />
Auf neueren Installationen (z.B. RPi Jessie) wird init.d durch systemd ersetzt. Folgend die Anleitung um alexa-fhem als Service zu installieren auf einem Raspberry Pi mit Jessie.<br />
<br />
Zunächst einen neuen Benutzer anlegen unter dem alexa-fhem laufen soll, falls man nicht möchtet dass alexa-fhem z.B. mit dem fhem User ausgeführt wird:<br />
<br />
<code lang="bash" style="width:75%;"><br />
sudo useradd -M --system alexa<br />
</code><br />
<br />
Eigentlich braucht der Benutzer keine Gruppen, aber man kann den Benutzer auch der Gruppe <code>dialout</code> hinzufügen (<code>sudo usermod -a -G dialout alexa</code>)<br />
<br />
Datei "alexa.service" unter <code>/etc/systemd/system</code> anlegen:<br />
<br />
[Unit]<br />
Description=Node.js Alexa Server <br />
After=syslog.target network-online.target<br />
<br />
[Service]<br />
Type=simple<br />
User=alexa <br />
WorkingDirectory=/opt/alexa/alexa-fhem<br />
ExecStart=/opt/fhem/alexa-fhem/bin/alexa -U /home/alexa/.alexa<br />
Restart=on-failure<br />
RestartSec=10<br />
KillMode=process<br />
<br />
[Install]<br />
WantedBy=multi-user.target <br />
<br />
Den Pfad <code>/home/alexa/.alexa</code> an die Systemgegebenheiten anpassen. Letztendlich kann die config.json irgendwo liegen, hauptsache alexa-fhem weiß wo. <code><Homeverzeichnis des "User=">/.alexa</code> empfholen. <br />
<br />
Im WorkingDirectory wird der alexa Dienst die Zertifikate suchen.<br />
<br />
Achtung: Natürlich muss der Benutzer auch Zugriff auf das Verzeichnis mit der config als auch das alexa-fhem Verzeichnis und das WorkingDirectory haben.<br />
<br />
Um den Service zu aktiveren und zu starten helfen folgende Befehle:<br />
sudo systemctl daemon-reload<br />
sudo systemctl enable alexa<br />
sudo systemctl start alexa<br />
<br />
Status abfragen mit<br />
sudo systemctl status alexa<br />
<br />
Log einsehen?<br />
sudo journalctl -u alexa<br />
<br />
(mit <code>-f</code> kann man den follow Modus aktivieren, wie <code>tail -f</code>).<br />
Bei einen reboot startet alexa-fhem jetzt automatisch.<br />
<br />
==== Alexa-Fhem testen ====<br />
Node.Js stellt einen Web-Server am Port 3000 bereit, das oben erzeugte Zertifikat sichert diesen Zugang per SSL ab. Durch Aufruf der Adresse<br />
<code>https://<IP-Adresse des Servers>:3000</code> kann man testen, ob der Alexa-Fhem Service läuft - der Seitenaufruf liefert eine Zeile JSON-Code, beginnend mit<br />
<code>{"header":{"name":"UnsupportedOperationError"...</code><br />
<br />
=== Alexa Device anlegen ===<br />
<br />
Das Modul 39_alexa.pm stellt innerhalb von FHEM verschiedene Attribute z.B. alexaName oder alexaRoom zur Verfügung. Manche dieser Attribute (wie z.b. alexaName) werden in beiden Skills verwendet, andere werden ausschließlich bei einer Nutzung des Alexa Custom Skill verwendet.<br />
<br />
Die Einrichtung des Alexa Device geschieht durch die nachfolgende Definition:<br />
<syntaxhighlight lang="bash" style="width:70%;">define MyAlexa alexa</syntaxhighlight><br />
<br />
<hr><br />
<br />
=== Alexa Skills ===<br />
Für folgende Schritte muss man unter der Adresse http://developer.amazon.com angemeldet sein<br />
# Anmeldung auswählen<br />[[Datei:Developer.amazon.com-01-login2.png|200px]]<br />
# Anmeldedaten eingeben<br />[[Datei:Developer.amazon.com-02-userpass2.png|200px]]<br />
<br />
==== Security Profile anlegen ====<br />
Die Erzeugung eines Sicherheitsprofils muss nur einmal erfolgen, es wird dann für alle weiteren Skills verwendet.<br />
# Nach der Anmeldung Auswahl von ''APPS & SERVICES''<br />[[Datei:Developer.amazon.com-03-apps_and_services.png|200px]]<br />
# Anschließend auswählen ''Security Profiles''<br />[[Datei:Developer.amazon.com-05-apps_and_services_-_security_profiles.png|200px]]<br />
# Auswählen ''Create a New Security Profile'' aus<br />[[Datei:Developer.amazon.com-06-apps_and_services_-_create_a_new_security_profile.png|200px]]<br />
# Dann einen Namen und eine Beschreibung für das Profil eingeben und mit ''Save'' bestätigen<br />[[Datei:Developer.amazon.com-07-apps_and_services_-_security_profile_management.png|200px]]<br />
<br />
===== Login with Amazon =====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Hier wird beschrieben, wo ''Client Id'' und ''Client Secret'' zu finden sind}}<br />
# Oben rechts auf ''Login with Amazon'' klicken.<br/>[[Datei:Developer.amazon.com-08-login_with_amazon.png|200px]]<br />
# Auf der neu geladenen Seite auswählen ''Sign up''<br/>[[Datei:Developer.amazon.com-09-login_with_amazon_-_sign_up.png|200px]]<br />
# Anschließend im Dropdown Menü das vorher angelegte Profil auswählen und mit ''Confirm'' bestätigen<br/>[[Datei:Developer.amazon.com-10-login_with_amazon_-_create_new_profile.png|200px]] [[Datei:Developer.amazon.com-11-login_with_amazon_-_create_new_profile2.png|200px]]<br />
# Im folgenden Fenster die Adresse [https://www.amazon.com/gp/help/customer/display.html?nodeId=468496 https://www.amazon.com/gp/help/customer/display.html?nodeId=468496] eingeben und mit ''Save'' bestätigen. '''Todo Erklärungsbedarf: WARUM diese Adresse'''<br/>[[Datei:Developer.amazon.com-12-login_with_amazon_-_enter_consent_screen_information.png|200px]]<br />
# Anschließend bei dem neu angelegten Eintrag auf der rechten Seite auf das Zahnrad klicken und ''Web Settings'' auswählen<br/>[[Datei:Developer.amazon.com-13-login_with_amazon_-_web_settings.png|200px]]<br />
# Im neu geladenen Fenster anklicken von ''Edit''<br/>[[Datei:Developer.amazon.com-14-login_with_amazon_-_edit.png|200px]]<br />
# Anschließend bei ''Allowed Return URLs'' die folgenden drei Adressen eingeben. ''xxx'' muss hierbei durch den Wert ersetzt werden, der in den beiden Abschnitten [[#SmartHome_Skill_anlegen | SmartHome Skill anlegen]] bzw. [[#Custom_Skill_anlegen | Custom Skill anlegen]] jeweils unter Punkt 4 (Seite ''Configuration'') bei ''Redirect Urls'' am Ende der URLs angezeigt wird<br />
## [https://layla.amazon.co.uk/api/skill/link/xxx https://layla.amazon.co.uk/api/skill/link/xxx]<br />
## [https://pitangui.amazon.com/api/skill/link/xxx https://pitangui.amazon.com/api/skill/link/xxx]<br />
## [https://layla.amazon.com/api/skill/link/xxx https://layla.amazon.com/api/skill/link/xxx]<br />
.<br/>[[Datei:Developer.amazon.com-15-login_with_amazon_-_allowed_return_urls.png|200px]]<br />
<br />
==== Skills bearbeiten ====<br />
# Im Menü den Punkt ''ALEXA'' auswählen<br />[[Datei:Developer.amazon.com-03-apps_and_services.png|200px]]<br />
# Anschließend im Feld ''Alexa Skills Kit'' auf ''Get started'' klicken<br />[[Datei:Developer.amazon.com-17-alexa_-_alex_skills_kit_-_get_started.png|200px]]<br />
<br />
===== SmartHome Skill anlegen =====<br />
# Oben rechts ''Add a New Skill'' auswählen<br />[[Datei:Developer.amazon.com-18-alexa_-_alex_skills_kit_-_add_a_new_skill.png|200px]]<br />
# Auf der folgenden Seite eingeben und dann mit ''Next'' bestätigen:<br />
#:* ''Skill Type'' -> ''SmartHome Skill API'' <br />
#:* ''Language'' -> ''German''<br />
#:* ''Name'' -> beliebiger Name, z.B. "MySmartHome Basic")<br />
#:* ''Payload Version'' -> ''v2 (other devices)'' <br/>[[Datei:Developer.amazon.com-19-alexa_-_alex_skills_kit_-_skill_information.png|200px]]<br />
# Die folgende Seite einfach mit ''Next'' überspringen<br />[[Datei:Developer.amazon.com-20-alexa_-_alex_skills_kit_-_interaction_model.png|200px]]<br />
# Auf der Seite ''Configuration'' Folgendes eingeben:<br />
#:* ''Service Endpoint Type'' -> ''AWS Lambda'' ist vorausgewählt und kann nicht geändert werden.<br />
#:* ''Geographical Region'' -> ''Europe'' auswählen und im Textfeld die ARN aus Abschnitt [[#ARN_der_AWS_Lambda_Funktion_bestimmen | AWS Lambda Funktion]] eintragen. <br />
#:* ''Authorization URL'' -> <code>https://www.amazon.com/ap/oa</code><br />
#:* ''Client ID'' -> ''Client ID'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
#:* ''Scope'' -> <code>profile:user_id</code> (wörtlich 1:1 eintragen)<br />
#:* ''Redirect URLs'' - sollten vorbelegt sein<br />
#:* ''Authorization Grant Type'' -> ''Auth Code Grant'' auswählen<br />
#:* ''Access Token URI'' -> <code>https://api.amazon.com/auth/o2/token</code><br />
#:* ''Client Secret'' -> ''Client Secret'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
#:* ''Client Authentication Scheme'' -> ''HTTP Basic''<br />
#:* ''Privacy Policy URL'' -> <code>https://www.amazon.com/gp/help/customer/display.html?nodeId=468496</code><br /><br /><br />
<br />[[Datei:Developer.amazon.com-21-alexa_-_alex_skills_kit_-_configuration.png|200px]] [[Datei:Developer.amazon.com-22-alexa_-_alex_skills_kit_-_test.png|200px]]<br />
<br />
===== Custom Skill anlegen =====<br />
<ol><br />
<li> Oben rechts ''Add a New Skill'' auswählen<br />[[Datei:Developer.amazon.com-18-alexa_-_alex_skills_kit_-_add_a_new_skill.png|200px]]</li><br />
<li> Auf der folgenden Seite (''Skill Information'') die nachstehenden Daten eingeben und dann mit ''Next'' bestätigen:<br />
<ul><br />
<li> ''Skill Type'' -> ''Custom Interaction Model'' </li><br />
<li> ''Language'' -> ''German''</li><br />
<li> ''Name'' -> beliebiger Name, z.B. "MySmartHome Advanced". Dieser wird in der Alexa App unter "Meine Skills" angezeigt.</li><br />
<li> ''Invocation Name'' -> Aufruf des Skills, unter dem dieser später gestartet wird. Z.B. "Alexa, starte James"<br />[[Datei:CustomSkill_2.PNG|400px]]</li><br />
</ul></li><br />
<li>Auf der Seite ''Interaction Model'' folgende Eingaben tätigen und mit ''Next'' abschließen<br />
<ul><br />
<li>In einem separaten Browserfenster FHEM aufrufen, und für das bereits definierte Alexa-Gerät das Kommando <code>get MyAlexa interactionModel</code> aufrufen. Es erscheint ein Popup-Fenster mit ziemlich vielen Zeilen.<br />
<li>In die Box ''Intent Schema'' kopiert man den ersten Teil dieser FHEM-Ausgabe hinein, also:<br/><blockquote><br />
{ <br />
"intents" : [ <br />
<hier ziemlich viele Zeilen> <br />
]<br />
}<br />
</blockquote></li><br />
<li>Nun die ''Custom Slot Types'' einrichten. Dazu muss aus dem zweiten Teil der FHEM-Ausgabe jeweils der Slot-Type (z.B. <code>FHEM_article</code>) in das Feld ''TYPE'' eingetragen werden, das nach dem Anklicken von ''Add Slot Type'' erscheint. In das darunter liegende größere Textfeld kommen die möglichen Werte für diesen Slot, so wie sie aus der FHEM-Ausgabe abzulesen sind. Dann mit ''Save'' sichern. Als Custom Slot Type erscheint dann für diesen Beispiel-Slot<br />
FHEM_article der | die | das | den<br />
d.h., die Zeilenumbrüche bei den möglichen Werten werden als "|" dargestellt.</li><br />
<li>Hier muss nun ein Bruch im Arbeitsfluss durchgeführt werden, denn bei der Erstellung des Custom Skills kommt es auf die Reihenfolge der Einträge an. Deshalb zunächst diese FHEM-Ausgabe schließen, und für dasselbe FHEM-Device <code>get MyAlexa customSlotTypes</code> ausführen. Auch diese Ausgabe wird, wie oben beschriebeen, in Custom Slot Types eingetragen (erst der TYPE, dann die möglichen Werte)<br />
<li>Anschließend erneut die FHEM-Ausgabe schließen und erneut für das bereits definierte Alexa-Gerät das Kommando <code>get MyAlexa interactionModel</code> aufrufen.<br />
<li>Unter ''Sample Utterances'' nun den Text aus dem dritten Teil dieser FHEM-Ausgabe hineinkopieren<br />[[Datei:CustomSkill_5.PNG|400px]]</li><br />
</ul></li><br />
<li>Auf der Seite ''Configuration'' Folgendes eingeben und mit ''Next'' bestätigen:<br />
<ul><br />
<li>''Service Endpoint Type'' -> ''AWS Lambda'' auswählen</li><br />
<li>''Geographical Region'' -> ''Europe'' auswählen und im Textfeld den Wert aus Abschnitt [[#AWS_Lambda_Funktion_anlegen | AWS Lambda Funktion anlegen]] (Punkt 12) eintragen. </li><br />
<li>''Do you allow users to create an account or link to an existing account with you?'' -> ''Yes''</li><br />
<li>''Authorization URL'' -> <code>https://www.amazon.com/ap/oa</code></li><br />
<li>''Client ID'' -> ''Client ID'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1</li><br />
<li>''Scope'' -> <code>profile:user_id</code> (wörtlich 1:1 eintragen)</li><br />
<li>''Redirect URLs'' - sollten vorbelegt sein</li><br />
<li>''Authorization Grant Type'' -> ''Auth Code Grant'' auswählen</li><br />
<li>''Access Token URI'' -> <code>https://api.amazon.com/auth/o2/token</code></li><br />
<li>''Client Secret'' -> ''Client Secret'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1</li><br />
<li>''Client Authentication Scheme'' -> ''HTTP Basic''</li><br />
<li>''Privacy Policy URL'' -> <code>https://www.amazon.com/gp/help/customer/display.html?nodeId=468496</code></li><br />
</ul><br />
Beim Sichern dieser Seite mit ''Next'' kann es zu einer Fehlermeldung kommen, wenn man seine Skill-Definitionen mit dem einfachen SmartHome-Skill begonnen hat. Deshalb muss noch der entsprechende Trigger für die [[#AWS_Lambda-Funktion | AWS Lambda Funktion]] nachgetragen werden, dies wird in Abschnitt [[#Trigger_f.C3.BCr_Custom_Skill_hinzuf.C3.BCgen | Trigger für Custom Skill hinzufügen]] beschrieben.<br />
<br />[[Datei:CustomSkill_6.PNG|400px]] [[Datei:CustomSkill_7.PNG|400px]]</li><br />
<br />
==== Testen ====<br />
Hat man den Custom Skill angelegt, bietet dieser auch eine komfortable Testmöglichkeit. Dazu wählt man in der Übersichtsseite ''All Skills'' den Button ''Edit'' des Alexa Custom Skill aus. Auf der nachfolgenden Seite dann links ''Test''. <br />
Die Testseite enthält <br />
* ein Feld ''Voice Simulator'', mit dem man die Sprachsausgabe testen kann, <br />
* ein Feld ''Service Simulator'', mit dem die Verarbeitung von Alexa-Kommandois getestet werden kann. Hier kann man z.B. eintragen<br />
"Alexa, sage <Custom Skill Invocation Name>: Stelle Weckzeit auf Neunzehn Siebenundzwanzig Uhr"<br />
"Alexa, frage <Custom Skill Invocation Name> nach dem Status von Weckzeit"<br />
Dabei ist natürlich der ''Custom Skill Invocation Name'' durch den Wert zu ersetzen, den man im Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]] unter Punkt 2 eingetragen hat.<br />
<br />
==== Skill Id bestimmen ====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Hier wird beschrieben, wo die ''Alexa Skill Id'' zu finden ist}}<br />
Für das [[#AWS_Lamba_Funktion_anlegen | Anlegen einer ''AWS Lambda Funktion'']] bzw für die [[#Alexa-Fhem_konfigurieren | Konfiguration von Alexa-Fhem]] wird die ''Alexa Skill Id'' benötigt. An diese kommt man wie folgt:<br />
# Anmelden wie unter [[#Alexa_Skills | Alexa Skills]] beschrieben.<br />
# Menüpunkt ''ALEXA'' auswählen, wie [[#Skills_bearbeiten | Skills bearbeiten]] erklärt.<br />
# Beim gewünschten Eintrag auf ''Edit'' klicken<br />[[Datei:Developer.amazon.com-23-alexa_-_alex_skills_kit_-_overview.png|200px]]<br />
# Die Id, die nun oben angezeigt wird, ist die gesuchte. Sie hat typischerweise das Format <code>amzn1.ask.skill.[Zahlen und Bindestriche]</code><br />[[Datei:Aws.amazon.com-06-configure_triggers2.png|200px]]<br />
<br />
<hr><br />
<br />
=== AWS Lambda Funktion ===<br />
Für folgende Schritte muss man unter der Adresse http://aws.amazon.com angemeldet sein<br />
# Anmeldung auswählen<br />[[Datei:Aws.amazon.com-01-site.png|200px]]<br />
# Anmeldedaten eingeben<br />[[Datei:Aws.amazon.com-02-login.png|200px]]<br />
# Den Punkt ''Lambda'' links auf der Startseite auswählen, bzw. im Menü ''Services'' unter ''Compute'' den Menüpunkt ''Lambda'' auswählen<br />[[Datei:Aws.amazon.com-03-lambda.png|200px]]<br />
==== AWS Lambda Funktion anlegen ====<br />
# Für eine erste Lambda-Funktion den Punkt ''Get Started Now'' auswählen<br />[[Datei:Aws.amazon.com-04-get_started_now.png|200px]]<br />
# Den Blueprint ''Blank function'' auswählen<br />[[Datei:Aws.amazon.com-05-select_blueprint.png|200px]]<br />
# Im neuen Fenster dann auf den gestrichelten Kasten klicken und ''Alexa Smart Home'' auswählen und mit ''Next'' bestätigen<br />[[Datei:Aws.amazon.com-06-configure_triggers1.png|200px]]<br />
## Achtung, es ist möglich, dass dabei ''Alexa Smart Home'' überhaupt nicht angeboten wird. Dann bitte ganz rechts oben in der Ecke nachsehen, welche Region bzw. welches Land ausgewählt ist. Empfohlen wird, ''Ireland'' auszuwählen. Dann erscheint bei den Funktionen auch ''Alexa Smart Home''.<br />
# Bei ''Application Id'' den Wert eintragen, dessen Ermittlung im Abschnitt [[#Skill_Id_bestimmen | Skill Id bestimmen]] beschrieben wird, den Haken bei ''Enable trigger'' setzen und mit ''Next'' bestätigen <br />[[Datei:Aws.amazon.com-06-configure_triggers3.png|200px]]<br />
# Auf der Konfigurationsseite eingeben:<br />
## ''Name'' -> ''FHEM''<br />
## ''Runtime'' -> Node.js 4.3. <br />
## ''Role'' -> ''Choose an existing role'' <br />
### Achtung: wenn es noch keine existing role gibt, zuerst ''Create a custom role'' -> in dem Popup dann ''lambda_basic_execution'' auswählen und auf ''Allow'' klicken sowie bei ''Existing role'' dann ''x'' wählen.<br />
# Auf der Code-Seite wird bzw. im großen Textfeld ist dann der Code aus der Datei ''lambda.js'' im Paket [[#Alexa-Fhem_installieren | Alexa-Fhem]] vollständig einzufügen. Dabei muss noch der Hostname im Quellcode an den eigenen Hostnamen angepasst werden. <br />
# Anschließend alles mit ''Next'' bestätigen.<br />[[Datei:Aws.amazon.com-07-configure_function.png|200px]]<br />
# Auf der Übersichtsseite dann ''Create function'' anklicken<br />[[Datei:Aws.amazon.com-08-review.png|200px]]<br />
<br />
==== Trigger für Custom Skill hinzufügen ====<br />
Editiert man eine Lambda-Funktion, werden auf der Seite ''Triggers'' diejenigen Dienste angezeigt, die diese Funktion aufrufen.<br />
* Hier taucht der Trigger ''Alexa Smart Home'' zusammen mit der ''Application Id'' auf, der bei der Einrichtung des SmartHome-Skills eingetragen wurde.<br />
* Zur Verbindung mit dem Custom Skill ist es nötig, einen zweiten Trigger hinzuzufügen. Durch Anklicken von ''Add Trigger'' wird eine Auswahlseite eingeblendet. Im neuen Fenster dann auf den gestrichelten Kasten klicken und ''Alexa Skills Kit' auswählen und mit ''Next'' bestätigen<br />
<br />
==== ARN der AWS Lambda Funktion bestimmen ====<br />
# Auf der Übersichtsseite oben links den Menüpunkt ''Functions'' aúswählen<br />[[Datei:Aws.amazon.com-09-go_overview.png|200px]]<br />
# Anschließend den Radiobutton der angelegten Funktion ''FHEM'' markieren und im Menü ''Action'' den Punkt ''Show ARN'' auswählen<br />[[Datei:Aws.amazon.com-10-1-show_arn.png|200px]]<br />
# Es wird nun eine ARN Adresse angezeigt, die für den Abschnitt [[#SmartHome_Skill_anlegen| SmartHome Skill anlegen]] benötigt wird<br />[[Datei:Aws.amazon.com-10-2-arn.png|200px]]<br />
<br />
=== Absichern des Zugriffs ===<br />
Natürlich muss der Zugriff auf den von Alexa-Fhem verwendeten Port (default: 3000, Bestandteil des Codes in der AWS Lambda-Funktion) durch die Firewall freigeschaltet werden (auf einer FritzBox unter "Portfreigaben").<br />
<br />
==== Absicherung direkt in Alexa-FHEM ====<br />
Die Kommunikation zwischen Amazon AWS und Alexa-FHEM ist auf die folgenden Arten gesichert:<br />
* Die Verbindung erfolgt per HTTPS<br />
* Es werden nur Verbindung angenommen auf denen ein gültiges Alexa-Event gesendet wird. <br />
* Es werden nur Verbindungen angenommen die ein gültiges und noch nicht abgelaufenes OAuth-Token enthalten. Jedes neue Token wird live bei Amazon auf Gültigkeit geprüft. <br />
* Es werden nur Verbindungen mit lokal konfigurierter Skill-ID angenommen.<br />
* Es ist nicht möglich von außen beliebige FHEM Kommandos zu senden. Die FHEM Kommandos werden nur lokal erzeugt.<br />
<br />
Wer möchte kann Alexa-FHEM natürlich noch weiter absichern. Es gilt aber, dass nicht jedes zusätzliche Glied in der Kette die Sicherheit sondern unter Umständen nur die Angriffsfläche erhöht. Ein falsch konfigurierter und nach aussen offener Apache (oder anderer ReverseProxy) ist unter Umständen ein größeres Risiko als Alexa-FHEM alleine.<br />
<br />
==== Absicherung per ReverseProxy ====<br />
<s>Die Kommunikation zwischen Amazon und FHEM ist wegen der Verwendung von SSL schon verschlüsselt - prinzipiell kann aber jeder von außen mit Alexa-Fhem kommunizieren. Man sollte sich deshalb im Klaren darüber sein, dass dies eine Sicherheitslücke darstellt:</s> Jeder offene Port verleitet zu Angriffen, und mit zunehmender Verbreitung von Alexa steigt auch das Risiko. Es wird deshalb empfohlen, vor den eigentlichen Alexa-Server zur Absicherung einen Apache-Webserver als ReverseProxy zu setzen. Nicht nur ist der Apache eine hervorragend stabile und seit Jahrzehnten getestete Software, sondern die Konfiguration als ReverseProxy erlaubt auch, den Zugriff auf den Alexa-Fhem-Rechner auf die Amazon-Maschinen zu beschränken.<br />
<br />
'''Achtung: Dies ist keine allgemeine Anleitung in Sachen Computersicherheit.''' Im Folgenden gehen wir davon aus, dass <br />
* Grundbegriffe wie Firewall, IP-Ports, SSL und Dynamic DNS vertraut sind<br />
* Ein Apache Webserver (idealerweise auf einer zweiten Maschine) bereits installiert ist und die Konfiguration verstanden wurde (wenn nicht: Es gibt im Netz ''tausende'' von Anleitungen dafür...)<br />
* Ein Servername von einem DynDNS-Anbieter - sagen wir ''myhome.is-my-castle.com'' - bereits von ''außen'' auf unser SmartHome zeigt.<br />
* Alexa-Fhem in einer der oben beschriebenen Basiskonfigurationen läuft, d.h. der Zugriff auf <code>https://myhome.is-my-castle.com:3000</code> ergibt, wie im Punkt [[#Alexa-Fhem_testen|Alexa-Fhem testen]] beschrieben, eine Antwort des Node.js Servers.<br />
<br />
Als erster Schritt zur Absicherung muss das ReverseProxy Modul für den Apache installiert und mit <code>a2enmod</code> aktiviert werden, hierzu sei auf [https://www.digitalocean.com/community/tutorials/how-to-use-apache-http-server-as-reverse-proxy-using-mod_proxy-extension diese Anleitung] verwiesen. Der zweite Schritt besteht darin, den SSL-Zugriff durch ein Passwort abzusichern. Dazu wird auf dem Apache-Rechner das Programm <br />
htpasswd <passwdfile> <username><br />
ausgeführt, das Programm fragt dann nach dem gewünschten Passwort. Wir nehmen im Folgenden an, dass das Passwortfile ''/etc/apache2/htpasswd'' ist, der gesetzte Username ''alexa'' lautet und das Passwort ''my_smarthome'' ist.<br />
<br />
Im dritten Schritt wird nun in das Apache-Konfigurationsfile die Weiterleitung auf den eigentlichen Alexa-Fhem-Rechner eingetragen. Dazu wählen wir, dass von außen der Standard-SSL-Port 443 benutzt werden soll, sowie als Verzeichnisname ''/alexa''. '''Achtung:''' Dieser Code soll '''nicht''' in die Default-Konfiguration des Apache-Webservers. Sondern in eine separate Datei (Dateiname z.B. "fhem"), die ins Unterverzeichnis /etc/apache2/conf.d gestellt wird.<br />
<br />
<VirtualHost *:443><br />
ServerName myhome.is-my-castle.com<br />
SSLEngine on<br />
SSLProxyEngine on<br />
SSLProxyCheckPeerCN off<br />
SSLProxyCheckPeerName off<br />
SSLCertificateKeyFile /etc/apache2/mycert/server.key<br />
SSLCertificateFile /etc/apache2/mycert/server.crt<br />
<Location /alexa><br />
AuthType Basic<br />
AuthName "Authentication Required"<br />
AuthUserFile "/etc/apache2/htpasswd"<br />
Require valid-user<br />
ProxyPass https://<hier IP-Adresse des Alexa-Fhem-Rechners>:3000/<br />
ProxyPassReverse https://<hier IP-Adresse des Alexa-Fhem-Rechners>:3000/<br />
Order deny,allow<br />
Allow from All<br />
</Location><br />
(... Hier eventuell weitere Umleitungen)<br />
</VirtualHost><br />
Nach einem Neustart des Apache-Servers, dem Schließen des Ports 3000 in der Firewall sowie dem Öffnen des Ports 443 ist der Alexa-Fhem-Rechner von außen nur noch erreichbar durch den Aufruf von <code>https://myhome.is-my-castle.com/alexa</code> und verlangt unmittelbar die Eingabe von Username und Passwort.<br />
<br />
Der vierte Schritt ist nun, den Code der AWS Lambda-Funktion an fünf Stellen zu verändern<br />
'''const PORT=443;'''<br />
const HOST='myhome.is-my-castle.com';<br />
'''const PATH='/alexa';'''<br />
'''const AUTH='alexa:my_smarthome';'''<br />
// entry<br />
exports.handler = function(event, context, callback) {<br />
console.log(`EVENT: ${event}`);<br />
console.log(`CONTEXT: ${context}`); <br />
var post_data = JSON.stringify(event);<br />
var options = {<br />
hostname: HOST,<br />
port: PORT,<br />
//family: 6,<br />
'''path: PATH,'''<br />
method: 'POST',<br />
'''auth: AUTH,'''<br />
rejectUnauthorized: false, // accept self-signed<br />
(etc., Rest des Codes wie gehabt)<br />
Natürlich muss der Zugriff getestet werden. Bei Beachtung aller dieser Schritte werden alle un-autorisierten Zugriffe von außen abgewehrt. Eine noch weiter gehende Sicherung ist möglich, dazu kann in der Serverkonfiguration der Zugriff auf die Amazon-Domains beschränkt werden. Das ganze Alexa-System ist aber noch in konstanter Weiterentwicklung, diese Domain-Namen können sich also noch ändern.<br />
<br />
== Einrichtung in der Alexa App==<br />
Nachdem die Alexa Skills angelegt wurden, müssen diese noch in der Alexa App eingerichtet werden.<br />
Dafür jeweils per Desktop-Browser auf [http://alexa.amazon.de alexa.amazon.de] anmelden, nicht die App unter iOS oder Android verwenden. Diese hat Probleme mit der OAuth Verknüpfung.<br />
<br />
=== Alexa Skill ===<br />
# Auf ''Skills'' klicken<br />[[Datei:Alexa.amazon.de-01-startseite.png|200px]]<br />
# Oben rechts ''Meine Skills'' bzw. ''Ihre Skills'' auswählen<br />[[Datei:Alexa.amazon.de-03-meine_skills.png|200px]]<br />
# In der Liste der Skills sollte das angelegte FHEM Skill angezeigt werden. Dieses anklicken<br />[[Datei:Alexa.amazon.de-02-liste_skills.png|200px]]<br />
# Oben Rechts in den Details des Skills auf ''Skill aktivieren'' klicken<br />[[Datei:Alexa.amazon.de-04-skill_details.png|200px]]<br />
# In dem neu geöffneten Fenster die Autorisierung bestätigen<br />[[Datei:Alexa.amazon.de-05-amazon_auth.png|200px]]<br />
# Anschließend sollte die Verbindung erfolgreich aufgebaut worden sein <br />[[Datei:Alexa.amazon.de-06-success.png|200px]]<br />
<br />
=== Geräte ===<br />
# Auf http://alexa.amazon.de anmelden<br />
# Auf ''Smart Home'' klicken<br />[[Datei:Alexa.amazon.de-01-startseite.png|200px]]<br />
# Anschließend den Punkt ''Geräte suchen'' anklicken<br />[[Datei:Alexa.amazon.de-07-Gerätesuche.png|200px]]<br />
# Wurde soweit alles korrekt eingerichtet, werden nun die gefundenen Geräte angezeigt.<br />
<br />
Tip: Es macht Sinn, unter ''Meine Gruppen'' Gruppen benannt nach den Räumen einzurichten. Hierdurch kann Alexa die Geräte besser auseinander halten, vor allem wenn die den gleichen Alias (z.B. "Licht") haben.<br />
<br />
== Einrichtung unter FHEM ==<br />
Im Folgenden werden exemplarisch ein paar Geräte beschrieben, die man nutzbringend mit FHEM einsetzen kann.<br />
<br />
Bei Verwendung des Custom Skills übersetzt die Kombination der Attribute ''alexaMapping'' und ''homebridgeMapping'' Sprachbefehle ("Intents") in gerätespezifische Kommandos. <br />
* Das Attribut alexaMapping wird am Alexa-Device gesetzt und dient dazu, erkannte Sprachkommandos in abstrakte Characteristiken zu überführen. Für den einfacheren SmartHome Skill hat darum das Attribut ''alexaMapping'' keine Bedeutung, sondern nur der ''genericDeviceType'' des zu steuernden Gerätes.<br />
* Das Attribut homebridgeMapping wird für beide Skills am zu steuernden Gerät gesetzt und übersetzt diese Charakteristiken in die konkreten Befehle, die das Gerät versteht. Der inhalt des Attributs wird von links nach rechts ausgewertet und ist wie folgt aufgebaut:<br />
** Das Attribut enthält eine durch Leerzeichen getrennte Liste aus Konfigurationen für jeweils eine Characteristik<br />
** Jede einzelne der Characteristik-Konfigurationen besteht aus dem Namen der Characteristik, gefolgt von "=" und einer kommaseparierten Liste von Parametern.<br />
attr <device> homebridgeMapping <Characteristic1>=<param1.1>,<param1.2>,... <Characteristic2>=<param2.1>,<param2.2>,...<br />
** Jeder Parameter besteht entweder aus<br />
*** <code><cmd>:<device>:<reading></code>, hier können nicht verwendete Elemente von links nach rechts weg gelassen werden.<br />
*** <code><name>=<value></code>, hier kann <code><value></code> entweder ein Wert oder semikolonseparierte Liste sein.<br />
*** Oder dem schlüsselwort <code>clear</code>, welches alle vorhandenen (default) Parameter dieser Characteristik löscht. <code>clear</code> kann auch an Stelle einer ganzen Characteristik-Konfiguration stehen<br />
Weiter führende Dokumentation zum homebridgeMapping findet sich unter https://forum.fhem.de/index.php/topic,48558.0.html<br />
<br />
=== Einfacher Schalter ===<br />
* Ein einfacher Schalter, der die set-Kommandos ''on'' und ''off'' kennt, kann direkt mit Alexa-Fhem gekoppelt werden <br />
* Für kompliziertere Aktionen, etwa das Übermitteln eines spezifischen Schaltbefehls an FHEM, ist die Einrichtung eines Dummies zu empfehlen. <br />
Ob Dummy oder nicht, wichtig sind die drei fett gedruckten Zeilen<br />
define Alexa.Party dummy<br />
'''attr Alexa.Party alexaName party'''<br />
'''attr Alexa.Party alexaRoom alexaroom'''<br />
'''attr Alexa.Party genericDeviceType switch'''<br />
attr Alexa.Party group AlexaGeräte<br />
attr Alexa.Party room AlexaRoom<br />
'''attr Alexa.Party setList on off'''<br />
Selbstverständlich kann man diesen Dummy mit einem notify oder DOIF abfangen, um die gewünschte Schaltaktion auszuführen. <br />
<br />
Ein Alternative zum Dummy ist das Anlegen eines readingsProxy, dem die entsprechenden Attribute gegeben werden.<br />
<br />
Weil es sich hierbei um eines der einfachen Geräte handelt, die Alexa selbst im SmartHome Skill bearbeiten kann, ist auch der zweite Schritt bei der Einrichtung in der Alexa App sinnvoll: Der Schalter wird dann im Bereich Smart Home der Alexa App erkannt. Wer ihn auch mit dem Custon Skill bedienen möchte, muss natürlich Sorge tragen, dass der Alexa-Name ''party'' bei den FHEM_Devices auftaucht und die entsprechenden weiteren Slot Types und Example Utterances in der Konfiguration des Custom Skills vorhanden sind (siehe Abschnitt [[##Custom_Skill_anlegen | Custom Skill Anlegen]]).<br />
<br />
=== Wecker ===<br />
Dieses Gerät kann man nur mit dem Custom Skill bedienen, es wird also '''nicht''' im Bereich Smart Home der Alexa App auftauchen. Wir richten einen Dummy ein, wichtig sind wieder die fett gedruckten Zeilen:<br />
define Alexa.Weckzeit dummy<br />
'''attr Alexa.Weckzeit alexaName weckzeit'''<br />
'''attr Alexa.Weckzeit alexaRoom alexaroom'''<br />
attr Alexa.Weckzeit genericDeviceType clock<br />
attr Alexa.Weckzeit group AlexaGeräte<br />
'''attr Alexa.Weckzeit homebridgeMapping Weckzeit=state,cmd=+'''<br />
attr Alexa.Weckzeit room AlexaRoom<br />
'''attr Alexa.Weckzeit setList Weckzeit:time'''<br />
Das Attribut ''genericDeviceTye'' ist nicht wichtig, weil es ein generisches Device dieser Art gar nicht gibt. Wichtig hingegen ist das Attribut ''homebridgeMapping'' <br />
<br />
Für das Gerät ''MyAlexa'', das in Abschnitt definiert wurde, muss im Attribut ''alexaMapping'' auftauchen<br />
Weckzeit=verb=stelle,valuePrefix=für;auf,values=AMAZON.TIME,valueSuffix=uhr<br />
Darüber hinaus muss der Alexa-Name ''weckzeit'' bei den FHEM_Devices auftauchen und die entsprechenden weiteren Slot Types und Example Utterances in der Konfiguration des Custom Skills vorhanden sein (siehe Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]]).<br />
<br />
Der Aufruf dieses Gerätes mit Alexa erfolgt dann z.B. mit den Sätzen<br />
<pre style="width:50%;"><br />
"Alexa, sage <Custom Skill Invocation Name>: Stelle Weckzeit auf Neunzehn Uhr Siebenundzwanzig"<br />
"Alexa, frage <Custom Skill Invocation Name> nach dem Status von Weckzeit"<br />
</pre><br />
Dabei ist natürlich der ''Custom Skill Invocation Name'' durch den Wert zu ersetzen, den man im Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]] unter Punkt 2 eingetragen hat.<br />
<br />
Zur weiteren Bearbeitung kann man jetzt mit einem DOIF Statusänderungen des Dummies abfangen und durch eine kleine Helperfunktion ins "echte" FHEM weiterleiten.<br />
define Alexa.Weckzeit.N DOIF (["Alexa.Weckzeit:.*"])({AlexaHelper("Alexa.Weckzeit","$EVENT")}) <br />
Die Helperfunktion (z.B. in 99_myUtils.pm) stellt aus der übergebenen Zeit (immer im Format dd:mm) eine sprachkompatible Nachricht $nc und einen mit den FHEM-Zeitangaben kompatiblen String $nt zusammen und reicht beide an eine Routine ''changeWakeTime'' weiter (dokumentiert in den [https://www.dpunkt.de/buecher/12387/9783960090120-smarthome-hacks.html Smart Home Hacks]).<br />
sub AlexaHelper($$){<br />
my ($name,$event)=@_;<br />
if( $name eq "Alexa.Weckzeit" ){ <br />
my ($nc,$nt);<br />
#-- volle Stunde----------------------------------------<br />
if( $event =~ /(\d+):00/ ){<br />
$nc=sprintf("%d Uhr",$1);<br />
$nt=sprintf("%02d:00:00",$1);<br />
#-- nicht volle Stunde---------------------------------<br />
}elsif( $event =~ /(\d+):(\d+)/ ){<br />
$nc=sprintf("%d Uhr %d",$1,$2);<br />
$nt=sprintf("%02d:%02d:00",$1,$2);<br />
}<br />
changeWakeTime(\'GalaxyTab.EG\',\'$nc\',\'$nt\');<br />
}<br />
}<br />
<br />
<hr><br />
<br />
=== Lichtszene ===<br />
Eine Lichtszene wird mit dem Modul LightScene angelegt. Wir gehen davon aus, dass in der Lichtszene die beiden Szenen Alle_An und Alle_Aus, sowie mindestens eine weitere Szene (hier: Sitzgruppe) definiert wurde.<br />
* Nachfolgend wird ein Beispiel beschrieben, wie man eine Lichtszene mit dem einfachen SmartHome Skill steuern kann. Die verwendeten Kommandos sind dann<br />
<pre><br />
"Alexa, schalte (die) Beleuchtung an" -> LightScene Alle_An wird ausgewählt<br />
"Alexa, schalte (die) Beleuchtungsitzgruppe an" -> LightScene Sitzgruppe wird ausgewählt<br />
...<br />
"Alexa, schalte (die) Beleuchtung aus" -> LightScene Alle_Aus wird ausgewählt<br />
</pre><br />
* Künftig wird man LightScene mit dem Custom Skill eventuell direkt steuern können - allerdings hat das einen geringeren WAF, als die Steuerung über den SmartHome Skill: Der Einschaltsatz muss dann mindestens lauten<br />
<pre><br />
"Alexa, sage <Custom Skill Invocation Name>: schalte (die) Beleuchtung an" -> LightScene Alle_An wird ausgewählt<br />
</pre><br />
Dafür wird es aber auch möglich sein direkt die SzenenNamen im gesprochenen Kommando zu verwenden und so auf die Umwege über dummys und ähnliches zu verzichten.<br />
<br />
<br />
Im ersten Schritt wird ein Dummy für die Gesamtbeleuchtung eingerichtet:<br />
define Alexa.Beleuchtung dummy <br />
attr Beleuchtung setList on off<br />
'''attr Alexa.Beleuchtung alexaName beleuchtung'''<br />
'''attr Alexa.Beleuchtung alexaRoom alexaroom'''<br />
'''attr Alexa.Beleuchtung genericDeviceType switch'''<br />
Anschließend wird für jede vorhandene Lichtszene (außer Alle_An und Alle_Aus) ein weiterer Dummy angelegt:<br />
define Alexa.Beleuchtung.Sitzgruppe dummy <br />
attr Beleuchtung setList on off<br />
'''attr Alexa.Beleuchtung.Sitzgruppe alexaName beleuchtungsitzgruppe'''<br />
'''attr Alexa.Beleuchtung.Sitzgruppe alexaRoom alexaroom'''<br />
'''attr Alexa.Beleuchtung.Sitzgruppe genericDeviceType switch''' <br />
Die eigentliche Steuerung übernimmt dann ein DOIF<br />
define Alexa.Beleuchtung.N DOIF<br />
(["Alexa.Beleuchtung.Sitzgruppe:on"])<br />
(set <devicename der Lichtszene> scene Sitzgruppe,<br />
set Alexa.Beleuchtung off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
DOELSIF<br />
... <weitere on-Events der anderen Szenen werden abgefangen><br />
DOELSEIF<br />
(["Alexa.Beleuchtung:on"])<br />
(set <devicename der Lichtszene> scene Alle_An,<br />
set Alexa.Beleuchtung.Sitzgruppe off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
DOELSEIF<br />
(["Alexa.Beleuchtung:off"])<br />
(set <devicename der Lichtszene> scene Alle_Aus,<br />
set Alexa.Beleuchtung.Sitzgruppe off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
Mit diesem DOIF wird ein Radiobutton simuliert, d.h. wie bei den Stationstasten vor Uralt-Radios sorgt die Auswahl einer Szene immer dafür, dass alle anderen Dummies ausgeschaltet werden.<br />
Natürlich kann man das auch mit einem kleinen Perl-Programm erreichen.<br />
<br />
<br />
Zwei andere Ansätze Lichtszenen zu schalten die ohne DOIF auskommen sind im Folgenden beschrieben:<br />
<br />
* Wenn es von Interesse ist die Steuerung mit einer Darstellung in FTUI zu verbinden: Statt der oben beschriebenen dummy Devices kann man readingsProxy Devices mit passenden setFn und valueFn analog zum [[Harmony#Button_f.C3.BCr_eine_bestimmte_Activity_im_Frontend_und_Homekit_.C3.BCber_readingsProxy|diesem Beispiel für harmony aktivitäten]] verwenden.<br />
<br />
* Für jede zu schaltende Szene wird ein dummy angelegt dessen homebridgeMapping direkt auf das LightScene Device zeigt:<br />
<br />
define <dummy> dummy<br />
attr <dummy> setList on off<br />
attr <dummy> genericDeviceType switch<br />
attr <dummy> homebridgeMapping On=<light scene>::state,valueOn=<szene>,cmdOn=scene+<szene>,cmdOff=scene+<szene aus><br />
<br />
Bei der zweiten Variante wird davon ausgegangen das der aktuelle status nicht abgefragt oder angezeigt werden soll. Deshalb gibt es keine direkte RadioButton Funktionalität.<br />
<br />
== Nutzung ==<br />
Um den Namen zu bestimmen, unter dem ein Gerät mit Alexa angesprochen wird, verwendet Alexa-Fhem mit absteigender Priorität:<br />
* das alexaName Attribut<br />
* das alias Attribut<br />
* das NAME Internal<br />
Damit Alexa ein Gerät eindeutig identifizieren kann, sollten eindeutige Gerätenamen verwendet werden, bestehed möglichst aus einem Wort und ohne Ziffern. Wenn Alexa einen Namen nicht versteht, kann man unter [http://alexa.amazon.de/spa/index.html] nachsehen was tatsächlich verstanden wurde und den Gerätenamen ggf. anpassen.<br />
<br />
=== SmartHome Skill ===<br />
Gruppen (Räume) müssen in der Alexa App konfiguriert werden. Über das API lassen sich nur der Name und die Schalteigenschaften übergeben.<br />
<br />
Nach erfolgreicher Einrichtung des SmartHome Skills sollte Alexa mit den folgenden Befehlen nutzbar sein:<br />
<pre style="width:50%;"><br />
“alexa, schalte <gerät/gruppe> ein”<br />
“alexa, schalte <gerät/gruppe> aus”<br />
“alexa, stelle <gerät/gruppe> auf <wert> prozent”<br />
“alexa, stelle <gerät/gruppe> auf <anzahl> grad”<br />
“alexa, erhöhe <gerät/gruppe> um <anzahl> prozent”<br />
“alexa, reduziere <gerät/gruppe> um <anzahl> prozent”<br />
“alexa, erhöhe <gerät/gruppe> um <anzahl> grad”<br />
“alexa, reduziere <gerät/gruppe> um <anzahl> grad”<br />
</pre><br />
<br />
=== Custom Skill ===<br />
Der Custom Skill erlaubt im Gegensatz zum SmartHome Skill eine weitreichende Konfiguration der möglichen Kommandos.<br />
<br />
Das Prinzip der Kommandokonfiguration ist {{Link2Forum|Topic=60244|Message=532513|LinkText=im Forum}} beschrieben.<br />
<br />
TODO: Abfragen, Attribute (alexaMapping, alexaTypes, fhemIntents, articles, prepositions)<br />
<br />
== Troubleshooting ==<br />
<br />
====Allgemeiner Hinweis====<br />
Besonders wichtig ist, dass man sich sehr genau an diese Anleitung hält. Ein häufiger Fehler ist, dass die einfachen Anführungszeichen in der Anleitung unter '''AWS Lambda Funktion anlegen''' Punkt 8 einfach weggelassen werden. Diese sind zwingend notwendig. Es darf auch nur der reine Hostname eingetragen werden. Also kein ''http://'' davor. Entweder eine feste IP Adresse oder den Hostnamen, um den Rechner zu erreichen, den ihr über den Port 3000 freigegeben habt. Das sollte dann so aussehen:<br />
<pre style="width:50%;"><br />
const PORT=3000;<br />
const HOST='mein.host.name';<br />
</pre><br />
<br />
====Freigabe von Port 3000====<br />
{{Randnotiz|RNTyp=Fehl|RNText=Derzeit müsst ihr über einen echten IPv4 Anschluss verfügen, damit der Amazon Lambda-Server euch erreichen kann. DS-Lite Anschlüsse wie die von <b>UnityMedia</b> z.B. funktionieren derzeit leider nicht. Eine möglicher "Workaround" wird hier beschrieben: https://forum.fhem.de/index.php/topic,60244.msg518276.html#msg518276}}<br />
<br />
Auf dem Router muss der Port 3000 Protokoll TCP freigegeben werden. D.h. von außen muss man wenn man den Port 3000 aufruft, auf dem intern laufenden node.js Alexa-Dienst zugreifen können.<br />
Je nach Router gestaltet sich das Portforwarding bzw. die Portumleitung etwas schwieriger.<br />
<br />
Bei einem Speedport Router der Telekom beispielsweise, muss der Router komplett neu gestartet werden, wenn die Portfreigabe eingerichtet wurde. <br />
<br />
Bei der Fritz!Box ist das nicht nötig, bei dieser finden die Freigabe unter ''Internet -> Freigaben -> Portfreigaben'' statt. Dort wählt man dann den Rechner aus und richtet eine neue Freigabe ein. Wichtig hierbei ist, dass man Portfreigabe auswählt und nicht MyFRITZ!-Freigabe. Bei Port von bis trägt man 3000 ein, bei Port extern ebenfalls.<br />
<br />
Um die Portweiterleitung zu testen, solltet ihr euch auch nicht im gleichen Netz befinden. Viele Router blockieren den Netzaufruf aus dem gleichen Netz. Am besten testet ihr es, wenn ihr an eurem Mobiltelefon W-LAN deaktiviert und im Browser folgende Seite aufruft: ''https://mein.hostname:3000''. Wenn ihr im Browser dann einen Quellcode von Alexa seht, funktioniert die Portumleitung.<br />
<br />
Wenn bis hier alles funktioniert und es läuft dennoch nicht rund, liegt das Problem woanders. Kommt z.B. bei der Gerätesuche kein Request rein (sichtbar auf dem Bildschirm, wenn bin/alexa gestartet wurden), kann evtl. der Lambda-Dienst falsch konfiguriert sein.<br />
<br />
====Probleme mit node.js - npm install====<br />
<br />
Falls eine Fehlermeldung auftritt, dass "npm" nicht gefunden werden kann, bitte NodeJS entsprechend der Anleitung im Homebridge-Artikel vorgehen: [[Homebridge_einrichten#NodeJS_installieren|NodeJS installieren]] sowie [[Homebridge_einrichten#Python.2C_g.2B.2B.2C_MDNS_installieren|Python, g++, MDNS installieren]], siehe auch folgenden Abschnitt.<br />
<br />
====Es kommen diverse Fehlermeldungen beim Starten von alexa-fhem und es beendet sich====<br />
Wenn man auf der Konsole angemeldet ist, den Befehl<syntaxhighlight lang="bash" style="width:50%;">node -v</syntaxhighlight>eingeben. Ist die Version niedriger als die geforderte 0.12, muss eine neuere installiert werden. Hier darf man dann im Wiki unter [[Homebridge_einrichten#NodeJS_installieren]] nachschauen. NodeJS V4 sollte hierbei schon ausreichen. Solange die node.js Version nicht passt, gar nicht groß rum experimentieren! Bitte beachtet, dass alle Voraussetzungen unter [[Alexa-Fhem#Voraussetzungen]] erfüllt sind! Keine Experimente mit Versionen die darunter liegen.<br />
<br />
====Fehlermeldung ''NAT-PMP failed: Error: timeout'' Fehler angezeigt beim Start von alexa-fhem====<br />
Wenn ihr dann alexa-fhem über die Konsole startet und bekommt folgenden Fehler: ''NAT-PMP failed: Error: timeout'', lasst euch davon nicht irritieren. Das bedeutet lediglich, dass der Port nicht automatich freigegeben wurde über uPNP. Alternativ prüft, ob die Funktion der Portfreigabe via uPNP auf eurem Router aktiviert ist.<br />
<br />
====Nach Start auf der Console beendet sich Alexa-FHEM sofort wieder====<br />
Unmittelbar nach dem Start von Alexa-FHEM werden ein paar UPNP Fehlermeldungen ausgegeben. Unmittelbar danach beendet sich Alexa-FHEM wieder. <br />
<br />
Viele scheinen ein Problem mit UPNP auf dem Raspberry Pi zu haben. Wenn dieses Problem auftritt einfach in der <code>~/.alexa/config.json</code> die folgenden Zeilen rauslöschen:<br />
<br />
<pre><br />
"nat-pmp": "10.0.1.1",<br />
"nat-upnp": true,<br />
</pre><br />
<br />
Jetzt erneut Alexa-FHEM starten. Sollte nun laufen.<br />
<br />
====Was ist zu tun, wenn alexa-fhem keine Geräte findet?====<br />
Zunächst müssen die Geräte, die angesprochen werden wollen, unter FHEM ein neues Attribut zugewiesen bekommen. Dazu das Gerät in FHEM öffnen und das Attribut ''genericDeviceType switch'' hinzufügen, wenn es ein Schalter mit der Funktiona AN/AUS sein soll. Wenn man will, kann man dem Gerät jetzt noch über das Attribut ''alias'' eine besseren Namen geben, mit dem Alexa das Gerät dann auch finden kann.<br />
Anschließend muss alexa-fhem neu gestartet werden und die definierten Geräte sollten nun gefunden werden.<br />
<br />
====Was ist zu tun, wenn Alexa zwar Geräte findet, diese aber nicht angesprochen werden können?====<br />
Zuerst die Informationen zum Datenfluss ganz oben ansehen. Dann am besten von hinten nach vorne vorgehen:<br />
* wenn nichts bei alexa-fhem ankommt: port forwarding prüfen<br />
* wenn lambda.js nichts los wird: im cloudwatch log nachsehen<br />
* wenn bei lambda.js nichts ankommt: den trigger prüfen<br />
<br />
<br />
Zunächst sollte man sich unter ''http://aws.amazon.com'' das Logfile seiner erstellten Funktion anschauen. Ist überhaupt ein Logfile vorhanden? Falls nicht, liegt es vermutlich am Trigger.<br />
Den solltet ihr überprüfen. Scheinbar kommt es hin und wieder vor, dass dieser nicht gesetzt ist. Dazu einfach auf ''Triggers'' klicken und mit ''Add trigger'' erneut einen anlegen. Hier muss, wie in der Anleitung unter '''AWS Lambda Funktion anlegen''' Punkt 7, die ''Application Id'' stehen und der Haken bei ''Enable trigger'' gesetzt sein. Dann alexa-fhem neu starten.<br />
Wenn ihr Änderugen gemacht habt und den alexa-fhem Dienst noch nicht neu gestartet habt, wäre jetzt der richtige Zeitpunkt.<br />
<br />
====Was ist zu tun, wenn sich der Alexa-Service nicht starten lässt?====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Der User in der User= Directive von alexa.service muss Ausführungsrecht auf dem alexa binary haben (x), so wie auch mind. Lesezugriff auf dem Verzeichnis nach -U Option in der ExecStart= Directive und auch auf dem WorkingDirectory }}<br />
Schaut bitte in das Unterverzeichnis [alexa-fhem (also dort, wo Ihr Alexa-FHEM instelliert habt]/bin. Die dort befindliche Datei ''alexa'' muss ausführbar sein. Also z.B. so:<br />
<syntaxhighlight lang="bash" style="width:70%;">2755327 4 -rwxr-xr-x 1 pi pi 339 Nov 26 23:20 alexa</syntaxhighlight><br />
Sollte dies nicht der Fall sein bitte mit:<br />
<syntaxhighlight lang="bash" style="width:70%;">chmod +x alexa</syntaxhighlight><br />
die Datei ausführbar machen. Sofern der User "pi" Eigentümer ist, ist kein sudo erforderlich.<br />
Eine lauffähige Konfiguration ist {{Link2Forum|Topic=71612|Message=668383|LinkText=hier}} zu sehen.<br />
<br />
====Wie kann ich via Alexa-FHEM auf FHEM zugreifen, wenn der Port mit Benutzername/Kennwort geschützt ist?====<br />
<br />
Hierzu muss die Datei <code>~/.alexa/config.json</code> geöffnet werden und der Abschnitt "connections" um folgende Zeile ergänzt werden:<pre><br />
"auth": {"user": "fhem", "pass": "fhempassword"},</pre><br />
Bei Verwendung von SSL bei FHEM muss auch noch <pre><br />
"ssl": true,</pre> hinzugefügt werden<br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Sprachsteuerung]]</div>Amenomadehttp://wiki.fhem.de/w/index.php?title=Alexa-Fhem&diff=22491Alexa-Fhem2017-09-06T00:59:36Z<p>Amenomade: /* Alexa-Fhem als Service (systemd) installieren */ Kommentar nach User=xxxxx führt zu 217/USER Fehler. /etc/default bringt unnötige Komplexität für normale Anwender</p>
<hr />
<div>'''Alexa-Fhem''' ist eine in JavaScript geschriebene und auf NodeJS basierende Software, welche es ermöglicht, der digitalen Amazon Assistentin Alexa zusätzliche Skills für die Heimautomatisierung via FHEM beizubringen. Eine erste funktionierende Version wurde von [https://forum.fhem.de/index.php?action=profile;u=430 justme1968] im {{Link2Forum|Topic=60244|LinkText=Forum}} veröffentlicht.<br />
Das ist eine erste Version der Dokumentation zur Installation und Einrichtung, eine Erweiterung wird sicherlich in nächster Zeit noch folgen.<br />
{{Infobox Modul<br />
|ModPurpose=Anbindung von FHEM an Amazon Assistent Alexa<br />
|ModType=x<br />
|ModTechName=<br />
|ModForumArea=Frontends/Sprachsteuerung<br />
|ModOwner=justme1968<br />
}} <br />
<br />
<br />
==Einführung==<br />
===Glossar===<br />
*Echo bzw. Echo Dot (im Folgenden maskulin bezeichnet) sind die derzeit verfügbaren Geräte des Alexa-Systems '''BILDER EINSTELLEN - Achtung Urheberrecht'''<br />
*AVS ist der Amazon Voice Service, d.h. die Spracherkennungskomponente des Systems.{{Randnotiz|RNTyp=r|RNText=Für die Nutzung der Amazon AWS-Dienste müssen zwingend die Daten einer Kreditkarte angegeben werden. Nach gegenwärtigem Kenntnisstand sollen jedoch keine Kosten für die Nutzung der im Rahmen dieses How To beschriebenen Dienste anfallen, sofern diese in einem Rahmen genutzt werden, der selbst eine intensive private Nutzung nicht überschreitet. Der Benutzer sei an dieser Stelle auf die von Amazon veröffentlichten Preislisten verwiesen. Die Autoren dieser Anleitung und der darin beschriebenen Module übernehmen keine Haftung für eventuelle Kosten, die aus der Nutzung der AWS entstehen. }}<br />
*AWS sind die Amazon Web Services, also per URL erreichbare Dienste zur Ausführung von Berechnungen etc. Im Rahmen von Alexa-Fhem wird bei AWS eine eigene JavaScript-Funktion hinterlegt, die zur Kommunikation mit dem FHEM-Server dient. Im Jargon von Amazon ist dies eine so genannte Lambda-Funktion '''WARUM ? Nachlesen bei Amazon'''.<br />
*Card bezeichnet einen Eintrag in der Alexa-App, der die erkannte Sprachnachricht sowie weiter gehenden Informationen über die Reaktion von Alexa enzthält und Rückmeldung an Amazon erlaubt.<br />
*Skill (engl. für Fähigkeit) ist die Bezeichnung für eine per Spracherkennung bediente Funktionalität des Alexa-Systems, z.B. zur Nachrichtenansage, zur Wettervorhersage oder zur Steuerung von FHEM<br />
<br />
===Arbeitsweise und Datenfluss===<br />
[[Datei:2gpXyLN.jpg|200px|thumb|right|Grafische Darstellung der beteiligten Komponenten]]<br />
Echo -> AVS -> AWS Lambda -> alexa-fhem -> AWS Lambda -> AVS -> Echo<br />
<br />
*Der Echo (oder ein anderes Alexa/AVS fähiges Gerät) nimmt Audiodaten auf und schickt diese an AVS (Amazon Voice Service) zur Erkennung<br />
*AVS führt die Spracherkennung durch und erzeugt ein Event mit Informationen zu den erkannten Daten<br />
:*Beim Alexa SmartHome Skill sind die möglichen Sätze für die Spracherkennung relativ fest vorgegeben <br />
:*Beim Alexa Custom Skill kommen die dazu nötigen Informationen aus dem ''Interaction Model'' der Alexa Skills Configuration<br />
*Das Event wird an den unter ''Configuration'' in der Alexa Skills Configuration hinterlegten Endpoint geschickt<br />
:*Beim Alexa SmartHome Skill ist das zwingend eine AWS Lambda Routine<br />
:*Beim Alexa Custom Skill kann das im Prinzip auch ein eigener Web Service sein<br />
*Das Event wird vom <code>lambda.js</code> code an alexa-fhem weitergeleitet<br />
*alexa-fhem steuert FHEM und sendet ein Antwort-Event zurück<br />
*<code>lambda.js</code> nimmt diese Antwort entgegen und gibt sie an AVS zurück<br />
*AVS sogt dafür das der Echo 'antwortet' und dass die Card in der Alexa App erscheint<br />
<br />
===Anmerkungen===<br />
*Ein Skill hat keinen Zugriff auf die Audiodaten<br />
*Mit dem Skill API kann ein Skill zu zu keiner Zeit von sich aus aktiv werden und 'einfach' Daten an den Echo schicken oder ihn dazu bringen irgendetwas zu tun.<br />
*Wenn man berücksichtigt welchen Weg die Daten insgesamt gehen, ist es erstaunlich, wie schnell die Reaktion auf einen gesprochenen Satz erfolgt.<br />
<br />
=== Abgrenzung des '''Alexa Smart Home Skills''' und des '''Alexa Custom Skills''' ===<br />
<br />
Der [[Alexa-Fhem#Smart_Home|Alexa Smart Home Skill]] ist ein Amazon-Alexa-Standard-Skill, der wesentliche Basisfunktionalitäten bereitstellt. Zu diesen gehört im Wesentlichen die Funktionalität, durch Alexa-FHEM bereitgestellte Devices im Alexa-Account des Benutzers anzulegen. Der Alexa Smart Home Skill reagiert auf gesprochene Interaktion in einem beschränkten Umfang. Beispielsweise genügt ein "Alexa, schalte die Wohnzimmerlampe an" um eine Interaktion zwischen Alexa Smart Home Skill und FHEM-Alexa auszulösen. Nach erfolgreicher Einrichtung wird dieser Skill in der Alexa-App bzw. im Web in der Rubrik "Smart Home" als Skill angezeigt.<br />
<br />
Der [[Alexa-Fhem#Custom|Alexa Custom Skill]] ist kein Standard-Smart-Home-Skill, sondern ein individuell entwickelter Skill, so wie alle anderen Skills auch. Er wird daher auch nicht in der Alexa-App unter der Rubrik "Smart Home" angezeigt. Gesprochene Interaktion mit diesem Skill erfolgt dadurch, dass entweder der Skill explizit gestartet wird (z.B. "Alexa, starte [Name des Skills]") oder direkt angesprochen wird (z.B. "Alexa, frage [Name des Skills] wie ist der Status von [Device] "). Der Alexa Custom Skill befindet sich in Entwicklung und wird hinsichtlich seiner Funktionalitäten laufend weiterentwickelt. Die Einrichtung dieses Skills ist grundsätzlich optional, jedoch werden anspruchsvollere Steuerungsmöglichkeiten nur mit diesem realisiert werden können.<br />
<br />
==Installation==<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Da die einzelnen Schritte der Anleitung an verschiedenen Stellen unterbrochen und später fortgesetzt werden müssen, empfiehlt es sich, die Anleitung einmal vollständig gelesen zu haben. Während der Konfiguration sollten alle nachfolgenden Abschnitte parallel in gleichzeitig geöffneten Browserfenstern durchgeführt werden, die jeweils bis zum Abschluss geöffnet bleiben müssen. }}<br />
Grundvoraussetzung für alle folgenden Schritte ist das Vorhandensein eines Amazon-Accounts. Es wird davon ausgegangen, dass die Konten für alle im Folgenden genutzten Amazon-Dienste eingerichtet wurden.<br />
<br />
===node.js installieren===<br />
Zunächst wird das Betriebssystem (in diesem Falle Debian oder Ubuntu) auf den aktuellen Stand gebracht:<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
sudo apt-get update<br />
sudo apt-get upgrade<br />
sudo apt-get install build-essential libssl-dev</syntaxhighlight><br />
<br />
Nun muss NodeJS installiert werden. Leider ist die Version im Debian Repository deutlich zu alt, daher wird mit den folgenden Befehlen das Node Repository hinzugefügt und NodeJS (in der LTS Version) entsprechend installiert:<br />
<syntaxhighlight lang="bash" style="width:50%;"><br />
curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -<br />
sudo apt-get install -y nodejs<br />
</syntaxhighlight><br />
<br />
=== Alexa-Fhem installieren ===<br />
'''Aus gegebenem Anlass: Dies ist weder eine Einführung in Linux, noch eine Anfängerdokumentation für FHEM.''' Also erst die Grundlagen lernen, und dann mit Alexa beginnen !<br />
<br />
Die aktuelle Version ist jeweils {{Link2Forum|Topic=60244|Message=540117|LinkText=hier}} zu finden.<br />
<br />
====Erstinstallation====<br />
Hier wird die Erstinstallation von Alexa-Fhem beschrieben.<br />
===== Linux =====<br />
# Die tgz-Datei unter Linux im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) entpacken (''nicht'' unter Windows, das zerstört die Rechteeinstellungen).<syntaxhighlight lang="bash" style="width:50%;">tar -xvzf dateiname.tgz</syntaxhighlight><br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen <syntaxhighlight lang="bash" style="width:50%;">mv package alexa-fhem</syntaxhighlight><br />
# Durch <syntaxhighlight lang="bash" style="width:50%;">cd alexa-fhem</syntaxhighlight> in das Verzeichnis wechseln<br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren (kein sudo!).<br />
# SSL Zertifikat erzeugen durch Aufruf von <syntaxhighlight lang="bash" style="width:50%;">./createKey.sh</syntaxhighlight> (kein sudo!). Hierbei beachten, dass ein Kennwort vergeben werden muss, das mindestens aus 4 Zeichen besteht, dieses Kennwort bitte merken.<br />
# Das Verzeichnis ''.alexa'' anlegen, ''und zwar im Home-Verzeichnis desjenigen Benutzers, unter dem Alexa-Fhem laufen soll.'' Insbesondere ist zu beachten, dass dieser Nutzer u.U. im Startskript explizit gesetzt wird. Mit dem untenstehenden Skript ist das ''nicht'' der User fhem, sondern der User ''pi''. Das Symbol ''~/'' verweist auf das Home-Verzeichnis des Benutzers, der gerade die Installation vornimmt.<br />
# Die Datei ''config-sample.json'' nach ''.alexa/config.json'' kopieren. Achtung: Installiert man alexa-fhem als root-user, zeigt das Symbol ''~/'' auf ''/root'' - und die Konfigurationsdatei wird ggf. bei einem manuellen Start von Alexa-Fhem nicht gefunden.<br />
# Achtung: Ggf. müssen auch die Dateien key.pem und cert.pem ins entsprechende Verzeichnis kopiert werden.<br />
===== Windows =====<br />
''Vor'' der Installation von Alexa-Fhem muss man folgende Anwendungen installieren:<br />
* Node.js (die aktuelle Version findet man unter https://nodejs.org/en/download/)<br />
* OpenSSL (http://slproweb.com/products/Win32OpenSSL.html oder https://www.heise.de/download/product/win32-openssl-47316/download)<br />
Erst dann fängt man mit Alexa-Fhem an.<br />
<br />
<br />
# Die tgz-Datei im Hauptverzeichnis von FHEM (z.B. <code>С:\Program Files (x86)\fhem</code>) entpacken.<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen<br />
# Windows-Shell (Kommandozeile, Eingabeaufforderung usw.) öffnen. "Start" -> "Ausführen" (oder [Windows-Taste]+[R]) -> cmd -> Ok. Durch <syntaxhighlight lang="bash" style="width:50%;">cd "<FHEM-Hauptverzeichis>\alexa-fhem"</syntaxhighlight> in das Verzeichnis wechseln. <br/>Dabei ist natürlich das <FHEM-Hauptverzeichis> durch den entsprechenden Pfad aus dem Schritt 1 zu ersetzen. Im o.g. Beispiel wäre es <code>cd "С:\Program Files (x86)\fhem\alexa-fhem"</code><br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren.<br/> Bei der Fehlermeldung wie "Der Befehl "npm" ist entweder falsch geschrieben oder konnte nicht gefunden werden." ist die Installation von Node.js zu überprüfen.<br />
# SSL Zertifikat erzeugen. Dafür muss man alle Befehle aus dem Skript ''createKey.sh'' nacheinander manuell ausführen. Hierbei beachten, dass ein Kennwort vergeben werden muss, das mindestens aus 4 Zeichen besteht, dieses Kennwort bitte merken. Der Windows-Welt unbekannter Befehl <code>mv</code> ist durch <code>move /y</code> zu ersetzen:<syntaxhighlight lang="bash" style="width:50%;">openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;">openssl rsa -in key.pem -out newkey.pem</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;">move /y newkey.pem key.pem</syntaxhighlight> Eventuelle Fehlermeldung "can't open config file: /usr/local/ssl/openssl.cnf" o.Ä. lässt sich durch Befehl <code>set OPENSSL_CONF=<OpenSSL-Verzeichnis>\bin\openssl.cfg</code> beheben, wobei <OpenSSL-Verzeichnis> durch den entsprechenden Installationspfad (typischerweise <code>c:\OpenSSL-Win32</code>) zu ersetzen ist.<br />
# Das Verzeichnis ''.alexa'' anlegen, ''und zwar im Benutzerverzeichnis desjenigen Benutzers, unter dem Alexa-Fhem laufen soll.'' In aktuellen Versionen von Windows (ab Windows 7 bzw. ab Windows Server 2008 R2) liegt das Verzeichnis unter <code>C:\Users\<Benutzername></code>, also z.B. für Benutzer "Administrator" - unter <code>C:\Users\Administrator</code>.<br/>Falls Windows sich weigert das Verzichniss mit dem Punkt am Anfang zu erstellen, kann man das aus der Kommandozeile machen:<syntaxhighlight lang="bash" style="width:50%;">cd "C:\Users\<Benutzername>"</syntaxhighlight><syntaxhighlight lang="bash" style="width:50%;"><br />
mkdir ".alexa"</syntaxhighlight><br />
# Die Datei ''config-sample.json'' nach ''C:\Users\<Benutzername>\.alexa\config.json'' kopieren.<br />
# Achtung: Ggf. müssen auch die Dateien key.pem und cert.pem ins entsprechende Verzeichnis (<code>"<FHEM-Hauptverzeichis>\alexa-fhem\bin</code>) kopiert werden.<br />
<br />
====Update====<br />
Hier wir das Update auf eine neue Version von Alexa-Fhem beschrieben<br />
===== Linux =====<br />
# Das Verzeichnis ''alexa-fhem'' im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) umbenennen in ''alexa-fhem.old''.<br />
# Die tgz-Datei der neuen Alexa-Fhem-Version unter Linux im Hauptverzeichnis von FHEM (typischerweise <code>/opt/fhem</code>) entpacken (''nicht'' unter Windows, das zerstört die Rechteeinstellungen).<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen, in das Verzeichnis wechseln<br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren (kein sudo!).<br />
# Die Zertifikatsdateien key.pem und cert.pem aus dem alten Verzeichnis ''alexa-fhem.old'' ins neue Verzeichnis ''alexa-fhem'' kopieren.<br />
Natürlich dann den Dienst neu starten, auch müssen selbstredend irgendwelche Modifikationen an der Datei server.js in der neuen Version nachgezogen werden. Wenn alles läuft, kann das alte Verzeichnis ''alexa-fhem.old'' gelöscht werden.<br />
===== Windows =====<br />
# Das Verzeichnis ''alexa-fhem'' im Hauptverzeichnis von FHEM (z.B. <code>С:\Program Files (x86)\fhem</code>) umbenennen in ''alexa-fhem.old''.<br />
# Die tgz-Datei der neuen Alexa-Fhem-Version im Hauptverzeichnis von FHEM entpacken.<br />
# Das dabei entstandene Verzeichnis ''package'' in ''alexa-fhem'' umbenennen<br />
# Windows-Shell (Kommandozeile, Eingabeaufforderung usw.) öffnen. "Start" -> "Ausführen" (oder [Windows-Taste]+[R]) -> cmd -> Ok. Durch <syntaxhighlight lang="bash" style="width:50%;">cd "<FHEM-Hauptverzeichis>\alexa-fhem"</syntaxhighlight> in das Verzeichnis wechseln. <br/>Dabei ist natürlich das <FHEM-Hauptverzeichis> durch den entsprechenden Pfad aus dem Schritt 1 zu ersetzen. Im o.g. Beispiel wäre es <code>cd "С:\Program Files (x86)\fhem\alexa-fhem"</code><br />
# Mit <syntaxhighlight lang="bash" style="width:50%;">npm install</syntaxhighlight> alle Abhängigkeiten installieren.<br />
# Die Zertifikatsdateien key.pem und cert.pem aus dem alten Verzeichnis ''alexa-fhem.old'' ins neue Verzeichnis ''alexa-fhem'' kopieren.<br />
Natürlich dann den Dienst neu starten, auch müssen selbstredend irgendwelche Modifikationen an der Datei server.js in der neuen Version nachgezogen werden. Wenn alles läuft, kann das alte Verzeichnis ''alexa-fhem.old'' gelöscht werden.<br />
<br />
==== Alexa-Fhem konfigurieren ====<br />
Der Inhalt der Datei ''~/.alexa/config.json'' muss an die eigene Umgebung angepasst werden. <br />
# ''nat-pmp'' -> wenn nat-pmp verwendet werden soll: die ip des eigenen routers,<br />
# ''nat-upnp'' -> wenn nat-upnp verwendet werden soll: ''true'',<br />
# ''applicationId'' <br />
#:* Wenn man nur den SmartHome-Skill verwenden möchte, kann dieser Eintrag leer bleiben.<br />
#:* Ansonsten ist er mit der SkillID des Alexa Custom Skills zu belegen, siehe Abschnitt [[#Skill_Id_bestimmen | Skill Id bestimmen]]<br />
# ''oauthClientID'' -> ''Client ID'' dem Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
# ''server'' -> IP-Adresse des eigenen FHEM-Servers<br />
# ''port'' -> Portnummer des eigenen FHEM-Servers<br />
Beispiel:<br />
{<br />
"alexa": {<br />
"name": "Alexa TEST",<br />
"keyFile": "./key.pem",<br />
"certFile": "./cert.pem",<br />
"applicationId": "amzn1.ask.skill.xxxxxxxxxxxxxxxxxxxxxxxxxxxx",<br />
"oauthClientID": "amzn1.application-oa2-client.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"<br />
},<br />
"connections": [<br />
{<br />
"name": "FHEM",<br />
"server": "192.168.0.xxx.xxx",<br />
"port": "8083",<br />
"filter": "room=AlexaRoom"<br />
}<br />
]<br />
}<br />
<br />
Mehrere Custom Skills lassen sich mit der folgenden Syntax eintragen<br />
"applicationId": [ "amzn1.ask.skill.1" , "amzn1.ask.skill.2" ],<br />
"oauthClientID": [ "amzn1.application-oa2-client.1" , "amzn1.application-oa2-client.1" ]<br />
<br />
Danach durch Aufruf von <syntaxhighlight lang="bash" style="width:50%;">./bin/alexa</syntaxhighlight> den Dienst starten (kein sudo!)<br />
<br />
<br />
Unter Windows startet man Alexa-Dienst durch <syntaxhighlight lang="bash" style="width:50%;">node alexa</syntaxhighlight> aus der <code>alex-fhem/bin</code> (also erst z.B. durch <code>cd "<FHEM-Hauptverzeichis>\alexa-fhem\bin"</code> ins richtige Verzeichnis kommen)<br />
<br />
Der Start des Alexa-Dienstes auf der Console ist immer dann zu empfehlen, wenn man auf die Ausgaben des Dienstes angewiesen ist und beispielsweise sehen möchte, welche Devices durch den Dienst bereitgestellt werden oder ob Fehler auftreten. Beendet man die Console-Session wird auch der Dienst wieder beendet. Insofern ist die vorgenannte Vorgehensweise nur für ein Debugging zu empfehlen und nicht im Regelbetrieb. Nachfolgend ist beschrieben, wie man den Alexa-Dienst aus FHEM heraus starten / stoppen und neu starten kann.<br />
<br />
==== Alexa-Fhem aus FHEM heraus starten ====<br />
Zunächst das Start-up-Skript aus diesem Post herunterladen {{Link2Forum|Topic=60244|Message=517271|LinkText=https://forum.fhem.de/index.php/topic,60244.msg517271.html#msg517271}} und unter /etc/init.d/alexa speichern.<br />
<br />
Das Script geht davon aus, das der alexa-fhem script unter /opt/fhem/alexa-fhem liegt, und die logfiles später unter /opt/fhem/log. Sollte das nicht der Fall sein, muss das Skript angepasst werden.<br />
<br />
Nun folgende Kommandos ausführen:<br />
<syntaxhighlight lang="bash" style="width:50%;">sudo chmod 755 /etc/init.d/alexa<br />
sudo update-rc.d alexa defaults</syntaxhighlight><br />
<br />
In der Datei <code>/etc/sudoers</code> den User fhem für die Nutzung von sudo zulassen (<code>sudo nano /etc/sudoers</code>), z.B. durch Anfügen der nachfolgenden Zeile:<br />
<code>fhem ALL=(ALL) NOPASSWD: ALL</code><br />
<br />
Nun folgende Devices anlegen (ggf. einem Raum zuordnen, z.B. AlexaControl):<br />
<syntaxhighlight lang="bash" style="width:75%;">define FHEM.Alexa.Status dummy<br />
<br />
define FHEM.Alexa dummy<br />
attr FHEM.Alexa event-on-change-reading state<br />
attr FHEM.Alexa webCmd status:start:stop:restart<br />
<br />
define FHEM.Alexa.DOIF DOIF ([FHEM.Alexa] eq "start") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa start > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "stop")<br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa stop > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "restart") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa restart > /dev/null 2>&1 &")}) <br />
DOELSEIF ([FHEM.Alexa] eq "status") <br />
(set FHEM.Alexa on, {system ("sudo /etc/init.d/alexa status > /dev/null 2>&1 &")})</syntaxhighlight><br />
<br />
==== Alexa-Fhem als Service (systemd) installieren ====<br />
Auf neueren Installationen (z.B. RPi Jessie) wird init.d durch systemd ersetzt. Folgend die Anleitung um alexa-fhem als Service zu installieren auf einem Raspberry Pi mit Jessie.<br />
<br />
Zunächst einen neuen Benutzer anlegen unter dem alexa-fhem laufen soll, falls man nicht möchtet dass alexa-fhem z.B. mit dem fhem User ausgeführt wird:<br />
<br />
<code lang="bash" style="width:75%;"><br />
sudo useradd -M --system alexa<br />
</code><br />
<br />
Eigentlich braucht der Benutzer keine Gruppen, aber man kann den Benutzer auch der Gruppe <code>dialout</code> hinzufügen (<code>sudo usermod -a -G dialout alexa</code>)<br />
<br />
Datei "alexa.service" unter <code>/etc/systemd/system</code> anlegen:<br />
<br />
[Unit]<br />
Description=Node.js Alexa Server <br />
After=syslog.target network-online.target<br />
<br />
[Service]<br />
Type=simple<br />
User=alexa <br />
WorkingDirectory=/opt/alexa/alexa-fhem<br />
ExecStart=/opt/fhem/alexa-fhem/bin/alexa -U /home/alexa/.alexa<br />
Restart=on-failure<br />
RestartSec=10<br />
KillMode=process<br />
<br />
[Install]<br />
WantedBy=multi-user.target <br />
<br />
Den Pfad <code>/home/alexa/.alexa</code> an die Systemgegebenheiten anpassen. Letztendlich kann die config.json irgendwo liegen, hauptsache alexa-fhem weiß wo. <code><Homeverzeichnis des "User=">/.alexa</code> empfholen. <br />
<br />
Im WorkingDirectory wird der alexa Dienst die Zertifikate suchen.<br />
<br />
Achtung: Natürlich muss der Benutzer auch Zugriff auf das Verzeichnis mit der config als auch das alexa-fhem Verzeichnis und das WorkingDirectory haben.<br />
<br />
Um den Service zu aktiveren und zu starten helfen folgende Befehle:<br />
sudo systemctl daemon-reload<br />
sudo systemctl enable alexa<br />
sudo systemctl start alexa<br />
<br />
Status abfragen mit<br />
sudo systemctl status alexa<br />
<br />
Log einsehen?<br />
sudo journalctl -u alexa<br />
<br />
(mit <code>-f</code> kann man den follow Modus aktivieren, wie <code>tail -f</code>).<br />
Bei einen reboot startet alexa-fhem jetzt automatisch.<br />
<br />
==== Alexa-Fhem testen ====<br />
Node.Js stellt einen Web-Server am Port 3000 bereit, das oben erzeugte Zertifikat sichert diesen Zugang per SSL ab. Durch Aufruf der Adresse<br />
<code>https://<IP-Adresse des Servers>:3000</code> kann man testen, ob der Alexa-Fhem Service läuft - der Seitenaufruf liefert eine Zeile JSON-Code, beginnend mit<br />
<code>{"header":{"name":"UnsupportedOperationError"...</code><br />
<br />
=== Alexa Device anlegen ===<br />
<br />
Das Modul 39_alexa.pm stellt innerhalb von FHEM verschiedene Attribute z.B. alexaName oder alexaRoom zur Verfügung. Manche dieser Attribute (wie z.b. alexaName) werden in beiden Skills verwendet, andere werden ausschließlich bei einer Nutzung des Alexa Custom Skill verwendet.<br />
<br />
Die Einrichtung des Alexa Device geschieht durch die nachfolgende Definition:<br />
<syntaxhighlight lang="bash" style="width:70%;">define MyAlexa alexa</syntaxhighlight><br />
<br />
<hr><br />
<br />
=== Alexa Skills ===<br />
Für folgende Schritte muss man unter der Adresse http://developer.amazon.com angemeldet sein<br />
# Anmeldung auswählen<br />[[Datei:Developer.amazon.com-01-login2.png|200px]]<br />
# Anmeldedaten eingeben<br />[[Datei:Developer.amazon.com-02-userpass2.png|200px]]<br />
<br />
==== Security Profile anlegen ====<br />
Die Erzeugung eines Sicherheitsprofils muss nur einmal erfolgen, es wird dann für alle weiteren Skills verwendet.<br />
# Nach der Anmeldung Auswahl von ''APPS & SERVICES''<br />[[Datei:Developer.amazon.com-03-apps_and_services.png|200px]]<br />
# Anschließend auswählen ''Security Profiles''<br />[[Datei:Developer.amazon.com-05-apps_and_services_-_security_profiles.png|200px]]<br />
# Auswählen ''Create a New Security Profile'' aus<br />[[Datei:Developer.amazon.com-06-apps_and_services_-_create_a_new_security_profile.png|200px]]<br />
# Dann einen Namen und eine Beschreibung für das Profil eingeben und mit ''Save'' bestätigen<br />[[Datei:Developer.amazon.com-07-apps_and_services_-_security_profile_management.png|200px]]<br />
<br />
===== Login with Amazon =====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Hier wird beschrieben, wo ''Client Id'' und ''Client Secret'' zu finden sind}}<br />
# Oben rechts auf ''Login with Amazon'' klicken.<br/>[[Datei:Developer.amazon.com-08-login_with_amazon.png|200px]]<br />
# Auf der neu geladenen Seite auswählen ''Sign up''<br/>[[Datei:Developer.amazon.com-09-login_with_amazon_-_sign_up.png|200px]]<br />
# Anschließend im Dropdown Menü das vorher angelegte Profil auswählen und mit ''Confirm'' bestätigen<br/>[[Datei:Developer.amazon.com-10-login_with_amazon_-_create_new_profile.png|200px]] [[Datei:Developer.amazon.com-11-login_with_amazon_-_create_new_profile2.png|200px]]<br />
# Im folgenden Fenster die Adresse [https://www.amazon.com/gp/help/customer/display.html?nodeId=468496 https://www.amazon.com/gp/help/customer/display.html?nodeId=468496] eingeben und mit ''Save'' bestätigen. '''Todo Erklärungsbedarf: WARUM diese Adresse'''<br/>[[Datei:Developer.amazon.com-12-login_with_amazon_-_enter_consent_screen_information.png|200px]]<br />
# Anschließend bei dem neu angelegten Eintrag auf der rechten Seite auf das Zahnrad klicken und ''Web Settings'' auswählen<br/>[[Datei:Developer.amazon.com-13-login_with_amazon_-_web_settings.png|200px]]<br />
# Im neu geladenen Fenster anklicken von ''Edit''<br/>[[Datei:Developer.amazon.com-14-login_with_amazon_-_edit.png|200px]]<br />
# Anschließend bei ''Allowed Return URLs'' die folgenden drei Adressen eingeben. ''xxx'' muss hierbei durch den Wert ersetzt werden, der in den beiden Abschnitten [[#SmartHome_Skill_anlegen | SmartHome Skill anlegen]] bzw. [[#Custom_Skill_anlegen | Custom Skill anlegen]] jeweils unter Punkt 4 (Seite ''Configuration'') bei ''Redirect Urls'' am Ende der URLs angezeigt wird<br />
## [https://layla.amazon.co.uk/api/skill/link/xxx https://layla.amazon.co.uk/api/skill/link/xxx]<br />
## [https://pitangui.amazon.com/api/skill/link/xxx https://pitangui.amazon.com/api/skill/link/xxx]<br />
## [https://layla.amazon.com/api/skill/link/xxx https://layla.amazon.com/api/skill/link/xxx]<br />
.<br/>[[Datei:Developer.amazon.com-15-login_with_amazon_-_allowed_return_urls.png|200px]]<br />
<br />
==== Skills bearbeiten ====<br />
# Im Menü den Punkt ''ALEXA'' auswählen<br />[[Datei:Developer.amazon.com-03-apps_and_services.png|200px]]<br />
# Anschließend im Feld ''Alexa Skills Kit'' auf ''Get started'' klicken<br />[[Datei:Developer.amazon.com-17-alexa_-_alex_skills_kit_-_get_started.png|200px]]<br />
<br />
===== SmartHome Skill anlegen =====<br />
# Oben rechts ''Add a New Skill'' auswählen<br />[[Datei:Developer.amazon.com-18-alexa_-_alex_skills_kit_-_add_a_new_skill.png|200px]]<br />
# Auf der folgenden Seite eingeben und dann mit ''Next'' bestätigen:<br />
#:* ''Skill Type'' -> ''SmartHome Skill API'' <br />
#:* ''Language'' -> ''German''<br />
#:* ''Name'' -> beliebiger Name, z.B. "MySmartHome Basic")<br />
#:* ''Payload Version'' -> ''v2 (other devices)'' <br/>[[Datei:Developer.amazon.com-19-alexa_-_alex_skills_kit_-_skill_information.png|200px]]<br />
# Die folgende Seite einfach mit ''Next'' überspringen<br />[[Datei:Developer.amazon.com-20-alexa_-_alex_skills_kit_-_interaction_model.png|200px]]<br />
# Auf der Seite ''Configuration'' Folgendes eingeben:<br />
#:* ''Service Endpoint Type'' -> ''AWS Lambda'' ist vorausgewählt und kann nicht geändert werden.<br />
#:* ''Geographical Region'' -> ''Europe'' auswählen und im Textfeld die ARN aus Abschnitt [[#ARN_der_AWS_Lambda_Funktion_bestimmen | AWS Lambda Funktion]] eintragen. <br />
#:* ''Authorization URL'' -> <code>https://www.amazon.com/ap/oa</code><br />
#:* ''Client ID'' -> ''Client ID'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
#:* ''Scope'' -> <code>profile:user_id</code> (wörtlich 1:1 eintragen)<br />
#:* ''Redirect URLs'' - sollten vorbelegt sein<br />
#:* ''Authorization Grant Type'' -> ''Auth Code Grant'' auswählen<br />
#:* ''Access Token URI'' -> <code>https://api.amazon.com/auth/o2/token</code><br />
#:* ''Client Secret'' -> ''Client Secret'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1<br />
#:* ''Client Authentication Scheme'' -> ''HTTP Basic''<br />
#:* ''Privacy Policy URL'' -> <code>https://www.amazon.com/gp/help/customer/display.html?nodeId=468496</code><br /><br /><br />
<br />[[Datei:Developer.amazon.com-21-alexa_-_alex_skills_kit_-_configuration.png|200px]] [[Datei:Developer.amazon.com-22-alexa_-_alex_skills_kit_-_test.png|200px]]<br />
<br />
===== Custom Skill anlegen =====<br />
<ol><br />
<li> Oben rechts ''Add a New Skill'' auswählen<br />[[Datei:Developer.amazon.com-18-alexa_-_alex_skills_kit_-_add_a_new_skill.png|200px]]</li><br />
<li> Auf der folgenden Seite (''Skill Information'') die nachstehenden Daten eingeben und dann mit ''Next'' bestätigen:<br />
<ul><br />
<li> ''Skill Type'' -> ''Custom Interaction Model'' </li><br />
<li> ''Language'' -> ''German''</li><br />
<li> ''Name'' -> beliebiger Name, z.B. "MySmartHome Advanced". Dieser wird in der Alexa App unter "Meine Skills" angezeigt.</li><br />
<li> ''Invocation Name'' -> Aufruf des Skills, unter dem dieser später gestartet wird. Z.B. "Alexa, starte James"<br />[[Datei:CustomSkill_2.PNG|400px]]</li><br />
</ul></li><br />
<li>Auf der Seite ''Interaction Model'' folgende Eingaben tätigen und mit ''Next'' abschließen<br />
<ul><br />
<li>In einem separaten Browserfenster FHEM aufrufen, und für das bereits definierte Alexa-Gerät das Kommando <code>get MyAlexa interactionModel</code> aufrufen. Es erscheint ein Popup-Fenster mit ziemlich vielen Zeilen.<br />
<li>In die Box ''Intent Schema'' kopiert man den ersten Teil dieser FHEM-Ausgabe hinein, also:<br/><blockquote><br />
{ <br />
"intents" : [ <br />
<hier ziemlich viele Zeilen> <br />
]<br />
}<br />
</blockquote></li><br />
<li>Nun die ''Custom Slot Types'' einrichten. Dazu muss aus dem zweiten Teil der FHEM-Ausgabe jeweils der Slot-Type (z.B. <code>FHEM_article</code>) in das Feld ''TYPE'' eingetragen werden, das nach dem Anklicken von ''Add Slot Type'' erscheint. In das darunter liegende größere Textfeld kommen die möglichen Werte für diesen Slot, so wie sie aus der FHEM-Ausgabe abzulesen sind. Dann mit ''Save'' sichern. Als Custom Slot Type erscheint dann für diesen Beispiel-Slot<br />
FHEM_article der | die | das | den<br />
d.h., die Zeilenumbrüche bei den möglichen Werten werden als "|" dargestellt.</li><br />
<li>Hier muss nun ein Bruch im Arbeitsfluss durchgeführt werden, denn bei der Erstellung des Custom Skills kommt es auf die Reihenfolge der Einträge an. Deshalb zunächst diese FHEM-Ausgabe schließen, und für dasselbe FHEM-Device <code>get MyAlexa customSlotTypes</code> ausführen. Auch diese Ausgabe wird, wie oben beschriebeen, in Custom Slot Types eingetragen (erst der TYPE, dann die möglichen Werte)<br />
<li>Anschließend erneut die FHEM-Ausgabe schließen und erneut für das bereits definierte Alexa-Gerät das Kommando <code>get MyAlexa interactionModel</code> aufrufen.<br />
<li>Unter ''Sample Utterances'' nun den Text aus dem dritten Teil dieser FHEM-Ausgabe hineinkopieren<br />[[Datei:CustomSkill_5.PNG|400px]]</li><br />
</ul></li><br />
<li>Auf der Seite ''Configuration'' Folgendes eingeben und mit ''Next'' bestätigen:<br />
<ul><br />
<li>''Service Endpoint Type'' -> ''AWS Lambda'' auswählen</li><br />
<li>''Geographical Region'' -> ''Europe'' auswählen und im Textfeld den Wert aus Abschnitt [[#AWS_Lambda_Funktion_anlegen | AWS Lambda Funktion anlegen]] (Punkt 12) eintragen. </li><br />
<li>''Do you allow users to create an account or link to an existing account with you?'' -> ''Yes''</li><br />
<li>''Authorization URL'' -> <code>https://www.amazon.com/ap/oa</code></li><br />
<li>''Client ID'' -> ''Client ID'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1</li><br />
<li>''Scope'' -> <code>profile:user_id</code> (wörtlich 1:1 eintragen)</li><br />
<li>''Redirect URLs'' - sollten vorbelegt sein</li><br />
<li>''Authorization Grant Type'' -> ''Auth Code Grant'' auswählen</li><br />
<li>''Access Token URI'' -> <code>https://api.amazon.com/auth/o2/token</code></li><br />
<li>''Client Secret'' -> ''Client Secret'' aus Abschnitt [[#Login_with_Amazon | Login with Amazon]], Punkt 1</li><br />
<li>''Client Authentication Scheme'' -> ''HTTP Basic''</li><br />
<li>''Privacy Policy URL'' -> <code>https://www.amazon.com/gp/help/customer/display.html?nodeId=468496</code></li><br />
</ul><br />
Beim Sichern dieser Seite mit ''Next'' kann es zu einer Fehlermeldung kommen, wenn man seine Skill-Definitionen mit dem einfachen SmartHome-Skill begonnen hat. Deshalb muss noch der entsprechende Trigger für die [[#AWS_Lambda-Funktion | AWS Lambda Funktion]] nachgetragen werden, dies wird in Abschnitt [[#Trigger_f.C3.BCr_Custom_Skill_hinzuf.C3.BCgen | Trigger für Custom Skill hinzufügen]] beschrieben.<br />
<br />[[Datei:CustomSkill_6.PNG|400px]] [[Datei:CustomSkill_7.PNG|400px]]</li><br />
<br />
==== Testen ====<br />
Hat man den Custom Skill angelegt, bietet dieser auch eine komfortable Testmöglichkeit. Dazu wählt man in der Übersichtsseite ''All Skills'' den Button ''Edit'' des Alexa Custom Skill aus. Auf der nachfolgenden Seite dann links ''Test''. <br />
Die Testseite enthält <br />
* ein Feld ''Voice Simulator'', mit dem man die Sprachsausgabe testen kann, <br />
* ein Feld ''Service Simulator'', mit dem die Verarbeitung von Alexa-Kommandois getestet werden kann. Hier kann man z.B. eintragen<br />
"Alexa, sage <Custom Skill Invocation Name>: Stelle Weckzeit auf Neunzehn Siebenundzwanzig Uhr"<br />
"Alexa, frage <Custom Skill Invocation Name> nach dem Status von Weckzeit"<br />
Dabei ist natürlich der ''Custom Skill Invocation Name'' durch den Wert zu ersetzen, den man im Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]] unter Punkt 2 eingetragen hat.<br />
<br />
==== Skill Id bestimmen ====<br />
{{Randnotiz|RNTyp=[g|Info]|RNText=Hier wird beschrieben, wo die ''Alexa Skill Id'' zu finden ist}}<br />
Für das [[#AWS_Lamba_Funktion_anlegen | Anlegen einer ''AWS Lambda Funktion'']] bzw für die [[#Alexa-Fhem_konfigurieren | Konfiguration von Alexa-Fhem]] wird die ''Alexa Skill Id'' benötigt. An diese kommt man wie folgt:<br />
# Anmelden wie unter [[#Alexa_Skills | Alexa Skills]] beschrieben.<br />
# Menüpunkt ''ALEXA'' auswählen, wie [[#Skills_bearbeiten | Skills bearbeiten]] erklärt.<br />
# Beim gewünschten Eintrag auf ''Edit'' klicken<br />[[Datei:Developer.amazon.com-23-alexa_-_alex_skills_kit_-_overview.png|200px]]<br />
# Die Id, die nun oben angezeigt wird, ist die gesuchte. Sie hat typischerweise das Format <code>amzn1.ask.skill.[Zahlen und Bindestriche]</code><br />[[Datei:Aws.amazon.com-06-configure_triggers2.png|200px]]<br />
<br />
<hr><br />
<br />
=== AWS Lambda Funktion ===<br />
Für folgende Schritte muss man unter der Adresse http://aws.amazon.com angemeldet sein<br />
# Anmeldung auswählen<br />[[Datei:Aws.amazon.com-01-site.png|200px]]<br />
# Anmeldedaten eingeben<br />[[Datei:Aws.amazon.com-02-login.png|200px]]<br />
# Den Punkt ''Lambda'' links auf der Startseite auswählen, bzw. im Menü ''Services'' unter ''Compute'' den Menüpunkt ''Lambda'' auswählen<br />[[Datei:Aws.amazon.com-03-lambda.png|200px]]<br />
==== AWS Lambda Funktion anlegen ====<br />
# Für eine erste Lambda-Funktion den Punkt ''Get Started Now'' auswählen<br />[[Datei:Aws.amazon.com-04-get_started_now.png|200px]]<br />
# Den Blueprint ''Blank function'' auswählen<br />[[Datei:Aws.amazon.com-05-select_blueprint.png|200px]]<br />
# Im neuen Fenster dann auf den gestrichelten Kasten klicken und ''Alexa Smart Home'' auswählen und mit ''Next'' bestätigen<br />[[Datei:Aws.amazon.com-06-configure_triggers1.png|200px]]<br />
## Achtung, es ist möglich, dass dabei ''Alexa Smart Home'' überhaupt nicht angeboten wird. Dann bitte ganz rechts oben in der Ecke nachsehen, welche Region bzw. welches Land ausgewählt ist. Empfohlen wird, ''Ireland'' auszuwählen. Dann erscheint bei den Funktionen auch ''Alexa Smart Home''.<br />
# Bei ''Application Id'' den Wert eintragen, dessen Ermittlung im Abschnitt [[#Skill_Id_bestimmen | Skill Id bestimmen]] beschrieben wird, den Haken bei ''Enable trigger'' setzen und mit ''Next'' bestätigen <br />[[Datei:Aws.amazon.com-06-configure_triggers3.png|200px]]<br />
# Auf der Konfigurationsseite eingeben:<br />
## ''Name'' -> ''FHEM''<br />
## ''Runtime'' -> Node.js 4.3. <br />
## ''Role'' -> ''Choose an existing role'' <br />
### Achtung: wenn es noch keine existing role gibt, zuerst ''Create a custom role'' -> in dem Popup dann ''lambda_basic_execution'' auswählen und auf ''Allow'' klicken sowie bei ''Existing role'' dann ''x'' wählen.<br />
# Auf der Code-Seite wird bzw. im großen Textfeld ist dann der Code aus der Datei ''lambda.js'' im Paket [[#Alexa-Fhem_installieren | Alexa-Fhem]] vollständig einzufügen. Dabei muss noch der Hostname im Quellcode an den eigenen Hostnamen angepasst werden. <br />
# Anschließend alles mit ''Next'' bestätigen.<br />[[Datei:Aws.amazon.com-07-configure_function.png|200px]]<br />
# Auf der Übersichtsseite dann ''Create function'' anklicken<br />[[Datei:Aws.amazon.com-08-review.png|200px]]<br />
<br />
==== Trigger für Custom Skill hinzufügen ====<br />
Editiert man eine Lambda-Funktion, werden auf der Seite ''Triggers'' diejenigen Dienste angezeigt, die diese Funktion aufrufen.<br />
* Hier taucht der Trigger ''Alexa Smart Home'' zusammen mit der ''Application Id'' auf, der bei der Einrichtung des SmartHome-Skills eingetragen wurde.<br />
* Zur Verbindung mit dem Custom Skill ist es nötig, einen zweiten Trigger hinzuzufügen. Durch Anklicken von ''Add Trigger'' wird eine Auswahlseite eingeblendet. Im neuen Fenster dann auf den gestrichelten Kasten klicken und ''Alexa Skills Kit' auswählen und mit ''Next'' bestätigen<br />
<br />
==== ARN der AWS Lambda Funktion bestimmen ====<br />
# Auf der Übersichtsseite oben links den Menüpunkt ''Functions'' aúswählen<br />[[Datei:Aws.amazon.com-09-go_overview.png|200px]]<br />
# Anschließend den Radiobutton der angelegten Funktion ''FHEM'' markieren und im Menü ''Action'' den Punkt ''Show ARN'' auswählen<br />[[Datei:Aws.amazon.com-10-1-show_arn.png|200px]]<br />
# Es wird nun eine ARN Adresse angezeigt, die für den Abschnitt [[#SmartHome_Skill_anlegen| SmartHome Skill anlegen]] benötigt wird<br />[[Datei:Aws.amazon.com-10-2-arn.png|200px]]<br />
<br />
=== Absichern des Zugriffs ===<br />
Natürlich muss der Zugriff auf den von Alexa-Fhem verwendeten Port (default: 3000, Bestandteil des Codes in der AWS Lambda-Funktion) durch die Firewall freigeschaltet werden (auf einer FritzBox unter "Portfreigaben").<br />
<br />
==== Absicherung direkt in Alexa-FHEM ====<br />
Die Kommunikation zwischen Amazon AWS und Alexa-FHEM ist auf die folgenden Arten gesichert:<br />
* Die Verbindung erfolgt per HTTPS<br />
* Es werden nur Verbindung angenommen auf denen ein gültiges Alexa-Event gesendet wird. <br />
* Es werden nur Verbindungen angenommen die ein gültiges und noch nicht abgelaufenes OAuth-Token enthalten. Jedes neue Token wird live bei Amazon auf Gültigkeit geprüft. <br />
* Es werden nur Verbindungen mit lokal konfigurierter Skill-ID angenommen.<br />
* Es ist nicht möglich von außen beliebige FHEM Kommandos zu senden. Die FHEM Kommandos werden nur lokal erzeugt.<br />
<br />
Wer möchte kann Alexa-FHEM natürlich noch weiter absichern. Es gilt aber, dass nicht jedes zusätzliche Glied in der Kette die Sicherheit sondern unter Umständen nur die Angriffsfläche erhöht. Ein falsch konfigurierter und nach aussen offener Apache (oder anderer ReverseProxy) ist unter Umständen ein größeres Risiko als Alexa-FHEM alleine.<br />
<br />
==== Absicherung per ReverseProxy ====<br />
<s>Die Kommunikation zwischen Amazon und FHEM ist wegen der Verwendung von SSL schon verschlüsselt - prinzipiell kann aber jeder von außen mit Alexa-Fhem kommunizieren. Man sollte sich deshalb im Klaren darüber sein, dass dies eine Sicherheitslücke darstellt:</s> Jeder offene Port verleitet zu Angriffen, und mit zunehmender Verbreitung von Alexa steigt auch das Risiko. Es wird deshalb empfohlen, vor den eigentlichen Alexa-Server zur Absicherung einen Apache-Webserver als ReverseProxy zu setzen. Nicht nur ist der Apache eine hervorragend stabile und seit Jahrzehnten getestete Software, sondern die Konfiguration als ReverseProxy erlaubt auch, den Zugriff auf den Alexa-Fhem-Rechner auf die Amazon-Maschinen zu beschränken.<br />
<br />
'''Achtung: Dies ist keine allgemeine Anleitung in Sachen Computersicherheit.''' Im Folgenden gehen wir davon aus, dass <br />
* Grundbegriffe wie Firewall, IP-Ports, SSL und Dynamic DNS vertraut sind<br />
* Ein Apache Webserver (idealerweise auf einer zweiten Maschine) bereits installiert ist und die Konfiguration verstanden wurde (wenn nicht: Es gibt im Netz ''tausende'' von Anleitungen dafür...)<br />
* Ein Servername von einem DynDNS-Anbieter - sagen wir ''myhome.is-my-castle.com'' - bereits von ''außen'' auf unser SmartHome zeigt.<br />
* Alexa-Fhem in einer der oben beschriebenen Basiskonfigurationen läuft, d.h. der Zugriff auf <code>https://myhome.is-my-castle.com:3000</code> ergibt, wie im Punkt [[#Alexa-Fhem_testen|Alexa-Fhem testen]] beschrieben, eine Antwort des Node.js Servers.<br />
<br />
Als erster Schritt zur Absicherung muss das ReverseProxy Modul für den Apache installiert und mit <code>a2enmod</code> aktiviert werden, hierzu sei auf [https://www.digitalocean.com/community/tutorials/how-to-use-apache-http-server-as-reverse-proxy-using-mod_proxy-extension diese Anleitung] verwiesen. Der zweite Schritt besteht darin, den SSL-Zugriff durch ein Passwort abzusichern. Dazu wird auf dem Apache-Rechner das Programm <br />
htpasswd <passwdfile> <username><br />
ausgeführt, das Programm fragt dann nach dem gewünschten Passwort. Wir nehmen im Folgenden an, dass das Passwortfile ''/etc/apache2/htpasswd'' ist, der gesetzte Username ''alexa'' lautet und das Passwort ''my_smarthome'' ist.<br />
<br />
Im dritten Schritt wird nun in das Apache-Konfigurationsfile die Weiterleitung auf den eigentlichen Alexa-Fhem-Rechner eingetragen. Dazu wählen wir, dass von außen der Standard-SSL-Port 443 benutzt werden soll, sowie als Verzeichnisname ''/alexa''. '''Achtung:''' Dieser Code soll '''nicht''' in die Default-Konfiguration des Apache-Webservers. Sondern in eine separate Datei (Dateiname z.B. "fhem"), die ins Unterverzeichnis /etc/apache2/conf.d gestellt wird.<br />
<br />
<VirtualHost *:443><br />
ServerName myhome.is-my-castle.com<br />
SSLEngine on<br />
SSLProxyEngine on<br />
SSLProxyCheckPeerCN off<br />
SSLProxyCheckPeerName off<br />
SSLCertificateKeyFile /etc/apache2/mycert/server.key<br />
SSLCertificateFile /etc/apache2/mycert/server.crt<br />
<Location /alexa><br />
AuthType Basic<br />
AuthName "Authentication Required"<br />
AuthUserFile "/etc/apache2/htpasswd"<br />
Require valid-user<br />
ProxyPass https://<hier IP-Adresse des Alexa-Fhem-Rechners>:3000/<br />
ProxyPassReverse https://<hier IP-Adresse des Alexa-Fhem-Rechners>:3000/<br />
Order deny,allow<br />
Allow from All<br />
</Location><br />
(... Hier eventuell weitere Umleitungen)<br />
</VirtualHost><br />
Nach einem Neustart des Apache-Servers, dem Schließen des Ports 3000 in der Firewall sowie dem Öffnen des Ports 443 ist der Alexa-Fhem-Rechner von außen nur noch erreichbar durch den Aufruf von <code>https://myhome.is-my-castle.com/alexa</code> und verlangt unmittelbar die Eingabe von Username und Passwort.<br />
<br />
Der vierte Schritt ist nun, den Code der AWS Lambda-Funktion an fünf Stellen zu verändern<br />
'''const PORT=443;'''<br />
const HOST='myhome.is-my-castle.com';<br />
'''const PATH='/alexa';'''<br />
'''const AUTH='alexa:my_smarthome';'''<br />
// entry<br />
exports.handler = function(event, context, callback) {<br />
console.log(`EVENT: ${event}`);<br />
console.log(`CONTEXT: ${context}`); <br />
var post_data = JSON.stringify(event);<br />
var options = {<br />
hostname: HOST,<br />
port: PORT,<br />
//family: 6,<br />
'''path: PATH,'''<br />
method: 'POST',<br />
'''auth: AUTH,'''<br />
rejectUnauthorized: false, // accept self-signed<br />
(etc., Rest des Codes wie gehabt)<br />
Natürlich muss der Zugriff getestet werden. Bei Beachtung aller dieser Schritte werden alle un-autorisierten Zugriffe von außen abgewehrt. Eine noch weiter gehende Sicherung ist möglich, dazu kann in der Serverkonfiguration der Zugriff auf die Amazon-Domains beschränkt werden. Das ganze Alexa-System ist aber noch in konstanter Weiterentwicklung, diese Domain-Namen können sich also noch ändern.<br />
<br />
== Einrichtung in der Alexa App==<br />
Nachdem die Alexa Skills angelegt wurden, müssen diese noch in der Alexa App eingerichtet werden.<br />
Dafür jeweils per Desktop-Browser auf [http://alexa.amazon.de alexa.amazon.de] anmelden, nicht die App unter iOS oder Android verwenden. Diese hat Probleme mit der OAuth Verknüpfung.<br />
<br />
=== Alexa Skill ===<br />
# Auf ''Skills'' klicken<br />[[Datei:Alexa.amazon.de-01-startseite.png|200px]]<br />
# Oben rechts ''Meine Skills'' bzw. ''Ihre Skills'' auswählen<br />[[Datei:Alexa.amazon.de-03-meine_skills.png|200px]]<br />
# In der Liste der Skills sollte das angelegte FHEM Skill angezeigt werden. Dieses anklicken<br />[[Datei:Alexa.amazon.de-02-liste_skills.png|200px]]<br />
# Oben Rechts in den Details des Skills auf ''Skill aktivieren'' klicken<br />[[Datei:Alexa.amazon.de-04-skill_details.png|200px]]<br />
# In dem neu geöffneten Fenster die Autorisierung bestätigen<br />[[Datei:Alexa.amazon.de-05-amazon_auth.png|200px]]<br />
# Anschließend sollte die Verbindung erfolgreich aufgebaut worden sein <br />[[Datei:Alexa.amazon.de-06-success.png|200px]]<br />
<br />
=== Geräte ===<br />
# Auf http://alexa.amazon.de anmelden<br />
# Auf ''Smart Home'' klicken<br />[[Datei:Alexa.amazon.de-01-startseite.png|200px]]<br />
# Anschließend den Punkt ''Geräte suchen'' anklicken<br />[[Datei:Alexa.amazon.de-07-Gerätesuche.png|200px]]<br />
# Wurde soweit alles korrekt eingerichtet, werden nun die gefundenen Geräte angezeigt.<br />
<br />
Tip: Es macht Sinn, unter ''Meine Gruppen'' Gruppen benannt nach den Räumen einzurichten. Hierdurch kann Alexa die Geräte besser auseinander halten, vor allem wenn die den gleichen Alias (z.B. "Licht") haben.<br />
<br />
== Einrichtung unter FHEM ==<br />
Im Folgenden werden exemplarisch ein paar Geräte beschrieben, die man nutzbringend mit FHEM einsetzen kann.<br />
<br />
Bei Verwendung des Custom Skills übersetzt die Kombination der Attribute ''alexaMapping'' und ''homebridgeMapping'' Sprachbefehle ("Intents") in gerätespezifische Kommandos. <br />
* Das Attribut alexaMapping wird am Alexa-Device gesetzt und dient dazu, erkannte Sprachkommandos in abstrakte Characteristiken zu überführen. Für den einfacheren SmartHome Skill hat darum das Attribut ''alexaMapping'' keine Bedeutung, sondern nur der ''genericDeviceType'' des zu steuernden Gerätes.<br />
* Das Attribut homebridgeMapping wird für beide Skills am zu steuernden Gerät gesetzt und übersetzt diese Charakteristiken in die konkreten Befehle, die das Gerät versteht. Der inhalt des Attributs wird von links nach rechts ausgewertet und ist wie folgt aufgebaut:<br />
** Das Attribut enthält eine durch Leerzeichen getrennte Liste aus Konfigurationen für jeweils eine Characteristik<br />
** Jede einzelne der Characteristik-Konfigurationen besteht aus dem Namen der Characteristik, gefolgt von "=" und einer kommaseparierten Liste von Parametern.<br />
attr <device> homebridgeMapping <Characteristic1>=<param1.1>,<param1.2>,... <Characteristic2>=<param2.1>,<param2.2>,...<br />
** Jeder Parameter besteht entweder aus<br />
*** <code><cmd>:<device>:<reading></code>, hier können nicht verwendete Elemente von links nach rechts weg gelassen werden.<br />
*** <code><name>=<value></code>, hier kann <code><value></code> entweder ein Wert oder semikolonseparierte Liste sein.<br />
*** Oder dem schlüsselwort <code>clear</code>, welches alle vorhandenen (default) Parameter dieser Characteristik löscht. <code>clear</code> kann auch an Stelle einer ganzen Characteristik-Konfiguration stehen<br />
Weiter führende Dokumentation zum homebridgeMapping findet sich unter https://forum.fhem.de/index.php/topic,48558.0.html<br />
<br />
=== Einfacher Schalter ===<br />
* Ein einfacher Schalter, der die set-Kommandos ''on'' und ''off'' kennt, kann direkt mit Alexa-Fhem gekoppelt werden <br />
* Für kompliziertere Aktionen, etwa das Übermitteln eines spezifischen Schaltbefehls an FHEM, ist die Einrichtung eines Dummies zu empfehlen. <br />
Ob Dummy oder nicht, wichtig sind die drei fett gedruckten Zeilen<br />
define Alexa.Party dummy<br />
'''attr Alexa.Party alexaName party'''<br />
'''attr Alexa.Party alexaRoom alexaroom'''<br />
'''attr Alexa.Party genericDeviceType switch'''<br />
attr Alexa.Party group AlexaGeräte<br />
attr Alexa.Party room AlexaRoom<br />
'''attr Alexa.Party setList on off'''<br />
Selbstverständlich kann man diesen Dummy mit einem notify oder DOIF abfangen, um die gewünschte Schaltaktion auszuführen. <br />
<br />
Ein Alternative zum Dummy ist das Anlegen eines readingsProxy, dem die entsprechenden Attribute gegeben werden.<br />
<br />
Weil es sich hierbei um eines der einfachen Geräte handelt, die Alexa selbst im SmartHome Skill bearbeiten kann, ist auch der zweite Schritt bei der Einrichtung in der Alexa App sinnvoll: Der Schalter wird dann im Bereich Smart Home der Alexa App erkannt. Wer ihn auch mit dem Custon Skill bedienen möchte, muss natürlich Sorge tragen, dass der Alexa-Name ''party'' bei den FHEM_Devices auftaucht und die entsprechenden weiteren Slot Types und Example Utterances in der Konfiguration des Custom Skills vorhanden sind (siehe Abschnitt [[##Custom_Skill_anlegen | Custom Skill Anlegen]]).<br />
<br />
=== Wecker ===<br />
Dieses Gerät kann man nur mit dem Custom Skill bedienen, es wird also '''nicht''' im Bereich Smart Home der Alexa App auftauchen. Wir richten einen Dummy ein, wichtig sind wieder die fett gedruckten Zeilen:<br />
define Alexa.Weckzeit dummy<br />
'''attr Alexa.Weckzeit alexaName weckzeit'''<br />
'''attr Alexa.Weckzeit alexaRoom alexaroom'''<br />
attr Alexa.Weckzeit genericDeviceType clock<br />
attr Alexa.Weckzeit group AlexaGeräte<br />
'''attr Alexa.Weckzeit homebridgeMapping Weckzeit=state,cmd=+'''<br />
attr Alexa.Weckzeit room AlexaRoom<br />
'''attr Alexa.Weckzeit setList Weckzeit:time'''<br />
Das Attribut ''genericDeviceTye'' ist nicht wichtig, weil es ein generisches Device dieser Art gar nicht gibt. Wichtig hingegen ist das Attribut ''homebridgeMapping'' <br />
<br />
Für das Gerät ''MyAlexa'', das in Abschnitt definiert wurde, muss im Attribut ''alexaMapping'' auftauchen<br />
Weckzeit=verb=stelle,valuePrefix=für;auf,values=AMAZON.TIME,valueSuffix=uhr<br />
Darüber hinaus muss der Alexa-Name ''weckzeit'' bei den FHEM_Devices auftauchen und die entsprechenden weiteren Slot Types und Example Utterances in der Konfiguration des Custom Skills vorhanden sein (siehe Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]]).<br />
<br />
Der Aufruf dieses Gerätes mit Alexa erfolgt dann z.B. mit den Sätzen<br />
<pre style="width:50%;"><br />
"Alexa, sage <Custom Skill Invocation Name>: Stelle Weckzeit auf Neunzehn Uhr Siebenundzwanzig"<br />
"Alexa, frage <Custom Skill Invocation Name> nach dem Status von Weckzeit"<br />
</pre><br />
Dabei ist natürlich der ''Custom Skill Invocation Name'' durch den Wert zu ersetzen, den man im Abschnitt [[#Custom_Skill_anlegen | Custom Skill Anlegen]] unter Punkt 2 eingetragen hat.<br />
<br />
Zur weiteren Bearbeitung kann man jetzt mit einem DOIF Statusänderungen des Dummies abfangen und durch eine kleine Helperfunktion ins "echte" FHEM weiterleiten.<br />
define Alexa.Weckzeit.N DOIF (["Alexa.Weckzeit:.*"])({AlexaHelper("Alexa.Weckzeit","$EVENT")}) <br />
Die Helperfunktion (z.B. in 99_myUtils.pm) stellt aus der übergebenen Zeit (immer im Format dd:mm) eine sprachkompatible Nachricht $nc und einen mit den FHEM-Zeitangaben kompatiblen String $nt zusammen und reicht beide an eine Routine ''changeWakeTime'' weiter (dokumentiert in den [https://www.dpunkt.de/buecher/12387/9783960090120-smarthome-hacks.html Smart Home Hacks]).<br />
sub AlexaHelper($$){<br />
my ($name,$event)=@_;<br />
if( $name eq "Alexa.Weckzeit" ){ <br />
my ($nc,$nt);<br />
#-- volle Stunde----------------------------------------<br />
if( $event =~ /(\d+):00/ ){<br />
$nc=sprintf("%d Uhr",$1);<br />
$nt=sprintf("%02d:00:00",$1);<br />
#-- nicht volle Stunde---------------------------------<br />
}elsif( $event =~ /(\d+):(\d+)/ ){<br />
$nc=sprintf("%d Uhr %d",$1,$2);<br />
$nt=sprintf("%02d:%02d:00",$1,$2);<br />
}<br />
changeWakeTime(\'GalaxyTab.EG\',\'$nc\',\'$nt\');<br />
}<br />
}<br />
<br />
<hr><br />
<br />
=== Lichtszene ===<br />
Eine Lichtszene wird mit dem Modul LightScene angelegt. Wir gehen davon aus, dass in der Lichtszene die beiden Szenen Alle_An und Alle_Aus, sowie mindestens eine weitere Szene (hier: Sitzgruppe) definiert wurde.<br />
* Nachfolgend wird ein Beispiel beschrieben, wie man eine Lichtszene mit dem einfachen SmartHome Skill steuern kann. Die verwendeten Kommandos sind dann<br />
<pre><br />
"Alexa, schalte (die) Beleuchtung an" -> LightScene Alle_An wird ausgewählt<br />
"Alexa, schalte (die) Beleuchtungsitzgruppe an" -> LightScene Sitzgruppe wird ausgewählt<br />
...<br />
"Alexa, schalte (die) Beleuchtung aus" -> LightScene Alle_Aus wird ausgewählt<br />
</pre><br />
* Künftig wird man LightScene mit dem Custom Skill eventuell direkt steuern können - allerdings hat das einen geringeren WAF, als die Steuerung über den SmartHome Skill: Der Einschaltsatz muss dann mindestens lauten<br />
<pre><br />
"Alexa, sage <Custom Skill Invocation Name>: schalte (die) Beleuchtung an" -> LightScene Alle_An wird ausgewählt<br />
</pre><br />
Dafür wird es aber auch möglich sein direkt die SzenenNamen im gesprochenen Kommando zu verwenden und so auf die Umwege über dummys und ähnliches zu verzichten.<br />
<br />
<br />
Im ersten Schritt wird ein Dummy für die Gesamtbeleuchtung eingerichtet:<br />
define Alexa.Beleuchtung dummy <br />
attr Beleuchtung setList on off<br />
'''attr Alexa.Beleuchtung alexaName beleuchtung'''<br />
'''attr Alexa.Beleuchtung alexaRoom alexaroom'''<br />
'''attr Alexa.Beleuchtung genericDeviceType switch'''<br />
Anschließend wird für jede vorhandene Lichtszene (außer Alle_An und Alle_Aus) ein weiterer Dummy angelegt:<br />
define Alexa.Beleuchtung.Sitzgruppe dummy <br />
attr Beleuchtung setList on off<br />
'''attr Alexa.Beleuchtung.Sitzgruppe alexaName beleuchtungsitzgruppe'''<br />
'''attr Alexa.Beleuchtung.Sitzgruppe alexaRoom alexaroom'''<br />
'''attr Alexa.Beleuchtung.Sitzgruppe genericDeviceType switch''' <br />
Die eigentliche Steuerung übernimmt dann ein DOIF<br />
define Alexa.Beleuchtung.N DOIF<br />
(["Alexa.Beleuchtung.Sitzgruppe:on"])<br />
(set <devicename der Lichtszene> scene Sitzgruppe,<br />
set Alexa.Beleuchtung off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
DOELSIF<br />
... <weitere on-Events der anderen Szenen werden abgefangen><br />
DOELSEIF<br />
(["Alexa.Beleuchtung:on"])<br />
(set <devicename der Lichtszene> scene Alle_An,<br />
set Alexa.Beleuchtung.Sitzgruppe off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
DOELSEIF<br />
(["Alexa.Beleuchtung:off"])<br />
(set <devicename der Lichtszene> scene Alle_Aus,<br />
set Alexa.Beleuchtung.Sitzgruppe off,<br />
...<weitere dummies der anderen Szenen werden ebenfalls ausgeschaltet><br />
)<br />
Mit diesem DOIF wird ein Radiobutton simuliert, d.h. wie bei den Stationstasten vor Uralt-Radios sorgt die Auswahl einer Szene immer dafür, dass alle anderen Dummies ausgeschaltet werden.<br />
Natürlich kann man das auch mit einem kleinen Perl-Programm erreichen.<br />
<br />
<br />
Zwei andere Ansätze Lichtszenen zu schalten die ohne DOIF auskommen sind im Folgenden beschrieben:<br />
<br />
* Wenn es von Interesse ist die Steuerung mit einer Darstellung in FTUI zu verbinden: Statt der oben beschriebenen dummy Devices kann man readingsProxy Devices mit passenden setFn und valueFn analog zum [[Harmony#Button_f.C3.BCr_eine_bestimmte_Activity_im_Frontend_und_Homekit_.C3.BCber_readingsProxy|diesem Beispiel für harmony aktivitäten]] verwenden.<br />
<br />
* Für jede zu schaltende Szene wird ein dummy angelegt dessen homebridgeMapping direkt auf das LightScene Device zeigt:<br />
<br />
define <dummy> dummy<br />
attr <dummy> setList on off<br />
attr <dummy> genericDeviceType switch<br />
attr <dummy> homebridgeMapping On=<light scene>::state,valueOn=<szene>,cmdOn=scene+<szene>,cmdOff=scene+<szene aus><br />
<br />
Bei der zweiten Variante wird davon ausgegangen das der aktuelle status nicht abgefragt oder angezeigt werden soll. Deshalb gibt es keine direkte RadioButton Funktionalität.<br />
<br />
== Nutzung ==<br />
Um den Namen zu bestimmen, unter dem ein Gerät mit Alexa angesprochen wird, verwendet Alexa-Fhem mit absteigender Priorität:<br />
* das alexaName Attribut<br />
* das alias Attribut<br />
* das NAME Internal<br />
Damit Alexa ein Gerät eindeutig identifizieren kann, sollten eindeutige Gerätenamen verwendet werden, bestehed möglichst aus einem Wort und ohne Ziffern. Wenn Alexa einen Namen nicht versteht, kann man unter [http://alexa.amazon.de/spa/index.html] nachsehen was tatsächlich verstanden wurde und den Gerätenamen ggf. anpassen.<br />
<br />
=== SmartHome Skill ===<br />
Gruppen (Räume) müssen in der Alexa App konfiguriert werden. Über das API lassen sich nur der Name und die Schalteigenschaften übergeben.<br />
<br />
Nach erfolgreicher Einrichtung des SmartHome Skills sollte Alexa mit den folgenden Befehlen nutzbar sein:<br />
<pre style="width:50%;"><br />
“alexa, schalte <gerät/gruppe> ein”<br />
“alexa, schalte <gerät/gruppe> aus”<br />
“alexa, stelle <gerät/gruppe> auf <wert> prozent”<br />
“alexa, stelle <gerät/gruppe> auf <anzahl> grad”<br />
“alexa, erhöhe <gerät/gruppe> um <anzahl> prozent”<br />
“alexa, reduziere <gerät/gruppe> um <anzahl> prozent”<br />
“alexa, erhöhe <gerät/gruppe> um <anzahl> grad”<br />
“alexa, reduziere <gerät/gruppe> um <anzahl> grad”<br />
</pre><br />
<br />
=== Custom Skill ===<br />
Der Custom Skill erlaubt im Gegensatz zum SmartHome Skill eine weitreichende Konfiguration der möglichen Kommandos.<br />
<br />
Das Prinzip der Kommandokonfiguration ist {{Link2Forum|Topic=60244|Message=532513|LinkText=im Forum}} beschrieben.<br />
<br />
TODO: Abfragen, Attribute (alexaMapping, alexaTypes, fhemIntents, articles, prepositions)<br />
<br />
== Troubleshooting ==<br />
<br />
====Allgemeiner Hinweis====<br />
Besonders wichtig ist, dass man sich sehr genau an diese Anleitung hält. Ein häufiger Fehler ist, dass die einfachen Anführungszeichen in der Anleitung unter '''AWS Lambda Funktion anlegen''' Punkt 8 einfach weggelassen werden. Diese sind zwingend notwendig. Es darf auch nur der reine Hostname eingetragen werden. Also kein ''http://'' davor. Entweder eine feste IP Adresse oder den Hostnamen, um den Rechner zu erreichen, den ihr über den Port 3000 freigegeben habt. Das sollte dann so aussehen:<br />
<pre style="width:50%;"><br />
const PORT=3000;<br />
const HOST='mein.host.name';<br />
</pre><br />
<br />
====Freigabe von Port 3000====<br />
{{Randnotiz|RNTyp=Fehl|RNText=Derzeit müsst ihr über einen echten IPv4 Anschluss verfügen, damit der Amazon Lambda-Server euch erreichen kann. DS-Lite Anschlüsse wie die von <b>UnityMedia</b> z.B. funktionieren derzeit leider nicht. Eine möglicher "Workaround" wird hier beschrieben: https://forum.fhem.de/index.php/topic,60244.msg518276.html#msg518276}}<br />
<br />
Auf dem Router muss der Port 3000 Protokoll TCP freigegeben werden. D.h. von außen muss man wenn man den Port 3000 aufruft, auf dem intern laufenden node.js Alexa-Dienst zugreifen können.<br />
Je nach Router gestaltet sich das Portforwarding bzw. die Portumleitung etwas schwieriger.<br />
<br />
Bei einem Speedport Router der Telekom beispielsweise, muss der Router komplett neu gestartet werden, wenn die Portfreigabe eingerichtet wurde. <br />
<br />
Bei der Fritz!Box ist das nicht nötig, bei dieser finden die Freigabe unter ''Internet -> Freigaben -> Portfreigaben'' statt. Dort wählt man dann den Rechner aus und richtet eine neue Freigabe ein. Wichtig hierbei ist, dass man Portfreigabe auswählt und nicht MyFRITZ!-Freigabe. Bei Port von bis trägt man 3000 ein, bei Port extern ebenfalls.<br />
<br />
Um die Portweiterleitung zu testen, solltet ihr euch auch nicht im gleichen Netz befinden. Viele Router blockieren den Netzaufruf aus dem gleichen Netz. Am besten testet ihr es, wenn ihr an eurem Mobiltelefon W-LAN deaktiviert und im Browser folgende Seite aufruft: ''https://mein.hostname:3000''. Wenn ihr im Browser dann einen Quellcode von Alexa seht, funktioniert die Portumleitung.<br />
<br />
Wenn bis hier alles funktioniert und es läuft dennoch nicht rund, liegt das Problem woanders. Kommt z.B. bei der Gerätesuche kein Request rein (sichtbar auf dem Bildschirm, wenn bin/alexa gestartet wurden), kann evtl. der Lambda-Dienst falsch konfiguriert sein.<br />
<br />
====Probleme mit node.js - npm install====<br />
<br />
Falls eine Fehlermeldung auftritt, dass "npm" nicht gefunden werden kann, bitte NodeJS entsprechend der Anleitung im Homebridge-Artikel vorgehen: [[Homebridge_einrichten#NodeJS_installieren|NodeJS installieren]] sowie [[Homebridge_einrichten#Python.2C_g.2B.2B.2C_MDNS_installieren|Python, g++, MDNS installieren]], siehe auch folgenden Abschnitt.<br />
<br />
====Es kommen diverse Fehlermeldungen beim Starten von alexa-fhem und es beendet sich====<br />
Wenn man auf der Konsole angemeldet ist, den Befehl<syntaxhighlight lang="bash" style="width:50%;">node -v</syntaxhighlight>eingeben. Ist die Version niedriger als die geforderte 0.12, muss eine neuere installiert werden. Hier darf man dann im Wiki unter [[Homebridge_einrichten#NodeJS_installieren]] nachschauen. NodeJS V4 sollte hierbei schon ausreichen. Solange die node.js Version nicht passt, gar nicht groß rum experimentieren! Bitte beachtet, dass alle Voraussetzungen unter [[Alexa-Fhem#Voraussetzungen]] erfüllt sind! Keine Experimente mit Versionen die darunter liegen.<br />
<br />
====Fehlermeldung ''NAT-PMP failed: Error: timeout'' Fehler angezeigt beim Start von alexa-fhem====<br />
Wenn ihr dann alexa-fhem über die Konsole startet und bekommt folgenden Fehler: ''NAT-PMP failed: Error: timeout'', lasst euch davon nicht irritieren. Das bedeutet lediglich, dass der Port nicht automatich freigegeben wurde über uPNP. Alternativ prüft, ob die Funktion der Portfreigabe via uPNP auf eurem Router aktiviert ist.<br />
<br />
====Nach Start auf der Console beendet sich Alexa-FHEM sofort wieder====<br />
Unmittelbar nach dem Start von Alexa-FHEM werden ein paar UPNP Fehlermeldungen ausgegeben. Unmittelbar danach beendet sich Alexa-FHEM wieder. <br />
<br />
Viele scheinen ein Problem mit UPNP auf dem Raspberry Pi zu haben. Wenn dieses Problem auftritt einfach in der <code>~/.alexa/config.json</code> die folgenden Zeilen rauslöschen:<br />
<br />
<pre><br />
"nat-pmp": "10.0.1.1",<br />
"nat-upnp": true,<br />
</pre><br />
<br />
Jetzt erneut Alexa-FHEM starten. Sollte nun laufen.<br />
<br />
====Was ist zu tun, wenn alexa-fhem keine Geräte findet?====<br />
Zunächst müssen die Geräte, die angesprochen werden wollen, unter FHEM ein neues Attribut zugewiesen bekommen. Dazu das Gerät in FHEM öffnen und das Attribut ''genericDeviceType switch'' hinzufügen, wenn es ein Schalter mit der Funktiona AN/AUS sein soll. Wenn man will, kann man dem Gerät jetzt noch über das Attribut ''alias'' eine besseren Namen geben, mit dem Alexa das Gerät dann auch finden kann.<br />
Anschließend muss alexa-fhem neu gestartet werden und die definierten Geräte sollten nun gefunden werden.<br />
<br />
====Was ist zu tun, wenn Alexa zwar Geräte findet, diese aber nicht angesprochen werden können?====<br />
Zuerst die Informationen zum Datenfluss ganz oben ansehen. Dann am besten von hinten nach vorne vorgehen:<br />
* wenn nichts bei alexa-fhem ankommt: port forwarding prüfen<br />
* wenn lambda.js nichts los wird: im cloudwatch log nachsehen<br />
* wenn bei lambda.js nichts ankommt: den trigger prüfen<br />
<br />
<br />
Zunächst sollte man sich unter ''http://aws.amazon.com'' das Logfile seiner erstellten Funktion anschauen. Ist überhaupt ein Logfile vorhanden? Falls nicht, liegt es vermutlich am Trigger.<br />
Den solltet ihr überprüfen. Scheinbar kommt es hin und wieder vor, dass dieser nicht gesetzt ist. Dazu einfach auf ''Triggers'' klicken und mit ''Add trigger'' erneut einen anlegen. Hier muss, wie in der Anleitung unter '''AWS Lambda Funktion anlegen''' Punkt 7, die ''Application Id'' stehen und der Haken bei ''Enable trigger'' gesetzt sein. Dann alexa-fhem neu starten.<br />
Wenn ihr Änderugen gemacht habt und den alexa-fhem Dienst noch nicht neu gestartet habt, wäre jetzt der richtige Zeitpunkt.<br />
<br />
====Was ist zu tun, wenn sich der Alexa-Service nicht starten lässt?====<br />
Schaut bitte in das Unterverzeichnis [alexa-fhem (also dort, wo Ihr Alexa-FHEM instelliert habt]/bin. Die dort befindliche Datei ''alexa'' muss ausführbar sein. Also z.B. so:<br />
<syntaxhighlight lang="bash" style="width:70%;">2755327 4 -rwxr-xr-x 1 pi pi 339 Nov 26 23:20 alexa</syntaxhighlight><br />
Sollte dies nicht der Fall sein bitte mit:<br />
<syntaxhighlight lang="bash" style="width:70%;">chmod +x alexa</syntaxhighlight><br />
die Datei ausführbar machen. Sofern der User "pi" Eigentümer ist, ist kein sudo erforderlich.<br />
<br />
<br />
====Wie kann ich via Alexa-FHEM auf FHEM zugreifen, wenn der Port mit Benutzername/Kennwort geschützt ist?====<br />
<br />
Hierzu muss die Datei <code>~/.alexa/config.json</code> geöffnet werden und der Abschnitt "connections" um folgende Zeile ergänzt werden:<pre><br />
"auth": {"user": "fhem", "pass": "fhempassword"},</pre><br />
Bei Verwendung von SSL bei FHEM muss auch noch <pre><br />
"ssl": true,</pre> hinzugefügt werden<br />
<br />
[[Kategorie:HOWTOS]]<br />
[[Kategorie:Sprachsteuerung]]</div>Amenomade