Angefangen hat alles mit einer "smarten" Steckdose.
Dann habe ich im Internet den FHEM-Server entdeckt...
Allgemeines
-
Allgemeines:
Was ist FHEM?
"FHEM ist ein in perl geschriebener, GPL lizensierter Server für die Heimautomatisierung."
Um es kurz zu machen: FHEM ist großartig ! Der Server läuft auf verschiedensten Geräten:
auf Windows, Linux, Raspberry Pi und anderen Kleinstrechnern - sogar auf NAS-Platten.
FHEM schafft das, was die Industrie mal wieder nicht hinbekommt: es vereint unendlich
viele Protokolle in einem System. Der Panasonic-TV kann mit dem Homematic-Rolladenaktor
agieren (wenn TV an, dann Rolladen herunterfahren),
die Philips-Hue-Lampe mit der Sonos-Box, der Logitech-Harmony-Hub mit dem Enigma-Receiver.
Und so weiter und so weiter...
Es ist ein klein wenig Hirnschmalz gefordert, bevor man irgendetwas zum Laufen bekommt,
man muß aber durchaus keine Atome spalten können, um Automatisierungen zu realisieren.
FHEM ist sehr gut dokumentiert und im FHEM-Forum trifft man auf nette User, die einen gerne unterstützen.
Ich kenne mich weder mit Perl noch mit JAVA aus und habe mir alles in oben genannten Forum angelesen.
Hier mein bisheriger "Output":
Fhem läuft bei mir auf einem Intel NUC i5 mit Linux Mint..
Eine sehr gute Beschreibung wie man FHEM auf einem Gerät installiert und wie man z.B. Verbindung zu Homematic-Komponenten schafft findet sich hier:
http://www.meintechblog.de/2013/05/fhem-server-auf-dem-raspberry-pi-in-einer-stunde-einrichten/
Mit dieser Beschreibung habe ich angefangen.
Mit der standard-FHEM-Oberfläche kann man eigentlich schon alles steuern.
Es geht allerdings noch schöner, denn es gibt viele unterschiedliche Frontends für fhem, Da sollte für jeden Geschmack und jede Anwendung etwas dabei sein. Es kommt halt drauf an, was man steuern möchte und wo man die Steuerung visualisieren möchte (kleines Display (Handy,Tablet) oder großes (PC, TV). Ich habe mich für das frontend "Floorplan" entschieden.
Den Floorplan finde ich am flexibelsten – da es sich ja im wesentlichen um eine „html-Seite“ handelt kann man hier in relativ kurzer Zeit viele Dinge realisieren.
Ausserdem: es muß sich bei einer floorplan-Seite ja nicht unbedingt um einen Gebäude-Grundriss handeln. Alles ist möglich - von der Listendarstellung bis zur 3D-Kugel.
Ich habe mich für das Design „darkfloorplanstyle.css“ entschieden.
Die 3D-Zeichnungen habe ich mit dem Programm "SweetHome3D" erstellt.
Die Bedienung erfolgt über unsere Tablets und PCs. In der Küche (zentraler Raum) und an der Haustür habe ich jeweils ein Tablet an
die Wand gespaxt:
Android, Dolphin-Browser im Fullscreen-Modus (Achtung: "Dolphin-Jetpack" muß abgeschaltet sein, sonst verschluckt der browser einige dummys)( wundert Euch nicht über die schiefe Wand - das gehört so - wir wohnen in einer uralten Reetdachkate, hier ist nichts gerade... )
und in der Küche: Komponenten
-
Ich habe folgende Komponenten im Einsatz:
Mein FHEM läuft mittlerweile auf einem Intel NUC i5, das Aufrufen der Floorplans ist dadurch superfix.
Zusätzlich habe ich im Einsatz:
- div. Homematic-Komponenten über HM-LAN-Adapter:
Schalter, Taster, Jalousie-Aktoren,Thermostaten, Funk-Tasterschnittstellen,Funk-Fernbedienungen - Fritzbox 6840LTE mit 10x FritzDect200
- Philips-Hue Bridge, dazu 3x Lightstrip und 3x Hue Bulb
- 1x VU+ Duo2 Enigma-Sat-Receiver
- 2x Harmony-Hub zur IR-Anbindung diverser Geräte ohne LAN-Schnittstelle
- 2x Philips-TV
- 7x PI2 mit piCorePlayer als Squeezebox-Client mit Logitech Squeezebox Server auf dem NUC
- 1x E-Litro Net Heizöl-Level Erfassung
- 1x HM-Sys-sRP-Pl Selektiver Funkrepeater
Folgendes habe ich (bisher) mit fhem realisiert:
Steuerung (fast) aller Lampen, Rollos, Pumpen, Ventile, Torantrieb
Steuerung von Philips-Hue Kompontenten
Steuerung von Philips-TVs
Steuerung der Dreambox
Steuerung von Harmony Hubs
Squeezebox Multiroom
Sprachbenachrichtigung bei eingehenden emails über Squeezebox "talk"
PCs aufwecken per WOL
Anwesenheitserkennung (ping auf unsere Handys) → pushmail → Begrüssung per Sprachausgabe
Müllabfuhr-Kalender (über Google Kalender, im Floorplan werden Symbole für Mülltonne, Gelber Sack oder
Papiertonne eingeblendet wenn die Abfuhr dran ist)
http://www.fhemwiki.de/wiki/Google-Kalender_zur_Steuerung_von_Dummies
Pushmail über Debian-Sendmail zur Fernbedienung von Android-Geräten (mit Tasker)
Messung des Heizöl-Standes zuerst per Ultraschall-Sensor, jetzt per Einperl-Sonde
Ausserdem kann ich sämtliche Befehle (auch TV-Programme umschalten, usw.)
per Spracheingabe steuern und bekomme auch ein Sprachfeedback:
„Computer, schalte die Aussenbeleuchtung ein“ → „Ich habe die Aussenbeleuchtung eingeschaltet“
http://forum.fhem.de/index.php/topic,13455.0.html - div. Homematic-Komponenten über HM-LAN-Adapter:
Floorplans
-
Meine Floorplans:
Erdgeschoss
Im Erdgeschoss-Floorplan kann ich alle relevanten Lampen und Rollos schalten, die farbigen „Blumen“ zeigen den
Schaltzustand unserer „Hue Devices“ an. (readingsProxy)
Die eigentliche Steuerung der Farben der Hue-Lampen und Lightstrips findet aus Platzgründen im separaten
Floorplan „Philips Hue“ statt.
Das Wetter ist das Yahoo-Wetter mit folgenden Anpassungen:
für die horizontale Darstellung: WeatherAsHtmlH
http://forum.fhem.de/index.php?topic=25262.0
und um die Beschriftung im dunklen Floorplan besser sichtbar zu machen habe ich diese Zeile
in die darkfloorplanstyle.css eingefügt:Code: [Auswählen]table.weather { color: #ffffff; font-size: 14px;}
Auch die Steuerung der Heizungs-Thermostaten habe ich – ebenfalls aus
Platzgründen in einen separaten Floorplan geschoben. Hier habe ich zusätzlich
die entsprechenden Plots eingefügt. Die kleinen Thermostaten im Erdgeschoss-Floorplan
sind weblinks, diese leiten direkt auf den „Heizungs-Floorplan“ weiter.
Ein Klick/Touch auf die PC-Symbole weckt den entsprechenden PC per WOL, das TV-Symbol
verlinkt zum "Multimedia-Floorplan, das Lautsprechersymbol zum "Multiroom-Audio"-Floorplan.
Das Tag/Nacht-Symbol ist ein "Makro"-Dummy für Licht, TV, usw.In der Küche:
An den on/off-Button unseres Kaffeeautomatens habe ich 2 Drähte angelötet. Ein Homematic-Schalter schaltet eine Kippstufe (Conrad-Bausatz) und die betätigt bei ein/aus kurz diesen Taster.
Das „Eierbechersymbol“ löst einen 5 Minuten Timer aus – danach gibt es eine „sendmail“ mit dem Betreff „Die Eier sind fertig!“ auf alle Tablets – die dann klingeln. Gibt immer perfekte Frühstückseier...
Obergeschoss:
Das Obergeschoss u.a. hat einen Wecker (sendmail auf's Tablet – das macht dann Lärm)
und einen TV-Ausschalttimer (Harmony Hub) Aussenanlage und Bewässerung
-
Aussenanlage:
Wir haben eine kleine „Hobby-Tierhaltung“ (Esel, Schafe, Hühner).
Die Stallbeleuchtung ist natürlich integriert, ausserdem die Wasserversorgung der
Ställe über ein Gardena-Ventil und einen Homematic-Schalter:Das Gardena-Ventil benötigt 24V AC - daher der Ringkerntrafo.
Hinter dem Ventil ist eine Schaltschrankheizung montiert, diese wird bei Minus-Graden von einer
Conrad-Thermostat-Steckdose aktiviert damit das Ventil im Winter nicht einfriert.
Zusätzlich lassen sich die Aussenbeleuchtung, die Lampion-Ketten der Terrassenbeleuchtung und diverse Pumpen
(wir haben einen Bachlauf, einen Teich mit Wasserspeier und einen kleinen Wasserfall gebaut) steuern. Gartentor-Steuerung
-
Torsteuerung
Wir haben einen Motorantrieb an unser Einfahrtstor gebaut. Auch diesen habe ich in unsere
Hausautomation integriert. Ich habe einen HM-LC-SW1-FM direkt in das Gehäuse der Torelektronik montiert.
Bedient wird das ganze mit HM-RC-4-2 Handsendern.
Da wir leider genau 2m vor dem Tor keine Verbindung mehr zum HMLAN-Adapter haben
(man müsste aus dem Auto aussteigen, um das Tor zu öffnen...), habe ich den den HM-LC-SW1-FM direkt
mit einer der Tasten unserer Handsender gepeert:Code: [Auswählen]set Handsender1_4 peerChan 0 Torantrieb single
Jetzt muß die Funkverbindung also nur noch bis zum Aktor reichen.
Weil der Torantrieb einen Tastimpuls erfordert, habe ich diesen peer „getimed“:Code: [Auswählen]set Torantrieb regSet shOnTime 3 Handsender1_4
Der Aktor schaltet jetzt für 3 Sekunden an und dann wieder aus. Der Tasttkontakt für das Tor muß potentialfrei sein,
ich habe also zusätzlich ein 230V-Relais hinter den Aktor gehängt.
Wie schon erwähnt: wir haben eine kleine Herde von „Rasen-Mäh-ern“ haben, die auch direkt um das Haus den Rasen kurzhalten.
Da ist es sehr wichtig, das Öffnen und Schließen des Tores zu überwachen. Auch um die Blumenbeete des Nachbarn zu schonen.
Zu diesem Zweck habe ich einen Homematic Funk-Tür/Fensterkontakt HM-SEC-SC-2 in ein wasserdichtes Gehäuse (eine alte dünnwandige Schraubenschachtel, in Torfarbe lackiert) montiert und den passenden Magneten an den Torflügel geschraubt.
Der Status bei geschlossenem Tor ist also „closed“ , wenn der Reedkontakt öffnet gibt es ein „open“.
So kann FHEM schonmal erkennen, ob das Tor auf oder zu ist. Ich überwache das Tor mit einer Kamera.
Um die Kamera im Floorplan anzuzeigen, wenn das Tor geöffnet ist, habe ich mir folgende Lösung einfallen lassen:
ich habe mir einen zweiten „Aussenanlagen“-Floorplan gebaut, der exakt dem
normalen entspricht, aber zusätzlich einen Iframe mit der URL der passenden Kamera enthält.
Mit einen DOIF überwache ich den Status des HM-LC-SW1-FM.Code: [Auswählen]define gateopenACT DOIF ([Torkontakt] eq "open") (set gateopen on, set Dum_pageswap_D /fhem/floorplan/fp_AN_gateopen) DOELSEIF ([Torkontakt] eq "closed") (set gateopen off, set Dum_pageswap_D /fhem/floorplan/fp_AN
Bei „open“ wird per pageswap auf den Floorplan mit dem Kamerabild umgeschaltet.
http://www.fhemwiki.de/wiki/Browsersteuerung,_Seiten_per_JS_autom._aufrufen
Außerdem wird ein dummy auf „on“ gesetzt, der für seinen „on“-Zustand ein blinkendes Warn-Gif (devStateIcon für „on“) vor das Tor im Floorplan setzt.
Wird das Tor wieder geschlossen, wird dieser dummy auf „off“ gesetzt – das devStateIcon für „off“ ist ein transparenter Pixel - das icon verschwindet also. Dann wird per pageswap wieder auf den „normalen“ Floorplan zurückgeschaltet.
Für den Floorplan gibt es dann noch einen zusätzlichen dummy, der den Toraktor per "on-for-timer" schaltet:Code: [Auswählen]define TorACT dummy
attr TorACT setList on off
attr TorACT room Aussenanlage
define TorACTon notify TorACT set Torantrieb on-for-timer 3
Und so sieht die Anzeige im Floorplan bei geöffnetem Tor aus: Kameraüberwachung
-
Kameras:
Unsere Kameras habe ich im Floorplan „Kameras“ als iframe untergebracht. Es handelt sich um
den jpg-Link unseres Kamerarekorders, das Bild wird ständig „refresht“, ist also ein
quasi-Bewegtbild. Da das ursprüngliche Bild des Kamera-Recorders zu klein ist,
habe ich es mit folgendem Befehl skaliert:Code: [Auswählen]attr cam1 htmlattr width="350" height="300" frameborder="0" marginheight="0"
marginwidth="0" style="zoom: 1.5;;-moz-transform: scale(1.5);;-moz-transform-origin: 0 0;;-o-transform: scale(1.5);;-o-transform-origin: 0 0;;-webkit-transform: scale(1.5);;webkit-transform-origin: 0 0;;"Zusätzlich zur Dropdown-Kameraauswahl habe ich mir eine html-Seite gebaut, die die jpg-links jeder unserer Kameras darstellt. Ein Klick auf eines
der kleinen Bilder stellt das Bild im großen frame dar. Bei dieser Ansicht funktioniert der refresh natürlich nicht so flüssig wie im Einzelbild. Die Seite wird alle 4 Sek. neu geladen. Ich habe diese html-Seite in das "docs"-Verzeichnis des fhem-Servers kopiert - das fungiert nämlich als mini-html-Server. Keine Ahnung ob man das soll oder darf - es funktioniert jedenfalls. Die "Multi-Kamera"-html-Seite habe ich wieder als iframe eingebunden: Philips Hue
-
Philips_hue:
Der Hue-Floorplan steuert alle Hue-Lampen und Lightstrips im Haus an.
Den Hintergrund der Slider für den dunklen Floorplan musste ich anpassen,
indem ich i.d. darkfloorplanstyle.css folgende Zeile hinzugefügt habe:Code: [Auswählen].colorpicker_hue .slider { background: url(/../jscolor/hue_background.svg); }
Die Buttons darunter lösen eine Debian Sendmail-Aus. Auf unseren Android-Geräten wird der Eingang der Mail anhand der
Betreffzeile per Tasker erkannt und die entsprechende App wird geöffnet. Das „Philips“-Symbol beispielsweise öffnet die App, die das Ambilight unseres Philips-TV mit dem Hue synct – da wird dann der ganze Raum zum Fernsehbild.
Ein Highlight ist auch der „Disco“ Button. Der öffnet in selbiger Weise die App „Hue Disco“ und synct die Hue-Lampen zur Musik.
Die pushmail hatte ich zunächst mit „Pushover“ realisiert.
Ich habe aber festgestellt, das die Reaktion über debian-sendmail schneller ist.
Mit sendmail dauert es ca. 3 Sekunden, bis sich die gewünschte App öffnet. Heizungssteuerung
-
Heizung:
Der Heizungs-Floorplan vereint die Steuerung aller Thermostaten und zeigt die Plots der entsprechenden
Temperaturverläufe an. Da die Beschriftung der Plots im dunklen Floorplan nicht zu sehen war, habe ich die
svg_style.css angepasst wie hier beschrieben:
http://forum.fhem.de/index.php/topic,20882.msg144114.html#msg144114Zusätzlich wird im Floorplan Heizung der Heizölstand im Tank angezeigt:
Heizölstand messen per Ultraschall
-
Messung des Heizöl-Standes per UltraschallDa unser Heizöltank bisher nur einen höchst ungenauen analogen Füllstandstandsanzeiger (so ein Schätzeisen mit Schwimmer) hatte,
habe ich nach einer Lösung der Ölstandsanzeige mit fhem gesucht.
Im Netz bin ich auf die Lösung von Bracew mit einem Ultraschallsensor gestoßen, der den Abstand zur Flüssigkeitsoberfläche misst.
Der Ultraschallsensor (DYP-ME007Y) ist so ein Teil wie es auch für die Rückfahrwarner bei Autos benutzt wird.
Das Modul kostet aktuell 15,99€ beim großen Internethändler mit „A“. Meiner kam direkt aus China, das hat ca. 2 Wochen gedauert.
Der Sensor wird an die GPIO eines RasPis angelötet – hier gibt es eine Anleitung und das passende Script zur Auswertung der Messdaten:
http://www.gtkdb.de/index_36_2272.html
Die Beschreibung ist für einen anderen Sensor, der oben erwähnte hat aber die gleichen Anschlüsse.
Bracew hat das ganze für fhem aufbereitet:
http://www.forum-raspberrypi.de/Thread-haussteuerung-heizoel-tankstand-oder-verbrauchs-fernablesung-mit-raspi-geloest-beitrag-21?pid=115200#pid115200
Per cronjob wird in festgelegten Intervallen die Messung gestartet, in eine Log-Datei kopiert und diese Log-Datei wird per
SFTP (von einem weiteren cronjob) an das log-Verzeichnes des fhem-Pis geschoben.
Aus den Messdaten wird dann ein Plot erstellt. Die Tankgröße und der Montageabstand kann im Meßscript angepasst werden –
da unser Tank nur 2000 Liter fasst, habe ich das auch getan.
Der "HeizPi" muß nicht im Tank-Raum sitzen, das Kabel am Sensor ist ziemlich lang:Ich bin während der Umsetzung/Installation auf einige Schwierigkeiten/Fehlermeldungen, usw. gestossen – hier die Lösungen:
1) folgende Erweiterungen für script-Ausführung und SFTP fehlten im Standard-Raspbian meines Mess-Pis und mussten von Hand nachinstalliert werden:
expectCode: [Auswählen]sudo apt-get install expect
und der tcl-interpreter
Code: [Auswählen]sudo apt-get install tcl8.4
2) Der Zugriff auf die GPIO muß als root erfolgen. Mit sudo crontab -e sollte ja eigentlich die cronjob-Tabelle von root erstellt werden
(so habe ich das zumindest verstanden), ich musste für den Mess-Cronjob jedoch noch extra ein „sudo“ vorstellen:Code: [Auswählen]10 0,6,12,18 * * * sudo /home/HeizPi/ultrasonic.py >> /home/HeizPi/Heizoel.log
(Beispiel für 4xtägl. Messung)
3) Der cronjob für die SFTP-Übertragung sollte eine Minute später als die Messung erfolgen, da diese ein paar Sekunden dauert.
Ist nicht so wichtig, da die log-Datei ja in jedem Fall geschrieben wird und bei der nächsten Übertragung dann mitgesendet wird.
Gibt halt nur keine zeitnahme Messung. Bracew misst übrigens 4x täglich, ich messe bisher stündlich – einfach, um zu sehen ob alles klappt.
Ich habe den Sensor – wie Bracew – in das Entlüftungsrohr meines Tanks montiert.
Da der Mindest-Messabstand des Sensors lt. Datenblatt 30cm beträgt, ist so eine korrekte Messung auch bei vollem Tank gewährleistet. Heizölstand messen per Einperl-Sensor
-
Messung des Heizöl-Standes per Einperl-Sensor
Der Ultraschall-Sensor im Tank hatte für mich irgendwie die ganze Zeit ein "Geschmäckle" (wegen Strom in der Nähe des Brennstoffes). Ich habe mir jetzt ein E-Litro-Net bestellt. Das Ding arbeitet mit einem Einperl-Sensor. Über einen Plastikschlauch wird ein klein wenig Luft in der Tank gepustet. Der hydrostatische Druck über der Einperlöffnung wird mit dem barometrischen Aussenluftdruck verglichen. Aus der Differenz ergibt sich dann die Höhe der Flüssigkeitssäule - also der Ölstand. Es befindet sich also lediglich ein Plastikschlauch im Tank - die Elektronik ist weit davon entfernt.
Der E-Litro Net hat eine html-Oberfläche. EInen Demo-Link gibt es auf der Herstellerseite. Mit dem Zusatz
Code: [Auswählen]/xml
gibt das Teil zusätzlich eine xml-Datei aus. Mit dem FHEM-Modul httpmod lese ich aus dieser Datei den Wert "tankLevel" aus
Code: [Auswählen]define OelTank httpmod http://IP_meines_E-Litro/xml 14400
attr OelTank reading01Name Level
attr OelTank reading01Regex (?s)tankLevel>([\d]+)
attr OelTank stateFormat Level
define FileLog_OelTank FileLog ./log/OelTank-%Y-%m.log OelTank.*Die Zahl hinter der URL ist der Abfrage-Intervall in Sekunden.
Für das ganze habe ich mir dann noch einen Plot für den Floorplan gebaut:
Zusätzlich zur Messwerterfassung "Level" habe ich mir noch einen httpmod-Dummy für den Wert "tankPercent" in der xml-Datei des E-Litro gebaut.
Code: [Auswählen]define OelStatusdummy httpmod http://IP_meines_E-litro/xml 14400
attr OelStatusdummy reading01Name tankPercent
attr OelStatusdummy reading01Regex (?s)tankPercent>([\d]+)
attr OelStatusdummy stateFormat tankPercent
Der Dummy soll per icon den Level des Ölstandes mit levelabhängigem devStateIcon grob anzeigen.
Das habe ich mir beim Rolladen abgeguckt (siehe Icon für Rolladen Status):
Beschreibung im FHEM-WikiFür den Level habe ich das FHEM-WLAN-Icon mit Gimp umgebaut, level5.png zeigt 5 volle Striche, level1.png nur einen und level0.png ein Warndreieck für "Heizöl nachbestellen":
Code: [Auswählen]attr OelStatusdummy devStateIcon 9\d.*:level5.png 8\d.*:level5.png 7\d.*:level4.png 6\d.*:level4.png 5\d.*:level3.png 4\d.*:level3.png 3\d.*:level2.png 2\d.*:level1.png 1\d.*:level0.png 0\d.*:level0.png
100% wird nicht vorkommen, da der Grenzwertschater bei 95% auslöst. Also kann die 1\d.* nur einmal vorkommen.
Im Floorplan sieht das dann so aus:
Somit habe ich jetzt eine 100% sichere Messwerterfassung ohne elektrische Sensorik in der Nähe des Tanks.
Wettervorhersage
-
Wetter
Im Floorplan Wetter wird ein Satellitenbild, ein Regenradar sowie nochmal das Yahoo-Wetter (diesmal vertikal)
angezeigt. http://forum.fhem.de/index.php/topic,33610.0.html Multimedia
-
Multimedia:
Der Floorplan „Multimedia“ steuert unsere Dreambox. Diese ist zentral im Haus über einen HDMI-Verteiler eingespeist und kann
direkt über das Enigma-Interface angesprochen werden.
Zusätzlich werden über die entsprechenden dummys unter „TV Wohnzimmer“, „Hifi Wohnzimmer“
und „TV Schlafzimmer“ zwei Harmony-Hubs angesprochen. Damit sind dann auch Makros möglich (TV, Dreambox und Hifi gleichzeitig an/aus)
Ich hatte die Philips-TVs zuerst über das Philips Smart TV Remote für JointSpace
angesteuert.
http://forum.fhem.de/index.php?topic=16189.0
Das hat auch sehr gut funktioniert – das Problem dabei ist allerdings , dass die Philips-TVs
den Modus „schnelle Inbetriebnahme“ erfordern (ansonsten schlafen die TVs komplett und sind über LAN nicht ansprechbar).
Leider kann man diesen Modus nicht permanent aktivieren sondern nur einen „Zeitrahmen“ angeben. Diese "Zeitrahmen sind max.
2h lang und es gibt 3 Stück davon - ergibt also maximal 6h „Aufweckbarkeit“ durch fhem...
Ich mache die Steuerung mittlerweile über Harmony-Hubs, das funktioniert super und ohne diese Einschränkung.
Ich habe allerdings zusätzlich das Modul PHTV aktiviert.
http://fhem.de/commandref.html#PHTV
Ich frage das Reading "presence" des TV im Wohnzimmer damit ab. Weil: es passiert schon mal, dass man im Schlafzimmer die falsche Taste drückt
(ist ja alles auf einem Floorplan) und versehntlich den "falschen TV" einschaltet.
Ein kleiner Statusdummy auf dem Floorplan zeigt dann an, ob der TV im Wohnzimmer läuft - wenn nicht, ist das icon unsichtbar:Code: [Auswählen]define WZTVpresent dummy
attr WZTVpresent setList on off
attr WZTVpresent devStateIcon on:set_on.png off:transparent.png
define WZTVpresentACT DOIF ([PhilipsTV:presence] eq "present") (set WZTVpresent on) DOELSEIF ([PhilipsTV:presence] eq "absent") (set WZTVpresent off)Der Modus "schnelle Inbetriebnahme" muß am TV dafür abgeschaltet sein, sonst ändert sich das Reading erst, wenn der TV in den Tiefschlaf fällt.
In einem iframe habe ich dann noch das Dreambox-Webinterface eingefügt – da kann man die Programme direkt klicken und sieht auch das
vollständige EPG.Bei Klick/Touch auf das Fernbedienungs-Symbol gelangt man zusätzlich auf den Floorplan „Remote“.
Dort sind die wichtigsten Sender als dummy mit den "Picons" der Dreambox dargestellt und wiederum klick/touchbar. Einkaufsliste
-
Einkaufsliste
Wir nutzen schon seit einiger Zeit die App "denkst-du-daran" auf unseren Androiden. Das ist eine cloudbasierte Einkaufsliste die sich auf allen Geräten
synchronisiert. Wir können also am Handy ablesen, was gerade fehlt. Da dieser Dienst auch ein frontend für den browser besitzt,
habe ich einen Floorplan drumrum gebaut (iframe). Wenn in der Küche das Olivenöl zur Neige geht, kann man also ganz einfach
einfach einen Eintrag (z.B. am wandhängenden Tablet) hinzufügen und derjenige, der gerade bei Aldi vorm Regal steht bekommt die Änderung sofort mit. Multiroom-Audio mit Squeezebox
-
Multiroom-Audio mit Squeezebox
Das Lautsprechersymbol oder der Menüpunkt "Multiroom" leitet weiter zum Floorplan "Multiroom".
Mit dem quelloffenen Logitech Sqeezebox Server ist es möglich, synchrones Audio auf mehrere Audio-Clients
zu verteilen. Bei mir laufen sowohl der Logitech-Server als auch die Clients jeweils auf einem Raspberry PI.
Ich habe mittlerweile 7 Pis als Client laufen und entweder an eine PC-Aktivbox gespaxt oder an eine vorhandene Hifi-Anlage
angeschlossen:Und über der Badewanne:
Wie bei einem Profi-Multiroom-System ist übrigens bei der Logitech Geschichte echtes synchrones Audio möglich.
Ein weiterer Vorteil für mich ist der Einsatz von piCore-Playern auf meinen Pis – diese laden Ihr komplettes
„Mini-Squeezebox-Client-Linux“ nach dem booten ins RAM – es wird also nichts auf der SD geschrieben und es kann
sogar im Betrieb der Stecker gezogen werden ohne die SD-Karte zu crashen.Aber der Reihe nach – so habe ich das umgesetzt:
1) Installation des Logitech Squeezebox-Servers auf einem PI 2 (mit Raspbian)
nach dieser Anleitung:
http://allthingspi.webspace.virginmedia.com/lms.php
Der Squeezebox-Server kann nach der Installation vollständig über sein webinterface
(IP_des_Squeezebox_Servers:9000) konfiguriert werden.
Ich habe meine Musik auf einem NAS, das muß natürlich auf dem PI gemounted werden.
Im webinterface unter „Einstellungen“ habe ich ein playlisten-Verzeichnis definiert.
Für meine Radiosender habe ich einfach eine .m3u-Datei erstellt, die die Stream-URL des Senders enthält.
Diese Datei habe ich per ftp auf den Squeezebox-Server geschoben.
Die Playlisten für die Musik von meiner NAS-Platte können sehr komfortabel im webinterface des LMS erstellt und gespeichert werden.
2) Installation der PiCore-Player auf den Client-Pis:
https://sites.google.com/site/picoreplayer/home
Bei der Installation hatte ich 2 Probleme:
a) Der piCorePlayer soll sich auch per eigenem webinterface konfigurieren lassen. Bei mir wurden
Änderungen nach einem reboot jedoch nicht übernommen. Ist evt. Ein Linux-Rechteproblem -
egal – es gibt eine Datei auf der Boot-Partition der erstellten SD-Karte, die heisst newconfig.cfg.
In diese Datei kann man alles eintragen: Player-Name, WLAN ja/nein, SSID, WLAN pw usw.
b) Bei Playern die über LAN angebunden sind, wird als standard die MAC-Adresse 00:00:00:00:00:00 eingetragen.
Der Logitech Server kommt mit 2 gleichen Mac-Adressen aber nicht klar, also muß diese unbedingt geändert werden.
Ich habe einfach die letzte Stelle geändert also xx.xx.xx.01, xx.xx.xx.02 usw.
Die Änderung kann man ebenfalls in der .cfg-Datei vornehmen.3) Ich habe mir die Module SB_SERVER und SB_PLAYER für fhem heruntergeladen
...und den Server per „define“ eingebunden wie hier beschrieben:
http://forum.fhem.de/index.php?topic=17667.0
Per autocreate wurden sofort alle piCorePlayer erkannt. Diese habe ich dann umbenannt.
Weil: der Name im FHEM muß mit dem Namen im Squeezebox-Server identisch sein
4) Ich habe mir einen floorplan gebastelt:
Ich habe die SB_PLAYER eingebunden.
Per "attr Mein_SB_PLAYER_Kueche webcmd playlists:volume" bekomme jetzt ich den Lautstärke-Slider
und ein dropdown-Menü für alle Playlisten des Squeezbox-Servers.
Ich hatte das Problem, dass das devStateIcon des Players im Floorplan sich nur bei jedem 2. Klick oder bei browser refresh
aktualisiert hat.
http://forum.fhem.de/index.php/topic,30139.msg287151.html#msg287151
Das Atrribut "donotnotify" des Players muß auf "false" gesetzt werden, dann geht es.
(Diese Einstellung ist auch für das ordnungsgemäße Aktualiseren der readings "currentTitle" und "currentArtist" notwendig - siehe weiter unten)
Um damit nicht zuviele events zu erzeugen, habe ich folgendes Attribut gesetzt (Danke kvo1! ):Code: [Auswählen]attr Mein_SB_Player event-on-change-reading currentTitle,currentArtist,state
Ich habe mir einen zusätzlichen dummy gebaut, weil ich zusätzlich noch die Stromversorgung meiner
Aktiv-Lautsprecher an- und abschalten möchte: *** siehe Hinweis "Update 2"Code: [Auswählen]define JNSKuechePower dummy
attr JNSKuechePower room SB_PLAYER
attr JNSKuechePower setList on off
attr JNSKuechePower devStateIcon off:mroom_kueche.off.png on:mroom_kueche.on.png
define JNSKuechePowerAn notify JNSKuechePower:onset Kueche on;set JogiNetAudio5Power on;set Kueche play
define JNSKuechePowerAUS notify JNSKuechePower:offset Kueche off
Ich lasse für den im floorplan eingebundenen SB-Player (hier heisst der „Kueche“) also nur „commands only“ anzeigen, dann
werden die webcmds „volume und playlists“ angezeigt, den dummy setze ich direkt darüber.
Zusätzlich lasse ich mir den gerade gespielten Titel/Interpreten
per readings-group anzeigen:Code: [Auswählen]define KuecheText readingsgroup Kueche:currentTitle,currentArtist
attr KuecheText room SB_PLAYER
attr KuecheText noheading 1
attr KuecheText nonames 1
attr KuecheText notime 1
attr KuecheText style style="color:lightblue;font-size:15px"
attr KuecheText visibility hidden
Um diese Readings nur bei aktivem Player einzuschalten, habe ich ein weiteres DOIF erstellt:Code: [Auswählen]define KuecheTextVis DOIF ([Kueche] eq "on") (set KuecheText visibility show) DOELSEIF ([Kueche] eq "off") (set KuecheText visibility hide)
attr KuecheTextVis room SB_PLAYER
Jetzt zum syncen der Einzelnen Player:
Ich möchte die Möglichkeit haben, jeden Player mit jedem anderen Player zu syncen.
Also habe ich mir für jeden Sync einen dummy gebaut.
Am Player „Kueche“ beispielsweise hängt also für jedes meiner anderen Geräte ein dummy:Code: [Auswählen]define JNSsyncKuecheAussen dummy
attr JNSsynxKuecheAussen room SB_PLAYER
attr JNSsyncKuecheAussen setList on off
attr JNSSyncKuecheAussen devStateIcon on:aussen_ticked.png off:aussen_unticked.png
ein notify für „An“ synct den Player mit dem gewünschten Gerät und schaltet den entsprechenden
Verstärker (per Homematic-Schalter) mit ein:Code: [Auswählen]define JNSsyncKuecheAussenAN notify JNSsyncKuecheAussen:on set JNSAussenPower on;set Kueche sync Aussen
;set Kueche play
das „Aus“-Notify entfernt den Player aus der Sync-Gruppe:Code: [Auswählen]define JNSsyncKuecheAussenAUS notify JNSsyncKuecheAussen:off
set JNSAussenPower off;set Aussen unsync
So einen dummy habe ich jetzt für alle devices angelegt, für die Küche also:Zitatdefine JNSsyncKuecheWohnzimmer dummy,...
define JNSsyncKuecheBad dummy...
blabla...
Ergibt bei mittlerweile 7 Playern die sich jeweils mit den anderen 6 Playern syncen können sollen 42 dummys.
Wird für einen Player ein weiterer dummy geklickt, hängt sich der jeweilige Player einfach an die sync-Gruppe dran.(in diesem Beispiel sind Bad und Wohnzimmer mit dem Player im Arbeitszimmer gesynct)
Für das Anlegen der vielen dummys Ist ein bischen Fleißarbeit erforderlich. Theoretisch kann man den sync auch in ein webcmd legen.
Ich fand es aber so wesentlich übersichtlicher.
So sieht es im floorplan aus (im Beispielbild läuft im Arbeitszimmer "Radio Latina", das Bad und das Wohnzimmer sind dazugesynct.
Parallel läuft im Schlafzimmer "Alsterradio")Es ist also auch möglich, in Zimmer A Sender/playlist X „gesynct“ zu hören, während im Zimmer B Sender/Playlist Y spielt.
Ist schon sehr komfortabel und - wie gesagt - auf meinen Pis absolut synchron.
Wenn ich zusätzlich eine andere Hardware (z.B. Tablet mit Player-App)
als Player laufen lassen möchten, ergibt sich evt. aus der unterschiedlichen Hardware ein Zeitversatz. Diesen kann man auf
der web-Oberfläche des LMS unter Einstellungen/Player anpassen.
Die Buttons play,pause,<<,>> habe ich über das Modul "remotecontrol" / layout "itunes" eingebunden - notify auf die SB_Player.
Zu guter letzt habe ich mir noch einen dummy „alle Zonen aus“ angelegt – damit wird auf Knopfdruck alles auf Null gesetzt.Ich habe dann mal gemessen (da ich LTE habe bekomme ich den Verbrauch von Vodafone angezeigt).
Über eine Stunde verbraucht ein Internetradiosender bei mir zwischen 60 und 80MB.
Und zwar UNABHÄNGIG davon, ober der Stream nur auf einem SB-Player oder auf 5 SB-Playern gleichzeitig läuft.
Der Server greift also immer nur einen Stream aus dem Internet ab.Stream des Sounds vom lokalen PC (z.B. Youtube, usw.):
Zum Stream des lokalen Desktop-Sounds:
Ich habe lange mit dem wavein-plugin experimentiert - leider ohne Ergebnis. Das kann daran liegen, dass ich das ganze "Pulse-Audio"-Geschehen
auf meinem Linux-PC nicht verstanden haben.
Egal - ich bin im Netz auf eine simple Lösung per VLC gestossen:
http://confoundedtech.blogspot.de/2014/10/pc-audio-music-to-squeezebox-without.html
Die Beschreibung ist für Linux, sollte sich aber auch auf Windows übertragen lassen (Firewall-Ports freigeben funktioniert natürlich dann über die entsprechenden Windows-Einstellungen).
PerCode: [Auswählen]cvlc pulse://alsa_output.pci-0000_00_1b.0.analog-stereo.monitor :sout='#transcode{vcodec=none,acodec=mp3,ab=320,channels=2,samplerate=44100}:http{dst=:8081/pc-stream.mp3}' :no-sout-rtp-sap :no-sout-standard-sap
starte ich den Stream auf meinem lokalen PC.
Auf dem Squeezebox-Server kann ich jetzt eine URL öffnen:
IP_MEINES-PCS:8081/pc-stream.mp3- es wird dann alles wiedergegeben, was mein lokaler PC auch abspielt.
Diese URL kann natürlich auch als Favorit oder playlist-Datei eingebunden werden.
Latenz: ca. 1 Sekunde - also bei Youtube-Videos nicht so ganz "lippensynchron" aber brauchbar f.d. Partymodus.Einbindung einer Durchsage-Option per email für das Squeezebox-Audiosystem
Es kommt des öfteren vor, dass einer von uns bei der Gartenarbeit oder beim Ausmisten der Ställe keinTelefon dabei hat.
"Hast Du denn das Telefon nicht gehört? ..."
Da ich - natürlich - Stall und Terrasse mittlerweile mit Squeezebox-Pis bestückt habe,
habe ich überlegt, eine email an fhem zu schicken und diese dann über die Squeezeboxen vorlesen zu lassen.
Hier meine Lösung mit der "talk"-Funktion des Squeezebox-Moduls:
1) Ich habe mir eine Durchsage-emailadresse angelegt.
Die ist natürlich streng geheim – wer die hat, der spricht schließlich mit unserem Haus...
Ich hoffe, diese Adresse landet niemals in einem Spamverteiler...
2) Ich habe mit dieser Anleitung den imap-Empfang unter fhem eingerichtet:
http://blog.jenconsulting.de/?p=152
3) ich habe eine mp3-Sounddatei (gong.mp3) auf den Squeezebox-Server geladen
4) Ich habe mir ein notify gebaut, das auf den Posteingang einer mail reagiert:Code: [Auswählen]define Durchsage notify FhemMail
set JNSKuechePower on;set JNSsyncKuecheAussen2 on;set JNSsyncKuecheBad on;set JNSsyncKuecheArbeitszimmer on;set JNSsyncKuecheWohnzimmer on;set JNSsyncKuecheSchlafzimmer on;set JNSsyncKuecheAussen on;sleep 5;{fhem("set Kueche talk Achtung Es folgt eine Durchsage |/home/pi/gong.mp3| ".ReadingsVal("FhemMail","Subject",""))};sleep 25;set alloff on;sleep 5;set Dum_pageswap_D /fhem/floorplan/Message;{fhem("set Dream1 showText ".ReadingsVal("FhemMail","Subject",""))};set alloff onDieses notify erledigt folgendes:
a) es schaltet den Player in der Küche an
b) es schaltet meine Sync-dummys an.
(siehe Beschreibung http://forum.fhem.de/index.php/topic,33088.msg288020.html#msg288020)
Alle Player werden also mit der Küche gesynct und diese wiederum schalten dann Ihren Verstärker, usw. an.
c) es wird ein Gong und danach ein „Achtung, es folgt eine Durchsage“ abgespielt - danach wird das Reading der Betreffzeile der eingehenden email vorgelesen.
(Wie gesagt nur die Betreffzeile - hier muß die Nachricht rein - der Inhalt der mail ist irrelevant)
d) Mein alloff dummy schaltet alle player ab. Wer irgendwo Musik gehört hat, muß wieder einschalten – Pech gehabt.
Außerdem unterstreicht das ja die Wichtigkeit der Durchsage.
Aber im Ernst: um selektiv an- und auszuschalten müßte ich im Vorwege prüfen, welcher Player gerade läuft – das kommt dann später...
e) per pageswap-dummy werden alle auf den Tablets oder PCs aufgerufenen Floorplans auf den Floorplan „Message“ umgeleitet
Beschreibung – siehe hier:
http://www.fhemwiki.de/wiki/Browsersteuerung,_Seiten_per_JS_autom._aufrufen
f) Zusätzlich wird der Inhalt des email-Readings i.d. laufende TV-Programm unserer Dreambox eingeblendet
Spätestens jetzt sollte jeder die Nachricht erhalten haben.
5) für den floorplan „Message“ habe ich eine readingsGroup angelegt,
die die letzte Nachricht mit Datum und Uhrzeit anzeigt:Code: [Auswählen]define mail_message readingsGroup FhemMail:Subject
attr mail_message room SB_PLAYER
attr mail_message style style="color:lightblue;;text-align:center;;font-size:25px"
attr mail_message timestampstyle style="color:magenta;;text-align:center;;font-size:15px"
attr mail_message cellStyle style="font-weight:bold;;font-size:16px
attr mail_message noheading 1
attr mail_message nonames 1
Und so sieht es dann auf allen Displays aus:Anzeige der 35 zuletzt gespielten Titel unserer Squeezebox-Player:
Oft hören wir einen Titel im Radio, den wir später gerne im Internet als mp3 käuflich erwerben möchten.
Bis dato mussten wir dann immer die Playlist-Recherche auf der Internetseite des jeweiligen Senders aufrufen.
Das ist jetzt Geschichte - mein "Musiktitel-Floorplan" sammelt Titel- und Interpreten-Readings.
Das geht ganz easy mit einer "readingsHistory":Code: [Auswählen]define Musiktitel readingsHistory SB_Player1:currentTitle,currentArtist SB_player2:currentTitel,currentArtist SB_Player3:currentTitel,currentArtist
attr Musiktitel style style="color:lightblue;;text-align:left;;font-size:15px"
attr Musiktitel rows 35
Und so sieht es dann im floorplan aus:Da kann man dann schnell mal nachschauen. Ein direkt generierter Link zur Suche im Amazon-Shop wäre natürlich genial - das liesse sich bestimmt
über die Such-URL+Reading lösen. Multiroom-Audio mit Kodi
-
Multiroom-Audio mit Kodi
Der Vollständigkeit halber sei hier noch eine weitere Multiroom-Audiovariante erwähnt: Ich hatte mir - vor der Squeezebox-Varaiante - eine Multiroom-Audioversion mit Kodi/XBMC-Clients gebaut. Auch diese lassen sich mit FHEM perfekt steuern, die Audio-Wiedergabe ist jedoch nicht synchron. Über einen mdp-Server hatte ich mir dazu noch eine Möglichkeit der "Stream-Bündelung" einfallen lassen. Hier die Beschreibung der damiligen Version:
Die OpenElec/Kodi-Geschichte steuere ich "headless" mit dem Modul "xbmc".
Das Booten erledigt ein Homematic-Schalter (weil der PI kein WOL kann), die Aktivbox wird gleich mit aktiviert.
Zusätzlich habe ich die "remote" des xbmc-Moduls eingebunden für Laut/Leise/Mute/Stop.
Die von uns meist gehörten Radiostreams habe ich als Favoriten-Dummies angelegt. Per "set MeinAudio1 open stream-URL"
kann ich den passenden Stream öffnen. Und das geht für jeden Raum - auch separat:Der weblink "Playlists" führt zum jeweiligen Floorplan "Playlists". Links unten sind vordefinierte kodi-Listen (80er, 90er, blabla).
Touch/Klick genügt. Die Listen editiere ich am PC und schiebe die per Filezilla auf die Rasbpis.
Ausserdem ist die "Chorus" Oberfläche von kodi als iframe in den Floorplan integriert. Für benutzerdefinierte Playlisten,
weitere webradios, usw.:Für die Radiosender meiner „Multiroom“-Lösung habe ich mir folgende Erweiterung ausgedacht:
Es ist – wie ich ja schon beschrieben habe – möglich, in jedem Raum auf einem OpenElec-PI einen anderen Radiosender
zu hören. Ein Floorplan-dummy öffnet dabei über das XBMC-Modul den jeweiligen Stream.
Da wir hier auf dem Land über LTE ins Internet gehen, nagt dass natürlich am Traffic (30GB ist das Limit) wenn alle Räume
den gleichen Sender hören (denn dann wird ja für jeden Raum ein Stream gestartet).
So ein Radiosender frisst ja nicht sooo viel, aber wir hören halt auch sehr viel Radio und es laufen ja auch noch weitere
Dienste, die am Trafficlimit zehren. Die Lösung, die mir dazu eingefallen ist, ist evt. etwas aufwändig, funktioniert aber prächtig.
Allerdings: Der Code (was hat sich der Künstler dabei gedacht?) ist wohlmöglich optimierungsfähig, kürzbar und effizienter zu gestalten.
Ich bin halt weder Programmierer noch fhem-Profi. Wer sowas in ein Perl-Script auslagern kann o.ä. - ich bin für Input
dankbar & aufgeschlossen. Hier jedenfalls meine McGyver-Lösung:
Ich habe mir zunächst auf einem freien RasbpPi 2 einen mpd-Server installiert
http://forum.fhem.de/index.php/topic,35428.0.html
und mir für jeden „Favouriten-Radiosender“ eine Playlist angelegt – also eine m3u-Datei, die lediglich die
URL des jeweiligen Senders beinhaltet.
Ich zähle dann einfach die Zahl der aktiven Dummys mit einem DOIF.
Ich habe insges. 5 Räume, in denen ein RasbPi mit OpenElec läuft.
Wenn in mehr als einem Raum der gleiche Sender läuft, dann wird per fhem die Stream-URL vom
eigentlichen Stream auf die Netzwerkadresse des mpd-Servers umgeschaltet und der mpd-Server wird veranlasst,
die Playlist des jeweiligen Senders abzuspielen.
http://forum.fhem.de/index.php?topic=18517.0
Zum Schluß wird ein „Statusdummy“ im Floorplan gesetzt. Blinkt der dummy grün, ist es ein Einzelstream, blinkt der
dummy rot ist es ein Stream des mpd-Servers.
Beispiel: hier laufen auf den PIs der Räume "Multiroom Aussen" und "Multiroom Bad" der gleiche Sender (Streams sind zusammen-
geschaltet) und im "Multiroom Schlafzimmer" läuft ein anderer Sender:Das würde natürlich mit allen playlisten – nicht nur mit Radiosendern laufen.
Funktionieren tut das Ganze so (am Beispiel „Alsterradio“):
Zuerst definiere ich für jeden Sender einen Dummy für den Radiostream
(Auswahl normaler Stream oder mpd-Server-Zugriff):Code: [Auswählen]define streamurl_alsterradio dummy
attr streamurl_alsterradio room xbmc
attr streamurl_alsterradio setList http://live96.106acht.de http://192.168.0.70:8000
set streamurl_alsterradio http://live96.106acht.de
zusätzlich gibt es einen „Statusdummy“ für jede Betriebsart und für jeden OpenElec-PI (JNA1-5):Code: [Auswählen]define JNA1wait dummy
attr JNA1wait setList on off active server achtung
attr JNA1wait devStateIcon on:wait.png off:transparent.png active:green_blink.gif server:red_blink.gif achtung:achtung.gif
Beim Einschalten eines RasbPis wird dieser dummy auf „wait“ gesetzt
(dann erscheint ein „bitte warten“), danach auf „off“, das ist ein transparenter Pixel:Wird ein Einzelstream abgerufen (active), blinkt ein grünes Licht (animiertes gif)
und im Serverbetrieb (also mehr als ein Einzelstream des gewünschten Senders)
blinkt ein rotes gif (Status: „server“) - siehe oben.
Der Status „achtung“ erscheint, sobald mehr als 2 Serverstreams laufen – da ich nur eine mpd-Instanz
laufen habe, geht das ja nicht (siehe weiter unten)
Bei klick oder touch auf den jeweiligen floorplan-dummy wird der stream gestartet und
wie bei Omas Dampfradio „springen die anderen Radiotasten heraus“, sobald man eine drückt:Code: [Auswählen]define alsterradioJNA1 dummy
attr alsterradioJNA1 room xbmc
attr alsterradioJNA1 setList on off
define alsterradioJNA1An notify alsterradioJNA1:on {fhem('set JogiNetAudio1 open '.Value('streamurl_alsterradio'));;fhem('set radiolatinaJNA1,skyrockJNA1,ouifmJNA1,radio538JNA1,ndr2JNA1,ndr1shJNA1,rshJNA1 off')}
define alsterradioJNA1Aus notify alsterradioJNA1:off set JNA1wait off
Ein DOIF guckt, wieviele Alsterradio-dummys gerade betätigt sind, setzt die Stream-URL entsprechend und selektiert
die playlist des mpd. So ein DOIF braucht es für jeden meiner 8 Favouriten.
(Es hat sich als am praktikabelsten erwiesen, den Text mit copy & paste in eine Textverarbeitung zu kopieren.
Ich benutze LibreOffice. Über „finden & ersetzen“ tauscht man dann einfach den Sendernamen aus und braucht nur noch
die Stream URL händisch zu ändern):Code: [Auswählen]define multi_alsterradio DOIF (([alsterradioJNA1] eq "on" and [alsterradioJNA2] eq "off" and [alsterradioJNA3] eq "off" and [alsterradioJNA4] eq "off" and [alsterradioJNA5] eq "off") or ([alsterradioJNA1] eq "off" and [alsterradioJNA2] eq "on" and [alsterradioJNA3] eq "off" and [alsterradioJNA4] eq "off" and [alsterradioJNA5] eq "off") or ([alsterradioJNA1] eq "off" and [alsterradioJNA2] eq "off" and [alsterradioJNA3] eq "on" and [alsterradioJNA4] eq "off" and [alsterradioJNA5] eq "off") or ([alsterradioJNA1] eq "off" and [alsterradioJNA2] eq "off" and [alsterradioJNA3] eq "off" and [alsterradioJNA4] eq "on" and [alsterradioJNA5] eq "off") or ([alsterradioJNA1] eq "off" and [alsterradioJNA2] eq "off" and [alsterradioJNA3] eq "off" and [alsterradioJNA4] eq "off" and [alsterradioJNA5] eq "on") or ([alsterradioJNA1] eq "off" and [alsterradioJNA2] eq "off" and [alsterradioJNA3] eq "off" and [alsterradioJNA4] eq "off" and [alsterradioJNA5] eq "off")) (set JogiNetMPD stop, set streamurl_alsterradio http://live96.106acht.de) DOELSE (set JogiNetMPD playlist alsterradio.m3u, set streamurl_alsterradio http://192.168.0.70:8000)
Zusätzlich wird geguckt ob mpd-Server-Betrieb oder nicht:Code: [Auswählen]define server_alsterradio dummy
attr server_alsterradio room xbmc
attr server_alsterradio setList on off
define serveract_alsterradio DOIF ([streamurl_alsterradio:state] eq "http://192.168.0.70:8000") (set server_alsterradio on) DOELSEIF ([streamurl_alsterradio:state] eq "http://live96.106acht.de") (set server_alsterradio off)
attr serveract_alsterradio do always
Wenn sich der Streamstatus ändert (also mpd-Server oder nicht) wird „Staus-dummy“ gesetzt und der Stream neu gestartet:Code: [Auswählen]define state_alsterradioJNA1wait DOIF (([alsterradioJNA1:state] eq "on" and [server_alsterradio:state] eq "on"))(set JNA1wait server,{fhem('set JogiNetAudio1, open '.Value('streamurl_alsterradio'))} ) DOELSEIF (([alsterradioJNA1:state] eq "on" and [server_alsterradio:state] eq "off"))(set JNA1wait active,{fhem('set JogiNetAudio1 open '.Value('streamurl_alsterradio'))} )
attr state_alsterradioJNA1wait do always
Wenn – wie oben erwähnt mehr als 2 Streams aus der einen mpd-Instanz abgerufen werden sollen,
muss das ganze zurückgesetzt werden. Überwacht wird das mit einem weiteren DOIF:Code: [Auswählen]define streamcount dummy
attr streamcount setList zuviele_streams streams_ok
attr streamcount room xbmc
define multi_serverzugriff DOIF (([server_latina] eq "on" and [server_skyrock] eq "off" and [server_radio538] eq "off" and [server_ouifm] eq "off" and [server_ndr2] eq "off" and [server_ndr1sh] eq "off" and [server_rsh] eq "off" and [server_alsterradio] eq "off") or ([server_latina] eq "off" and [server_skyrock] eq "on" and [server_radio538] eq "off" and [server_ouifm] eq "off" and [server_ndr2] eq "off" and [server_ndr1sh] eq "off" and [server_rsh] eq "off" and [server_alsterradio] eq "off") or ([server_latina] eq "off" and [server_skyrock] eq "off" and [server_radio538] eq "off" and [server_ouifm] eq "off" and [server_ndr2] eq "off" and [server_ndr1sh] eq "off" and [server_rsh] eq "off" and [server_alsterradio] eq "off") or ([server_latina] eq "off" and [server_skyrock] eq "off" and [server_radio538] eq "off" and [server_ouifm] eq "on" and [server_ndr2] eq "off" and [server_ndr1sh] eq "off" and [server_rsh] eq "off" and [server_alsterradio] eq "off") or ([server_latina] eq "off" and [server_skyrock] eq "off" and [server_radio538] eq "off" and [server_ouifm] eq "off" and [server_ndr2] eq "on" and [server_ndr1sh] eq "off" and [server_rsh] eq "off" and [server_alsterradio] eq "off") or ([server_latina] eq "off" and [server_skyrock] eq "off" and [server_radio538] eq "off" and [server_ouifm] eq "off" and [server_ndr2] eq "off" and [server_ndr1sh] eq "on" and [server_rsh] eq "off" and [server_alsterradio] eq "off") or ([server_latina] eq "off" and [server_skyrock] eq "off" and [server_radio538] eq "off" and [server_quifm] eq "off" and [server_ndr2] eq "off" and [server_ndr1sh] eq "off" and [server_rsh] eq "on" and [server_alsterradio] eq "off") or ([server_latina] eq "off" and [server_skyrock] eq "off" and [server_radio538] eq "off" and [server_ouifm] eq "off" and [server_ndr2] eq "off" and [server_ndr1sh] eq "off" and [server_rsh] eq "off" and [server_alsterradio] eq "on") or ([server_latina] eq "off" and [server_skyrock] eq "off" and [server_radio538] eq "off" and [server_ouifm] eq "off" and [server_ndr2] eq "off" and [server_ndr1sh] eq "off" and [server_rsh] eq "off" and [server_alsterradio] eq "off")) (set streamcount streams_ok) DOELSE (set streamcount zuviele_streams)
attr multi_serverzugriff do always
define streamcount_act DOIF ([streamcount:state] eq "zuviele_streams") (set stream_reset on)(hier laufen 2x Alsterradio, die Stream-URL wurde umgeschaltet auf die lokale IP des mpd-Servers und weil das nur
ein Sender versucht, ist der Status streamcount auf "streams_ok)
„stream_reset“ schaltet erstmal mit dem Holzhammer alle „Radiotasten“ für alle Räume aus, setzt dann den Serverstatus der
Streams auf „off“ und den Statusdummy auf „achtung“ (es kommt die Anzeige „Server überlastet, bitte neu wählen“).Nach einer kleinen Pause wird zuletzt noch der Status-dummy wieder auf „off“ gesetzt:
Code: [Auswählen]define stream_reset dummy
attr stream_reset setList on off
attr stream_reset room xbmc
define stream_resetAN notify stream_reset:on set radiolatinaJNA1 off;;set skyrockJNA1 off;;set radio538JNA1 off;;set ouifmJNA1 off;;set ndr2JNA1 off;;set NDR1shJNA1 off;;set rshJNA1 off;;set alsterradioJNA1 off;;set radiolatinaJNA2 off;;set skyrockJNA2 off;;set radio538JNA2 off;;set ouifmJNA2 off;;set ndr2JNA2 off;;set NDR1shJNA2 off;;set rshJNA2 off;;set alsterradioJNA2 off;;set radiolatinaJNA3 off;;set skyrockJNA3 off;;set radio538JNA3 off;;set ouifmJNA3 off;;set ndr2JNA3 off;;set NDR1shJNA3 off;;set rshJNA3 off;;set alsterradioJNA3 off;;set radiolatinaJNA4 off;;set skyrockJNA4 off;;set radio538JNA4 off;;set ouifmJNA4 off;;set ndr2JNA4 off;;set NDR1shJNA4 off;;set rshJNA4 off;;set alsterradioJNA4 off;;set radiolatinaJNA5 off;;set skyrockJNA5 off;;set radio538JNA5 off;;set ouifmJNA5 off;;set ndr2JNA5 off;;set NDR1shJNA5 off;;set rshJNA5 off;;set alsterradioJNA5 off;;set server_latina off;;set server_skyrock off;;set server_radio538 off;;set server_ouifm off;;set server_ndr2 off;;set server_ndr1sh off;;set server_rsh off;;set server_alsterradio off;;set streamcount streams_ok;;set JNA1wait achtung;;set JNA2wait achtung;;set JNA3wait achtung;;set JNA4wait achtung;;set JNA5wait achtung;;sleep 15;;set JNA1wait off;;set JNA2wait off;;set JNA3wait off;;set JNA4wait off;;set JNA5wait off
Jetzt kann man die Sender wieder ganz normal wählen und die DOIFs selektieren wieder die gewünschte Betriebsart. Abfall-Kalender mit Google
-
Einbindung des Google-Kalenders in FHEM
Wenn die Mülltonne, die Papiertonne oder der gelbe Sack an die Strasse muss, tragen wir diesen Termin in den Google Kalender ein.
Über das FHEM-Modul Calendar lassen sich diese Termine prima auslesen.
Einen Tag bevor die Tonne abgeholt wird, zeigt unser Floorplan ein entsprechendes Symbol.
Zusätzlich bekommen wir jeder eine email geschickt mit dem Text "der gelbe Sack muss raus!" oder "die Papiertonne muß raus".
So habe ich das Ganze umgesetzt.
Zunächst muß natürlich ein Google-Kalender vorhanden sein. Die Kalender ID findet sich bei den Einstellungen des Google-Kalenders unter "PrivatAdresse".
So wird das Calendar-Device in FHEM angelegt:
Code: [Auswählen]define AbfallGoogleCalender Calendar ical url https://www.google.com/calendar/ical/meine_GoogleKalender_URL.ics 43200
Die "43200" steht für den Abfrage-Intervall in Sekunden, der Kalender wird also alle 12 Stunden abgefragt.
Dann habe ich mir Dummies für den Floorplan angelegt:
FHEM Wiki Google-Kalender zur Steuerung von Dummies
Code: [Auswählen]define gelber_Sack
dummy attr gelber_Sack room Kalender attr gelber_Sack setList ja nein attr gelber_Sack webCmd ja:nein
attr gelber_Sack devStateIcon ja:gelber_sack.ja.png nein:transparent.pngDas devStateIcon ist ein transparenter Pixel bei "nein" und ein entsprechendes Symbol bei "ja". Für die "schwarze Tonne" und die Papiertonne habe ich mir dann ebenfalls dummies angelegt:
mit
Code: [Auswählen]update all https://raw.githubusercontent.com/uniqueck/fhem-abfall/master/controls_fhemabfall.txt
habe ich mir dann das inoffizielle Hilfmodul "Abfall" installiert. FHEM Wiki ABFALL
Dann wird ein Device "myABFALL" erstellt:
Code: [Auswählen]define myABFALL AbfallGoogleCalender
wobei "AbfallGoogleCalender" der Names des definierten Google-Kalenders im Modul "Calender" ist.
Zur Datumsanzeige wird eine Hilfsfunktion in die 99_myUtils eingefügt:
Code: [Auswählen]#
# Hilfsfunktion für Kalenderauswertungen
#
sub datumHeuteMorgen($){
my $compareDate = shift;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$year += 1900; $mon += 1;
my $heute = sprintf('%02d.%02d.%04d', $mday, $mon, $year);
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time+86400);
$year += 1900; $mon += 1;
my $morgen = sprintf('%02d.%02d.%04d', $mday, $mon, $year);
return "heute" if $compareDate eq $heute;
return "morgen" if $compareDate eq $morgen;
return $compareDate;
}
sub
myUtils_refresh($)
{
my ($name) = @_;
FW_directNotify("#FHEMWEB:$name", "location.reload(true);","" );
}Dann werden die User-Readings definiert:
Code: [Auswählen]attr myABFALL ftui_datum {ReadingsVal("myABFALL","now_text","") eq "" ? datumHeuteMorgen(ReadingsVal("myABFALL","next_datum","")) : "heute"
und zum Schluß werden noch entsprechende "DOIFS" generiert:
Code: [Auswählen]set DgelberSack DOIF ([myABFALL] =~ "gelber") (set gelber_sack ja,{ DebianMail(This email address is being protected from spambots. You need JavaScript enabled to view it.','Muchelndorf Smarthome: Der Gelbe Sack muss raus!','Muchelndorf Smarthome: Der gelbe Sack muss raus!');;} DOELSE (set gelber_sack nein) attr DgelberSack do always
Somit haben wir einen Tag vor dem eigentlichen Kalendereintrag das Floorplan-icon gesetzt und per Debian-Mail eine email verschickt.
Erhöhung der Funkreichweite
-
Erhöhung der Funkreichweite von Homematic-Komponenten
Der Herbst kommt, die Tage werden wieder kürzer. Wir müssen nach der Arbeit unsere Tiere versorgen und wenn wir abends den Paddock unserer Esel abäppeln, ist es im Normalfall bereits dunkel. Unser Paddock liegt auf dem Nachbargrundstück und es gibt dort eine Aussenbeleuchtung. Leider liegt diese weit ausserhalb der Reichweite unseres Homematic HM-LAN Adapters. Ich habe etwas im Internet gesucht, es gibt einen selektiven Funkrepeater für Homematic-Komponenten - den HM-Sys-SRP-Pl Funk-Zwischenstecker.
Das Gerät scheint nicht mehr produziert zu werden, ich habe leider nur einen Bausatz gefunden. Eine halbe Stunde Lötarbeit war also vonnöten - glücklicherweise waren alle SMD-Teile bereits bestückt.
Auf "halber Strecke" zur Verteilerdose der Lichtanlage des Nachbarhauses steht unser Gartenpavillion. Von hier bis zum HM-LAN-Adapter sind es ca. 15m mit zwei Wänden dazwischen. Hier habe ich den Repeater in einem wetterfesten Gehäuse montiert. Vom Pavillion bis zum "Aussenlichtverteiler" des Nachbarhauses sind dann nochmal ca. 18m Funkstrecke zu überbrücken.
Das Nachbarhaus hatte vorher schon einen Funklichtschalter der Marke "Jung" - diesen habe ich einfach durch einen Homematic HM-LC-SW1-FM Funkschaltaktor ersetzt. Die Fernbedienungen der Nachbarn musste ich natürlich austauschen. Leider wird die aktuelle Version der Homematic Fernbedienung HM-RC-4-3 nicht von der veralteten Firmware meines HMLAN-Adpaters unterstützt, eine direkte Anmeldung im FHEM ist daher fehlgeschlagen ( es wird ein unbekanntes Gerät erkannt). Ich hätte natürlich ein Firmware-Update machen können, habe aber keinen Windows-PC im Haus...
Ich habe also die 3 Fernbedienungen für die Nachbarn direkt mit dem HM-LC-SW1-FM gepeert. Hierzu muss an jeweils beiden Komponten das Anlern-Prozedere ausgeführt werden. Wichtig: die direkte Verbindung ist nur möglich, wenn der HM-LC-SW1-FM noch nicht im FHEM (bzw. am HM-LAN-Adapter) angemeldet ist.
Nachdem die Fernbedienungen sich direkt mit dem Aktor verstanden haben, habe ich den HW-LC-SW1-FM dann mit dem üblichen Prozedere im FHEM angemeldet:
set HMLAN1 hmPairForSec 900
und umbenannt
ren CUL_HM_HM_LC_SW1_FM_xxxxxx NachbarLicht
Das Anlernen muß natürlich in Reichweite des HM-LAN passieren und nicht in Nachbars Garage.
Jetzt der Repeater:
Auch dieser kann genau wie der Funkaktor automatisch mit set HMLAN1 hmPairForSec 900 angelernt und dann anschliessend umbenannt werden.
Der Repeater ist selektiv, d.h. man kann bis zu 16 Kanäle am Repeater betreiben, wobei jeder Aktor oder Sensor einen Kanal bekommt:
set <REPEATER> setRepeat <Channel> <Sensor/Aktor> <IO> no
http://www.fhemwiki.de/wiki/HM-Sys-sRP-Pl_Funk-Zwischenstecker_Repeater
Das FHEM-wiki empfiehlt den Einsatz einer VCCU, da ich nur einen einzigen Aktor schalten möchte, habe ich diesen Schritt übersprungen. Bisher hatte ich keine Probleme , aber hier die Anleitung zu erstellen einer solchen:
http://www.fhemwiki.de/wiki/Virtueller_Controller_VCCU
Ohne VCCU sieht meine Einbindung des HM-LC-SW1-FM in den Repeater (Kanal 1) dann also so aus:
set Mein_Repeater_1 setRepeat 1 NachbarLicht HMLAN1 no
Den Aktor für das Nachbargrundstück kann ich jetzt problemlos über das FHEM erreichen, mit unseren
eigenen, vorhandenen Handsendern koppeln und auch im Floorplan einbinden.
Mit Repeater überbrücke ich problemlos eine Funkstrecke von ca. 33m Luftlinie mit 3 Wänden dazwischen.
Nie wieder Arbeit im dunkeln !
Email mit FHEM versenden
-
Email versenden mit FHEM
Mein FHEM kann Emails versenden - z.B. zur Erinnerung, wenn die Mülltonne an die Strasse gestellt werden muß. Diese Email kann z.B. auch auf dem Handy ausgewertet werden. Hierfür benutze ich die Anroid- pp "Tasker". Der Tasker kann z..B. die Betreffzeile einer email auswerten und daraufhin eine App starten.
Auf meinem NUC-FHEM-Server läuft ein Linux Mint, gleiche Anleitung gilt für Ubuntu, Raspbian, usw.
Siehe auch: FHEM Wiki Email senden
Auf dem FHEM-Serversystem muß zunächst einmal "sendemail" installiert werden:
Code: [Auswählen]sudo apt-get update
sudo apt-get install sendemail libio-socket-ssl-perl libnet-ssleay-perl perlAchtung: Bei älteren Distributionen wird das "sendemail" evt. mit großem "E", also "sendEmail" geschrieben.
In die 99_myUtils.pm habe ich folgendes eingetragen:
Code: [Auswählen]######## DebianMail Mail versenden ############
sub
DebianMail
{
my $rcpt = shift;
my $subject = shift;
my $text = shift;
my $attach = shift;
my $ret = "";
my $sender = "absender\@meinedomain.de";
my $konto = "absender\@meinedomain.de";
my $passwrd = "mein_passwort";
my $provider = "smtp.mein_provider.de";
Log 1, "sendemail RCP: $rcpt";
Log 1, "sendemail Subject: $subject";
Log 1, "sendemail Text: $text";
Log 1, "sendemail Anhang: $attach";
$ret .= qx(sendemail -f '$sender' -t '$rcpt' -u '$subject' -m '$text' -a $attach -s '$provider' -xu '$konto' -xp '$passwrd' -o tls=auto -o message-charset=utf-8);
$ret =~ s,[\r\n]*,,g; # remove CR from return-string
Log 1, "sendemail returned: $ret";
}Der Aufruf erfolgt im FHEM so:
Code: [Auswählen]{ DebianMail('meine_email@meine_domain.de','Betreff','Email_Text');;}
Offline-Sprachsteuerung mit MOVI und Arduino
-
Offline-Spracherkennung mit Arduino-MOVI Shield und Steuerung von FHEM
Für den Arduino gibt es eine „offline Spracherkennung“ - das MOVI-Shield von Audeme.
Hiermit habe ich mir eine „cloudfreie“ Offline-Alexa für FHEM gebastelt.
Hier ein kleines Video der "pre-alpha"mit einem Pi2, die wohnt noch in einem Eierkarton:
Und hier der erste Versuch der Integration in ein Gehäuse (aka "alte Lautsprecherbox") - meine "Gehäuseversion 1":
Die Zutaten:
Ein Raspberry Pi (am besten die Version 3, weil da das WLAN gleich mit „an Bord“ ist), ein Arduino
(ich habe mich für den MEGA 2560 R3 entschieden) und natürlich das MOVI-Shield.
Die Vorbereitung:
Zunächst muss das Betriebssystem des Raspberry Pi auf eine SD-Karte. Am einfachsten geht das mit Noobs: herunterladen, das ZIP-Archiv entpacken und den Inhalt einfach auf eine leere SD-Karte schieben. Wenn diese dann in den PI gesteckt wird, kann der damit booten und man wird durch die Installation des Betriebssystems geführt. WLAN, IP-Adressen festlegen, usw. geht mittlerweile auch bei Raspbian ohne „Konsole“ direkt aus der grafischen Oberfläche heraus.
Das MOVI-Shield wird auf den Arduino gesteckt und es muß noch ein Jumper entsprechend der eingesetzten Arduino-Version gesetzt werden. Wie das Jumper-Setting ist und welche Arduino-Boards und Klone kompatibel sind, entnehmt Ihr am besten der Anleitung des Herstellers:
https://www.audeme.com/downloads.html
Da die SD-Karte des MOVI-Boards Hardware-spezifische und proprietäre Programmteile enthält, empfiehlt der Hersteller die zu klonen. Bei Ausfall der SD-Karte ohne existierendes Backup müsste der MOVI ansonsten zum Hersteller eingeschickt werden.
Wenn die SD-Karte des MOVI schonmal im Rechner steckt: auf die „Update“-Partition werden das ebenfalls herunterladbare Firmeware-Update sowie – falls gewünscht – das Deutsche Sprachpaket geladen. Auch hierzu: siehe Anleitung des Herstellers.
Der Ardunio muß eine kräftige Stromversorgung bekommen, ansonsten bootet der MOVI nicht. Ein 5V-USB-Netzteil ist nicht ausreichend!
Der Arduino wird über USB mit dem PI verbunden.
Die Verkabelung (inkl. Realtime-Clock, dazu weiter unten mehr) ist im Bild gut zu erkennen. Es handelt sich hierbei um meine "Gehäuseversion IV":
Die "Technik" kann hinter einem Schrank oder auf einem Regal verschwinden, nur der Lautsprecher und das 360°-Mikro (das ist der kleine "Hut" auf dem Lautsprecher) sind sichtbar. Ein winziges "Frontend" sozusagen:
Zurück zur Software:
um schnell meinen Arduino-Sketch auf alle Pis zu bekommen, habe ich die aktuelle Arduino IDE auf den Pi geladen. Die IDE in den Repositories des Pi ist leider stark veraltet. Ihr müsst Euch also die aktuelle IDE für ARM herunterladen:
https://www.arduino.cc/en/Main/Software
Im Verzeichnis, wo Ihr die zip-Datei entpackt habt, gibt es jetzt ein Installationsscript.
Um die IDE zu installieren, muß man dieses Script ausführen:
sudo ./install.sh
Um die "headless" Pis mit den daran angeschlossenen Arduinos zu bedienen, habe den RDP-Server XRDP installiert.
Achtung: vorher muß der RealVNC-Server runter - die beiden beissen sich:
sudo apt-get purge realvnc-vnc-server sudo apt-get update sudo apt-get install xrdp
Zuletzt muß im aktuellen Raspbian noch ssh aktiviert werden. Dass kann man über die GUI erledigen:
Einstellungen --> Raspberry-Pi-Konfiguration --> Schnittstellen
Mit "passwd" dann im Terminal noch ein eigenes Passwort setzen. Es wird nach dem bisherigen Passwort gefragt, das ist per default "raspberry".
Jetzt kann man mit einem RDP-Client (unter Linux benutze ich Remmina) auf das Desktop des PIs und auf die Arduino-IDE zugreifen.
Achtung: es wird - anders als bei klassischer Fernwartung - für die RDP-Sitzung ein eigenes Desktop aufgemacht.
Das MOVI-Shield braucht jetzt noch die Libraries (Download beim Hersteller), diese werden in der Arduino IDE direkt als zip-Datei unter Sketch –> Bibliothek einbinden geladen.
Mit der MOVI-Bibliothek werden gleich einige Beispiel-Sketche installiert. Ich empfehle den „LightSwitch“ (Beispiele → Movi(tm)VoiceDialogShield → beginner → LightSwitch). Diesen habe ich geladen und nach und nach ausgebaut.
Es gibt für den MOVI ein Deutsches Sprachpaket, man muß aber sehr viel "phonetisch umschreiben" und die Erkennung ist nicht so präzise wie auf Englisch. Zudem kann der Synthesizer keine Umlaute aussprechen und sowohl bei der Erkennung als auch bei der Aussprache von z.B. "Küche" hatte ich arge Schweirigkeiten. Nach langen Versuchen habe ich mich für Englisch entschieden - hier klappt die Erkennung deutlich besser. Ich habe bei mir die weibliche Stimme eingestellt. Das Callsign ist frei wählbar - mein MOVI hört auf "Moneypenny".
Das "Einlernen" neuer Sätze denkbar einfach. Über die Arduino-IDE im MOVI-Sketch einfach eintragen und hochladen:
Für die Erkennung:
recognizer.addSentence("Aussenlicht an"); // Add German sentence 8
und für das Sprach-Feedback:
if (res==8) { // Sentence 8 recognizer.say("Die Aussenbeleuchtung ist jetzt eingeschaltet!"); // Respond a sentence in German }
Anbindung an FHEM:
Auf dem frisch Installierten PI muß ein FHEM installiert werden.
Die Vorbereitung:
sudo apt-get update && sudo apt-get -y upgrade && sudo reboot
sudo apt-get -f install && sudo apt-get -y install perl-base libdevice-serialport-perl libwww-perl libio-socket-ssl-perl libcgi-pm-perl libjson-perl sqlite3 libdbd-sqlite3-perl libtext-diff-perl libtimedate-perl libmail-imapclient-perl libgd-graph-perl libtext-csv-perl libxml-simple-perl liblist-moreutils-perl ttf-liberation libimage-librsvg-perl libgd-text-perl libsocket6-perl libio-socket-inet6-perl libmime-base64-perl libimage-info-perl libusb-1.0-0-dev libnet-server-perl
Die Installation:
sudo wget http://fhem.de/fhem-5.8.deb && sudo dpkg -i fhem-5.8.deb
Folgende Schritte sind auf dem Client-Pi notwendig:
Den Arduino habe ich als „JeeLink“-Device im FHEM angelegt.
define myArduino1 JeeLink /dev/ttyACM0@9600 attr myArduino1 event-on-change-reading .*
Der Client wird dann im Haupt-FHEM als FHEM2FHEM-Device angelegt.
Im „Haupt“-FHEM:
Wie hier beschrieben: https://forum.fhem.de/index.php/topic,25399.msg183910.html#msg183910
wird im Linux -Terminal meines (Haupt)FHEM-Servers eine "named pipe“ gesetzt:
mkfifo /tmp/jdummy
Dann wird ein JeeLink dummy angelegt:
define myArduino1 JeeLink /tmp/jdummy@directio attr myArduino1 event-on-change-reading .*
Achtung: es muß tatsächlich „directio“ heissen – ohne „n“
Jetzt kommt das FHEM2FHEM device:
define remotepi1 FHEM2FHEM IP_meines_Client_PI:7072 LOG:.*
Bei Aktivität des Movi werden jetzt folgende Readings im JeeLink dummy "myArduino1" erzeugt:
(Im Beispiel sage ich „Homeoffice on“, der MOVI-Sketch für den ARDUINO muß natürlich geladen sein):
UNKNOWNCODE MOVIEvent[140] ACTIVELISTEN 2018-02-10 19:40:46 UNKNOWNCODE MOVIEvent[141] END ACTIVELISTEN 2018-02-10 19:40:50 UNKNOWNCODE MOVIEvent[150] SPEAKING 2018-02-10 19:40:52 UNKNOWNCODE MOVIEvent[151] END SPEAKING 2018-02-10 19:40:59 UNKNOWNCODE MOVIEvent[200] CALLSIGN DETECTED 2018-02-10 19:40:46 UNKNOWNCODE MOVIEvent[201] HOMEOFFICE ON 2018-02-10 19:40:51 UNKNOWNCODE MOVIEvent[202] #7 2018-02-10 19:40:52
Das MOVI-Shield vergibt die Satznummern nach der Reihenfolge im Sketch. Der erste Satz heisst "#0", der Zweite "#1", usw.
Mit
attr myArduino1 stateFormat { ReadingsVal("myArduino1","UNKNOWNCODE MOVIEvent[202]",0);; }
setze ich den Status des JeeLink dummies auf diese Satznummer, im Beispiel die "#7"
Ein DOIF kann jetzt auf diese Satznummer reagieren:
define ARD1 DOIF ([myArduino1:"#7"]) (set Arbeitszimmer1 on,set Arbeitszimmer2 on) DOELSEIF ([myArduino1:"#8"]) (set Arbeitszimmer1 off,set Arbeitszimmer2 off) attr ARD1 do always
Die Anbindung weiterer Pis mit Arduino+Movishield für die Spracherkennung in weiteren (Ziel: in allen!) Räumen ist sehr einfach:
Wie oben beschrieben könnt Ihr Euch weitere Pi/MOVI-Kombinationen zusammenbauen.
Zur Vereinfachung habe ich mir eine SD-Karte mit einer fertigen Installation geklont. So brauche ich diese nur in weitere Pis zu stecken und die IP zu ändern, der Rest passiert dann wie beschrieben per RDP.
Auf dem "Haupt-FHEM" muß dann nur ein weiteres FHEM2FHEM-Device für jeden zusätzlichen MOVI-Pi angelegt werden:
define remotepi2 FHEM2FHEM IP_meines_2tenPI:7072 LOG:.* define remotepi3 FHEM2FHEM IP_meines_3ten_PI:7072 LOG:.* ... ...
Da alle Pis die gleichen Readings erzeugen, triggern alle für den MOVI angelegten DOIFS auf alle Pis.
Den Arduino-Sketch und die Libraries schiebe ich per Filezilla auf die Pis und binde sie dann per Arduino IDE ein. So kann ich schnell etwas ändern und diese Änderung allen Client-MOVIs mitteilen.
Wichtige Tipps:
1) Wenn das FHEM auf dem Client-Pi an der USB-Schnittstelle „lauscht“ ist diese blockiert.
Es gibt in der Arduino-IDE dann eine Fehlermeldung beim Upload eines neuen oder geänderten Sketches. Abhilfe: im FHEM des Clients muß das JeeLink-Device kurzfristig auf eine andere Schnittstelle. IM FHEM-web auf das Device klicken und bei „DEF“ z.B. /dev/ACM0@9600 in /dev/ACM1@9600 ändern. Der state wechselt dann auf „disconnected“ und dann funktioniert der Sketch-Upload.
2) Wenn irgendetwas im Sketch geändert wurde und/oder die Schnittstelle wie in Punkt 1 beschrieben kurzzeitig geändert wurde, dann braucht das FHEM2FHEM -Device im Haupt-FHEM ein „set remotepi1 reopen“. Wenn man mehrere Cleints geändert hat, ist es natürlich mühsam, das bei jedem einzelnen auszuführen. Also habe ich mir einen „pi-reopen“ dummy gebaut. Ein DOIF triggert auf diesen dummy führt den Befehl dann auf allen FHEM2FHEM-Pis aus:
define pi_reopen dummy attr pi_reopen setList on off define pi_reopen_act DOIF ([pi_reopen:"on"]) (set remotepi1 reopen,set remotepi2 reopen,...,set pi_reopen off) attr pi_reopen_act do always
3) Der MOVI verfügt über ein "LowLevel Interface". Damit kann man z.B.die Systemmeldungen ("there is a lot of noise in the room") abstellen oder den Mikrofon-Threshold für die optimale Erkennung einstellen. Der Hersteller hat dafür einen eigenen Sketch bereitgestellt. Wenn man diesen Sketch hochlädt, kann man das LowLevel-Interface über den Seriellen Monitor der Arduino IDE bedienen. Es geht aber auch viel einfacher: man kann einfach über das Terminal des Pis darauf zugreifen:
echo "SYSTEMMESSAGES OFF" > /dev/ttyACM0
oder über die FHEM-Kommandozeile:
{system("echo SYSTEMMESSAGES OFF > /dev/ttyACM0")}
Die Systemrückmeldungen werden im Event Monitor von FHEM angezeigt. "HELP" gibt eine Liste der möglichen Befehle aus.Für diese Variante muß der PI nichtmal "disconnected" werden (wie in Punkt 1 beschrieben)
Uhrzeit und Datum ansagen lassen:
Für ganz kleines Geld gibt es eine "Real-Time-Clock" für den Arduino.
Hier gibt es einen Beitrag, der die Installation beschreibt:
https://www.instructables.com/id/Voice-Controlled-Clock-With-Arduino-no-WiFi-No-PC/
Ich habe die dazugehörige library hier heruntergeladen: https://github.com/adafruit/RTClib
und per
#include "RTClib.h"
in den Arduino Sketch eingebunden. Die Zeilen des Uhrzeit-Sketches habe ich in meinem Sketch integriert.
Um die Uhr zu stellen, muß der PI die richtige Zeit wissen:
sudo dpkg-reconfigure tzdata
Im Sketch muss für das Stellen der Uhrzeit kurzfristig die Auskommentierung einer Zeile entfernt werden.
Damit stellt sich die Uhr und wenn das einmal geschehen ist, kann die Zeile wieder auskommentiert werden:
// Comment out the first time to set the time and date on the RTC module. After this, // it will remember it via it non-volatile memory. // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
Ich kann den MOVI jetzt also nach Uhrzeit und Datum fragen, einen Timer für die Frühstückseier setzen, usw.
Hier ein Demo-Video meiner zweiten Moneypenny-Version - diesmal mit Pi3 inkl. Lautsprecher und Mikro im Gehäuse
eines alten Kabelmodems - das war meine "Gehäuseversion III":
Steuerung meiner Multiroom-Lautsprecher (FHEM/Squeezebox):
Mit der MOVI-Library werden verschiedene Beispiel-Sketche angeboten, u.a. der "NestedDialog".
(In der Arduino IDE zu finden unter "Beispiele-->MOVI(tm)Voice Dialog Shield--> intermediate--> NestedDialog").
Hiermit kann ich z.B. folgenden Dialog erreichen:
Ich: "Moneypenny, spiele Musik!"
Moneypenny: "welchen Spieler möchtest Du?"
Ich:"Badezimmer!"
Moneypenny: "Welche Playliste oder welchen Sender soll ich spielen?"
Ich: "Latina!"
Moneypenny: "Ich spiele jetzt Radio Latina auf dem ausgewählten Player!"
Ich habe also das Beispiel "NestedDialog" zusätzlich in meinen Sketch eingebaut.
Wie weiter oben beschrieben, triggern meine DOIFs im Haupt-FHEM ja auf die eindeutigen Satznummern,
die kommen beim "NestedDialog" nicht vor.
Also habe ich hier eine Umleitung gebaut: die Player-DOIFs reagieren auf eine Variable:
"#8" für Musik, zweite Stelle für den Player, dritte Stelle für die Playlist.
Also: Event "#821" = Musik, Player 2, Playlist 1.
Mit
Serial.println
im MOVI-Sketch übergebe ich das "Reading" an das Haupt-FHEM.
Anders ausgedrückt:
Moneypenny: "welchen Spieler möchtest Du?"
Ich:"Badezimmer!" --> Variable Player wird gesetzt
Moneypenny: "Welche Playliste oder welchen Sender soll ich spielen?"
Ich: "Latina!" --> Variable Playlist wird gesetzt
Moneypenny: "Ich spiele jetzt Radio Latina auf dem ausgewählten Player!"
Im Arduino-Sketch sieht das im Wesentlichen so aus:
// choose Player if (context==BOOT) { // MOVI just started if (res==20) recognizer.ask(F("What Player do you choose?")); context=PLAYER; sbp=0; } if (context==PLAYER) { if (res==45) { // player living room recognizer.say(F("player living room choosen")); recognizer.ask(F("What Playlist or Station do you choose?")); context=PLAYLIST; sbp=1; } if (res==46) { // player kitchen recognizer.say(F("player kitchen choosen")); recognizer.ask(F("What Playlist or Station do you choose?")); context=PLAYLIST; sbp=2; } if (res==47) { // player bathroom recognizer.say(F("player bathroom choosen")); recognizer.ask(F("What Playlist or Station do you choose?")); context=PLAYLIST; sbp=3; } if (res==48) { // player outside recognizer.say(F("player outside choosen")); recognizer.ask(F("What Playlist or Station do you choose?")); context=PLAYLIST; sbp=4; } if (context==PLAYLIST) { if (res==50) { // NDR2 recognizer.say(F("I am now playing ND R2 on the selected player")); context=BOOT; playlst=1; String Au1=String (sbp,DEC); String Au2=String (playlst,DEC); String Au4=Au3+Au1+Au2; Serial.println(Au4); } if (res==51) { // LATINA recognizer.say(F("I am now playing LATINA on the selected player")); context=BOOT; playlst=2; String Au1=String (sbp,DEC); String Au2=String (playlst,DEC); String Au4=Au3+Au1+Au2; Serial.println(Au4); } if (res==52) { // Barbaras Liste recognizer.say(F("I am now playing Barbaras Playlist on the selected player")); context=BOOT; >playlst=3; String Au1=String (sbp,DEC); String Au2=String (playlst,DEC); String Au4=Au3+Au1+Au2; Serial.println(Au4); } f (res==53) { // Jochens Liste recognizer.say(F("I am now playing Jochens playlist on the selected player")); context=BOOT; playlst=4; String Au1=String (sbp,DEC); String Au2=String (playlst,DEC); String Au4=Au3+Au1+Au2; Serial.println(Au4); }
Und so sieht das passende DOIF im Haupt-FHEM aus:
define play22 DOIF[ ([myArduino1:state] =~ "#822") (set JNSKuechePower on,set Kueche on,set Kueche playlist play latina) attr play22 do always
Natürlich sind weitere Befehle wie Sync. und Lautstärke möglich, soweit bin ich aber noch nicht.
Ansage des Wetters:
Der MOVI kann in zwei Richtungen kommunizieren. Ich kann über:
{system("echo SAY test > /dev/ttyACM0")}
vom FHEM des jewiligen MOVI-Pis einen Text (hier "test") vorlesen lassen.
Da auch eine "offline-Alexa" über das Wetter informieren können muß, habe ich folgendes gemacht:
Achtung: das passiert alles im FHEM des/der Movi-Pi(s), nicht im Haupt-FHEM
Ich habe ein "Weather" - device angelegt: https://wiki.fhem.de/wiki/Weather
define MeinWetter Weather 676378 3600 de
Da Moneypenny noch Englisch spricht, habe ich das "de" weggelassen. Euren Städtecode bekommt ihr wie im Wiki beschrieben.
Dann:
define forecast dummy
Diesen dummy kann ich schonmal mit den Readings aus dem Weather-Device plus etwas Zwischentext befüllen:
{ fhem("set forecast " ."The weather in ".(ReadingsVal("MeinWetter","city",0)." today is ". ReadingsVal("MeinWetter","condition",0)).". The temperature currently is ". ReadingsVal("MeinWetter","temp_c",0)." degrees celsius. The forecast for tomorrow will be ".ReadingsVal("MeinWetter","fc2_condition",0)." and a maximum temperature of ".ReadingsVal("MeinWetter","fc2_high_c",0)." degrees celsius. ") }
Merkwürdigerweise konnte ich nicht direkt in einem DOIF auf ein "MOVI-Event" reagieren, die "system"-Ausgabe gibt den Wert "-1" zurück und damit macht das DOIF (oder ich?) einen Fehler. Egal, über den Umweg dummy+notify geht es:
define wetterdummy dummy attr wetterdummy setList on off define wspeech_on notify wetterdummy:on {my $wetter = ReadingsVal("forecast","state",0);;system("echo SAY $wetter > /dev/ttyACM0")}
Im Arduino Sketch passiert bei Anfrage nach dem Wetter folgendes:
If (res==54) { // Sentence 53 digitalWrite(led, HIGH); // Turn on LED Serial.println("wetter"); // Ausgabe wetterdummy on Serial.println("..."); // Ausgabe wetterdummy off digitalWrite(led, LOW); //Turn off LED
Im FHEM reagiert ein DOIF darauf:
define forecast_act DOIF ([myArduino1:&RAWMSG] =~ "wetter") (set wetterdummy on) DOELSEIF ([myArduino1:&RAWMSG] =~ "...") (set wetterdummy off) attr forecast_act do always
Und damit das Wetter immer schön aktuell bleibt, wird der dummy "forecast" bei Aktualiserung des Devices "MeinWetter" neu befüllt:
define wetteraktuell notify MeinWetter.* { fhem("set forecast " ."The weather in ".(ReadingsVal("MeinWetter","city",0)." today is ". ReadingsVal("MeinWetter","condition",0)).". The temperature currently is ". ReadingsVal("MeinWetter","temp_c",0)." degrees celsius. The forecast for tomorrow will be ".ReadingsVal("MeinWetter","fc2_condition",0)." and a maximum temperature of ".ReadingsVal("MeinWetter","fc2_high_c",0)." degrees celsius. ") }
Gestensteuerung mit dem APDS-9960 Sensor
-
Gestensteuerung mit dem APDS-9960 Sensor
Im Internet bin ich auf ganz einfache Möglichkeit der Gestenerkennung gestossen:
https://www.youtube.com/watch?v=d8txEBNaTw0
Den Sensor "APDS-9960" gibt es für kleines Geld zu kaufen. Er wird an einen Arduino angeschlossen.
Achtung: VCC muss an den 3,3V-Anschluss, nicht an 5V !
Hier gibt es den Anschlussplan und bei GitHub die Arduino-Libraries inklusive Beispiel Sketch.
Im Beispiel-Sketch reagiert der Sensor auf Hand rauf/runter,links/rechts und weit/nah.
Ich habe das Ganze in FHEM eingebunden wie im Abschnitt "Offline-Sprachsteuerung mit MOVI und Arduino" beschrieben.
Also Arduino-->Pseudo-Jeelink-Device im FHEM auf Raspberry PI --> FHEM2FHEM
Im FHEM-Eventmonitor tauchen jetzt die Handbewegungen auf:
UNKNOWNCODE" gefolgt von "UP","DOWN","LEFT","RIGHT","NEAR" oder "FAR" - je nach Handbewegung.
Darauf kann ein DOIF triggern:define LightstripsAus DOIF ([myArduino1:state] eq "UNKNOWNCODE DOWN")(set HUEDevice6 off)
Zum Test habe ich mal eine Stehlampe auf "Hand links/rechts" und einen Lightstrip auf "Hand hoch/runter" gelegt.
Hier ein kleines Video dazu:
Ein weiteres Anwendungsbeispiel für die Gestenerkennung: die Steuerung meiner Squeezebox-Player
Ich habe im setup-Teil des Gesten-Sketches zwei Variablen cud und clr (soll heissen: counter up/down bzw. counter links/rechts)
sowie zwei Strings "UD" und "LR" (für up-down und left-right) angelegt:int cud = 0;
int clr = 0;
String S1 = "UD";
String S2 = "LR";Dann im loop-Teil:
// Handgeste hoch-runter
case DIR_UP:
cud = cud+1;
if (cud >5) {
cud=5;
}
Serial.println(S1+cud);
break;
case DIR_DOWN:
cud =cud-1;
if (cud <0) {
cud=0;
}
Serial.println(S1+cud);
break;
// Handgeste links-rechts
case DIR_LEFT:
clr = clr-1;
if (clr <0) {
clr=5;
}
Serial.println(S2+clr);
break;
case DIR_RIGHT:
clr = clr+1;
if (clr >5) {
clr=0;
}
Serial.println(S2+clr);
break;Die Handbewegungen hoch runter werden also in der Variable "cud" hoch bzw. runtergezählt. Im Beispiel ist bei "5" nach oben und "0" nach unten Schluss.
Bei Handbewegung links/rechts wird in "clr" gezählt, bei "<0" springt die Variable auf "5" und bei ">5" wieder auf "0"
Der Arduinio gibt bei Hand rauf/runter also String S1+cud aus, also z.B. "UNKNOWNCODE UD4".
Bei Hand links/trechts entsprechend String S2+clr, also z.B. "UNKNOWNCODE LR3".
Jetzt kommen die DOIFs im FHEM:
Hand links/rechts "winkt "die Sender oder playlisten meines players "Arbeitszimmer" durch:define Senderwahl0 DOIF ([myArduino1:state] eq "UNKNOWNCODE LR0") (set Arbeitszimmer playlist play latina)
define Senderwahl1 DOIF ([myArduino1:state] eq "UNKNOWNCODE LR1") (set Arbeitszimmer playlist play Radio538)
define Senderwahl2 DOIF ([myArduino1:state] eq "UNKNOWNCODE LR2") (set Arbeitszimmer playlist play NDR2)
...und die rauf/runter-Handbewegung steuert die Lautstärke:
define Lautstaerke0 DOIF ([myArduino1:state] eq "UNKNOWNCODE UD0") (set Arbeitszimmer volume 10)
define Lautstaerke1 DOIF ([myArduino1:state] eq "UNKNOWNCODE UD1") (set Arbeitszimmer volume 20)
define Lautstaerke2 DOIF ([myArduino1:state] eq "UNKNOWNCODE UD2") (set Arbeitszimmer volume 30)Das An-und Ausschalten des players übernimmt die Funktion "FAR". Auf die Auswertung von "NEAR" habe ich verzichtet, dann muss man sich keine Mühe geben, die Entfernung zum Sensor abzuschätzen.
Ich habe sozusagen ein "Toggle" auf "FAR" gesetzt. Will heissen:
Hand Richtung Sensor und wieder weg: Player an
Hand Richtung Sensor und wieder weg: Player ausUnd so geht's:
wieder habe ich im setup-Teil eine Variable gesetzt:
int onoff =0;
Und dann im loop ("NEAR" ist wie gesagt auskommentiert und somit deaktiviert):
// case DIR_NEAR:
// Serial.println("NEAR");
// break;
case DIR_FAR:
onoff=onoff+1;
if (onoff >1) {
onoff=0;
Serial.println("PLR_OFF");
}
else if (onoff =1) {
Serial.println("PLR_ON");
}
break;Das passende FHEM-DOIF reagiert dann wie oben beschrieben auf "UNKNOWNCODE PLR_ON" bzw. "PLR_OFF".
Damit kann die Gestensteuerung eines Squeezebox-Players "stand-alone" erfolgen - das funktioniert prima!
Ich habe mir ein 20x4 Display und ein passendes Gehäuse bestellt,
damit kann dann der Sendername und die Lautstärke angezeigt werden.
Dank WLAN kann dieses Squeezebox-Bedienteil überall im Haus aufgestellt werden.
Das ganze könnte z.B. auch den TV steuern. Oder Hue-Farben "durchwinken"... Die private Alexa - ein Hut für den Echo-Dot
-
Die private Alexa - eine Abwandlung des "Projekt Alias"Wir leben jetzt eine ganze Zeit mit Moneypenny zusammen (Beschreibung siehe weiter oben) und die Sprachsteuerung klappt auch sehr gut. Der Nachteil einer "offline"-Sprachsteuerung ist natürlich, dass sie "offline" ist. Fragen nach Zugverbindung, Stau, "wie hiess der letzte Kaiser von China" funktionieren so natürlich nicht.
Cloudlösungen von Amazon oder Google können da deutlich mehr, sind aber natürlich "Wanzen" - wie schlimm oder nicht, das mag jeder für sich selbst beurteilen.
Im Internet bin ich jetzt auf diese nette Bastellösung gestoßen: https://www.instructables.com/id/Project-Alias
Im wesentlichen ist das ein Deckel, der auf ein Google oder Amazon-Gerät gesetzt wird. Der Deckel enthält einen Pi, ein Mikrofon-Shield und zwei kleine Lautsprecher. Per selbst definiertem "Triggerword" flüstern diese Lautsprecher "ALEXA" (oder "OK Google") in das Gerät und aktivieren so Alexa (oder Google). Wenn das Triggerword nicht fällt, kommt aus den Lautsprechern ein "Stimmengemurmel" und Alexa oder Google versteht nur noch Bahnhof.
Das Ganze ist so leise, dass man es von Aussen nicht hört und die "Wanze" ist somit abgeschaltet.
Ich bin eigentlich komplett gegen Cloudlösungen aber ich habe mir gedacht, damit könnte ich leben und habe das Projekt nachgebaut.
Ich bin dabei aber nicht so richtig glücklich geworden. Das Triggerword wird per Keras "Deep-Learning" eingelernt. Das ist sehr komplex und man muß v.a. auch negativ-Beispiele (z.B. Hintergrundgeräusche) einlernen. Das Ding triggert bei allen möglichen Geräuschen (gelegentlich auch bei "Alexa") und dann sagt es "Alexa" gerne 2 oder 3 mal und würgt damit die Alexa-Aktion damit ab. Kurz: ich habe keine stabile Triggerworderkennung hinbekommen.Daraufhin habe ich mich mal mit Snips beschäftigt - das ist eine offline-Sprachsteuerung für die es viele fertige "Skills" gibt, aber für die man auch eigene Skills anlegen kann.
Ich habe mich auf die bloße Erkennung des Hotwords beschränkt so wie hier für eine Steuerung von Funksteckdosen beschrieben: https://medium.com/snips-ai/voice-controlled-lights-with-a-raspberry-pi-and-snips-822e53d7ede6
Die entsprechenden Scripte habe ich dann etwas abgewandelt.
Aber zunächst zur Hardware:
Die 3D-Druckdateien für den Deckel und den Lautsprecher-Halter gibt es auf der instructables Seite des Alias-Projektes zum Download. Da ich keinen 3D-Drucker besitze, habe ich diese bei einem 3D-Druckdienst im Internet bestellt. Ich habe das billigste Material (PA12) genommen - ist sehr stabil. Beim Lautsprecher-Halter sagt mein Druckdienstleister "zu dünn, auf eigene Gefahr" - der Halter ist aber absolut in Ordnung.
Ich habe den Deckel auf dem Echo-Dot (Version 2) gesetzt.Also: Deckel, Lautsprecherhalter, 2 kleine 16mm-Lautsprecher, usw. alles wie auf https://www.instructables.com/id/Project-Alias/
Im Gegensatz zum "Project Alias" benutze ich keinen Pi A+ sondern einen Pi3 B+ (Snips scheint auf der CPU des kleinen A+ nicht zu laufen, aber nicht wegen der Leistung sondern wegen irgendwelcher Bibliotheken). Der große PI passt natürlich nicht in den gedruckten Deckel. Lediglich die Lautsprecher an dem dafür vorgesehenen 3D-gedrucktem Plastikgestänge befinden sich im Deckel und ein Zuleitungskabel führt hinein.
Die Lautsprecher decken 2 der 6 Mikrofone ab, das reicht, um Alexa zu verwirren. Ich habe die Lautsprecherhalterung aber direkt auf die Mikros geklebt, damit Alexa auch wirklich nichts hört.Die beiden wav-files "noise.wav" und "alexa.wav" (download auf der github-Seite vom Projekt Alias) befinden sich auf der SD-Karte eines MWP1 - das ist ein winziger stand-alone-wav-player mit mit einem ebenso winzigen Audio-Verstärker (einfach mal googeln). Der MWP1 kann bis zu acht verschiedene wav-files spielen, indem man bestimmte Logik-Eingänge des players auf Masse legt.
Das Script snips_handler.py der Funksteckdosenlösung habe ich so abgewandelt, dass es (mithilfe von zwei "Subprozessen")
die GPIO des PIs ansteuert und so die Pins des wav-players entsprechend des gewünschten wavs auf Masse legt. Realisiert habe ich das mit einem NPN-Transistor (z.B. BC546), dessen Basis an der GPIO hängt und der dann bei "High"-Signal den Logikeingang des MWP1 auf Masse zieht.
Die Versorgungsspannung des Players hängt direkt an 5V der GPIO, die Masse an GPIO-Masse. Es ist also keine eigene Stromversorgung erforderlich.
Den Lautsprecherausgang des MWP1 habe ich mit einem 1kOhm Potentiometer noch etwas runtergeregelt - bis an die Schwelle, wo der Echo nicht mehr auf "Alexa" hört. Man soll ja schließlich von aussen nicht hören, was unter dem Deckel passiert.
Zur Installation:
1) Der Pi:
auf meinem PI läuft ein Raspian full. Mit XRDP kann ich per Netzwerk auf dessen GUI und kann alles bedienen
2) Das Mikrofon:
Ihr benötigt ein Mikrofon. Im Gegensatz zur alten Moneypenny benutze ich jetzt ein USB-Array-Mikrofon (das kann Sound-Richtung und Sound-Entfernung erkennen und ist ähnlich präzise wie das Mikrofon von Alexa. Ich benutze versuchweise ein ReSpeaker MicArray v2.0, habe aber gelesen, dass es ähnlich gut und deutlich günstiger mit dem Mikrofon einer PS3 Eye Kamera (ab 9€) funktionieren soll...
Das Mikro ist im wesentlichen eine zusätzliche "Soundkarte", die sich aber plug&play beim Einstecken in den USB-Port des Pis installiert.
aplay -l
zeigt Euch alle verfügbaren Abspiel-Geräte an
und
arecord -l
alle verfügbaren Aufnahmegeräte.
Die gefundenen Gerät müssen jetzt noch in der Datei /etc/asound.conf verewigt werden.
sudo nano/etc/asound.conf
So sieht das bei mir aus:
pcm.!default {
type asym
playback.pcm {
type plug
slave.pcm "hw:0,0"
}
capture.pcm {
type plug
slave.pcm "hw:1,0"
}
}3) Die Konfiguration des Snips ist im Artikel hier komplett beschrieben, es gibt aber eine Änderung. Der genannte Schlüsselserver ist nicht erreichbar - man muß also einen alternativen Server verwenden.
Die komplette Konfiguration für alle benötigten Snips-Dienste für die Erkennung eines Hotwords muss dann also so lauten:
cd
sudo apt-get install -y dirmngr
sudo bash -c 'echo "deb https://raspbian.snips.ai/$(lsb_release -cs) stable main" > /etc/apt/sources.list.d/snips.list'
sudo apt-key adv --keyserver pgp.surfnet.nl --recv-keys D4F50CDCA10A2849
sudo apt-get update
sudo apt-get install -y mosquitto
sudo apt-get install -y snips-audio-server
sudo apt-get install -y snips-hotword git clone https://github.com/snipsco/snips-record-personal-hotword.gitcd snips-record-personal-hotword/
sudo apt-get install -y python-numpy python-pyaudio python-soundfile
sudo apt-get install -y snips-platform-voicemit
sudo systemctl stop snips-audio-server; python script_recording.py <your_hotword_name>
nehmt Ihr dann Euer hotword auf - das ganze legt einen Ordner im Verzeichnis
/home/pi/snips-record-personal-hotword/
an
Testen könnten Ihr Euer Hotword mit
sudo systemctl stop snips-hotword; sudo systemctl start snips-audio-server;
snips-hotword --model<path_to_your_model>=<sensitivity>Die sensitivity sollte bei 0.5 (default) oder 0.6 liegen - je höher, desto empfindlicher
Wenn alles läuft, erstellt Ihr das Verzeichnis /etc/snips und kopiert den soeben erstellten Ordner hinein:
sudo mkdir -p /etc/snips
sudo mv /home/pi/snips-record-personal-hotword/personal_2019_xx_xxxxxx /etc/snipsDann edtiert Ihr die Konfig-Datei /etc/snips.toml und legt den link zu Eurem Ordner unter "model" an. Den Hashtag vor "model" müsst Ihr vorher entfernen:
model = ["/etc/snips/personal_2019_xx_xxxxxx=0.5"]
Der Wert "=0.5" ist Eure sensitivity, könnte also auch "=0.6" heissen..
Snips ist sehr genau mit der Hotword-Erkennung. Wenn ich ein Hotword einlerne, heisst das noch lange nicht, dass auch meine Frau verstanden wird.
Hierfür kann man mehrere "models" per Komma getrennt in den "model"-part der snips.toml einfügen, diese werden durch ein Komma getrennt.
Mit beispielsweise 2 models sähe die Zeile in der /etc/snips.toml so aus
model = ["/etc/snips/personal_2019_xx_xxxxxx=0.5", "
/etc/snips/personal_2019_yy_yyyyyy=0.5"
]Die models müssen unterschiedliche "hotword-keys" bekommen, sonst triggert Snips mehrfach. Ändern könnt Ihr diesen jederzeit in der "config.json"-Datei ("hotword_key": "Euer_Hotword") im jeweiligen model-Ordner . Im Beispiel verwende ich "jochen" und "barbara" als Hotword-Key.
Der Dienst "snips-hotword" muß einmal mit
sudo systemctl restart snips-hotword
neu gestartet werden.
Jetzt wird der python-Handler heruntergeladen:
sudo apt-get install -y python-pip
sudo pip install paho-mqtt==1.3.1
cd
mkdir alias
cd alias
wget https://raw.githubusercontent.com/adrienball/smart-lights/master/snips_handler.pyDann das Script ausführbar machen:
sudo chmod +x snips_handler.py
Die Scripte:
python_handler.py
Das Script python-handler.py aus dem Funksteckdosen-Artikel habe ich so abgewandelt, dass es die GPIO des RaspPi anspricht.
Da das "Hintergrundgeräusch" in einer Endlosschleife abgespielt werden soll, habe ich festgestellt, dass das ganze wesentlich stabiler läuft, wenn die "Aktionen" in subprozesse ausgelagert werden.
Eines vorweg - ich kenne mich absolut nicht mit python aus und alles was ich hier so "verwirklicht" habe ich mir im Netz angelesen und zusammengetragen. Es funktioniert zwar aber evt.kann man einiges deutlich eleganter lösen. Für "Input" bin ich dankbar.
Das Script "snips_handler.py hat folgende Funktion:
1) Bei "Hotword-Detect" wird das Script "alias.py" gestartet --> Alexa bekommt "Alexa" ins Ohr geflüstert
2) Das Script "noise.py" wird gestartet --> Alexa bekommt ein "Stimmengemurmel vorgespielt und hört nichts mehr. Dieses Script beginnt mit einer kurzen Pause, damit Alexa auch längere Sätze versteht.
3) bei Aufruf "alexa,py wird" wird der Prozess "noise.py" gekillt
4) bei Ende "alexa.py" wird der Prozess "alexa.py" gekillt.#!/usr/bin/env python
# encoding: utf-8
from __future__ import unicode_literals
import datetime
import json
import subprocess
import paho.mqtt.client as mqtt
import os
import signal
fromtimestamp = datetime.datetime.fromtimestamp
# MQTT client to connect to the bus mqtt_client = mqtt.Client()
HOST = "localhost"
PORT = 1883
HOTWORD_DETECTED = "hermes/hotword/default/detected"
HOTWORDS_J = {"jochen"}
HOTWORDS_B = {"barbara"}
# Subscribe to the important messages
def on_connect(client, userdata, flags, rc):
mqtt_client.subscribe(HOTWORD_DETECTED)
# Process a message as it arrives
def on_message(client, userdata, msg):
if not msg.topic == HOTWORD_DETECTED:
return
payload = json.loads(msg.payload)
model_id = payload["modelId"]
if model_id in HOTWORDS_J:
os.system("pkill -9 -f noise.py")
subprocess.Popen(["python", "/home/pi/alias/alias.py"])
time.sleep(3)
os.system("pkill -9 -f alias.py")
subprocess.Popen(["python", "/home/pi/alias/noise.py"])
time.sleep(1)
elif model_id in HOTWORDS_B: os.system("pkill -9 -f noise.py")
subprocess.Popen(["python", "/home/pi/alias/alias.py"]) time.sleep(4)
os.system("pkill -9 -f alias.py") subprocess.Popen(["python", "/home/pi/alias/noise.py"]) time.sleep(1)
else:
print("Unmapped hotword model_id: %s" % model_id)
if __name__ == '__main__':
mqtt_client.on_connect = on_connect
mqtt_client.on_message = on_message
mqtt_client.connect(HOST, PORT)
mqtt_client.loop_forever()alias.py
Das Script alias.py liegt im selben Ordner wie das snips_handler.py. Auch dieses Script muß ausführbar gemacht werden.
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(17,GPIO.OUT, initial=GPIO.LOW)
print "Alexa on"
GPIO.output(17,GPIO.HIGH)
time.sleep(1)
print "Alexa off"
GPIO.output(17,GPIO.LOW)
time.sleep(10)noise.py
mit diesem Script (auch im selben Ordner) wird Alexa in einer Endlos-Scheife ein "Stimmengemurmel" ins Ohr geflüstert. Auch hier: ausführbar machen !
import RPi.GPIO as GPIO
import time
while True: GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(27,GPIO.OUT, initial=GPIO.LOW)
time.sleep(16)
GPIO.output(27,GPIO.HIGH)
print "Noise on"
time.sleep(1) GPIO.output(27,GPIO.LOW)
print "Noise off"
GPIO.cleanup()Zum Schluß noch zwei Cronjob-Einträge
crontab -e
Der Datei folgendes hinzufügen:
*/15 * * * * service snips-audio-server restart
Dies startet den snips-audio-server alle 15 Minuten neu. Der Grund ist, dass dieser mir schon 2x "abgeschmiert" war - warum auch immer. Nach Neustart des Dienstes läuft er sofort wieder.
@reboot python /home/pi/alias/snips_handler.py
Das startet das snips_handler.script bei Systemstart.
Und das war es im Wesentlichen. Ich kann jetzt "Alexa" schreien, wie ich will - sie hört mich nicht. Erst wenn ich sage "Moneypenny" reagiert Alexa und ich kann meinen Satz sagen.
Natürlich ist Alexa an mein FHEM angeschlossen, also geht sowas wie:
"Moneypenny - stelle die Heizung im Wohnzimmer auf 23Grad" oder "grünes Licht im Arbeitszimmer".
Und - im Gegensatz zu Moneypenny weiss "Moneypenny II" alles über das Wetter und kennt das TV-Programm von morgen !
Amazon Alexa und Amazon Music mit Squeezebox-Multiroom
-
Alexa und Amazon Music an Squeezebox Multiroom anbinden
Alexa bietet von sich aus ja schon so allerhand an Musikdiensten. Wer Amazon Music oder Spotify abonniert hat, kann seine Musik ganz einfach per Sprachbefehl aufrufen:
"spiele etwas von David Bowie auf dem Echo xyz" startet die Wiedergabe auf einem Amazon Gerät - ebenso sind natürlich Internetradios, Hörspiele, usw. möglich.
Da unsere selbstgebaute Multiroom-Lösung ja auf dem Logitech-Squeezebox-Server basiert, habe ich mich gefragt, wie ich Alexa am besten auf unsere Lautsprecher bringe.
Die Lösung dafür ist relativ simpel, ich hatte sowas schon einmal für die Wiedergabe des Desktop-Sounds eines PCs ausprobiert.
Hier wird beschrieben, wie man einen VLC-Player veranlasst, einen Stream mit Pulseaudio ins Netzwerk zu schicken:
http://confoundedtech.blogspot.com/2014/10/pc-audio-music-to-squeezebox-without.html
Ich habe mir also zunächst einen Echo-Dot zum Streamen abkommandiert. Den Klinken-Audioausgang des Dots habe ich mit einer
USB-Soundkarte verbunden und diese USB-Soundkarte habe ich an einen Pi mit Raspbian angeschlossen.
Bei der USB-Soundkarte habe ich ein wenig suchen müssen um ein Gerät mit Stereo-Line-Eingang zu finden. Die billigen China-USB- Soundkarten haben in der Regel nur einen Mono-Mikrofoneingang.
Ich habe mich für das Behringer U-Control UCA202 USB-Audiointerface entschieden (Google hilft!), das Gerät wird von Linux sofort und ohne weitere Installationen erkannt.
Zunächst müssen einige Zusätze für pulseaudio installiert werden:
https://wiki.ubuntuusers.de/PulseAudio/
https://wiki.ubuntuusers.de/pavucontrol/
sudo apt-get install gstreamer1.0-pulseaudio
sudo apt-get install libsdl1.2debian-pulseaudio pulseaudio-module-gconf pulseaudio-module-lirc pulseaudio-module-x11 pulseaudio-module-zeroconf pulseaudio-module-bluetooth
sudo apt-get install pavucontrol
sudo apt-get install paprefsJetzt muss der VLC auf den Pi:
sudo apt-get install vlc
Dann müsst Ihr den Befehl
paprefs
ausführen und in dem sich öffnenden Fenster den Netzwerkzugriff auf den Puls-Audiostream erlauben
Der Befehl
pacmd list-sources
listet Euche alle vom Pi erkannten Soundkarten auf.
Der Befehl
cvlc pulse://Eure Soundkarte :sout='#transcode{vcodec=none,acodec=mp3,ab=320,channels=2,samplerate=44100}:http{dst=:8081/stream.mp3}' :no-sout-rtp-sap :no-sout-standard-sap
startet dann den Audiostream.
Für die Behringer U-Control UCA202 lautet der Befehl bei mir dann so:
cvlc pulse://alsa_input.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.analog-stereo :sout='#transcode{vcodec=none,acodec=mp3,ab=320,channels=2,samplerate=44100}:http{dst=:8081/stream.mp3}' :no-sout-rtp-sap :no-sout-standard-sap
Den Amazon Echo habe ich "Echo Netzwerk" genannt. Ihr müsstet also jetzt sagen "Alexa, spiele etwas von xyz auf dem Echo Netzwerk"
Ob der Stream funktioniert, könnt Ihr schonmal im Browser Eures PCs testen:
unter
http://IP_EURES_PI:8081/stream.mp3
müsstet Ihr schon etwas hören können, wenn Alexa etwas abspielt.
Wenn der Stream zu leise oder zu laut ist, könnt Ihr mit dem Befehl
pavucontrol
die Ein- und Ausgangslautstärke von pulseaudio konfigurieren. Natürlich könnt Ihr zusätzlich die Lautstärke des Echo-Gerätes mit den Plus/Minus-Tasten am Gerät regeln.
Beachtet dabei, das der Stream um einige Sekunden verzögert auf die Änderung reagiert.
Damit der Stream bei Neustart des Pi automatisch gestartet wird, habe ich ein kleines Script angelegt:
sudo nano /home/pi/streamstart.sh
#!/bin/sh
cvlc pulse://alsa_input.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.analog-stereo :sout='#transcode{vcodec=none,acodec=mp3,ab=320,channels=2,samplerate=44100}:http{dst=:8081/alias.mp3}' :no-sout-rtp-sap :no-sout-standard-sapDas script wird auführbar gemacht:
sudo chmod +x /home/pi/streamstart.sh
und per
crontab -e
wird für die automatische Ausführung bei Systemstart folgende Zeile hinzugefügt:
@reboot /bin/bash /home/pi/streamstart.sh
Der Stream wird jetzt also bei Neustart automatisch geladen und läuft permanent.
Ein Pi3 B+ benötigt ohne Eingangssignal ca. 6% CPU-Leistung, wenn der Echo ein Signal liefert sind es 12-13%.
Die Stream-URL, die Ihr gerade in Euren Browser eingegeben habt wird jetzt im Squeezebox-Server als URL eingetragen, mit einem Namen versehen (z.B. "alexa-stream") und als Favorit festgelegt.
Jetzt kann ich im FHEM das Squeezebox-Modul entsprechend konfigurieren:
set mein_player favorites alexa-stream
Per dummy kann ich z.B. Geräte syncen, also Gruppen bilden.
In meinem FHEM sieht es dann ungefähr so aus:
define lautsprechergruppe_unten dummy
attr lautsprechergruppe_unten setList on off
attr lautsprechergruppe_unten room alexa
attr lautsprechergruppe_unten genericDeviceType switch
attr lautsprecheranlage_unten alexaName Lautsprechergruppe unten
define unten_musik_an DOIF ([lautsprechergruppe_unten] eq "on") (set Squeezeplayer1 on,set Squeezeplayer1 favorites alexa-stream,set,set Squeezeplayer1 sync Squeezeplayer2, set.....blabla)
define unten_musik_aus DOIF ([lautsprechergruppe_unten] eq "off") (set Squeezeplayer2 unsyc, set ...blablabla,set Squeezeplayer1 off)Ich sage also sowas wie: "Alexa, schalte die Lautsprechergruppe unten an" und dann "Alexa, spiele etwas von David Bowie auf dem Echo Netzwerk."
Dann schaltet FHEM die Squeezebox-Player und deren Lautsprecher ein, synct die Player und setzt den Favoriten auf "alexa-stream".
Der Stream vom Pi wird dann auf allen gewünschten Lautsprechern syncron wiedergegeben.
Bewässerung mit FHEM-Smarthome-Anbindung
-
Bewässerung mit FHEM-Smarthome-Anbindung
Für das An- und Ausschalten der Wasserversorgung unsrer Ställe verwenden wir schon seit langer Zeit ein Gardena 24V-Ventil.
In der Sommerzeit wollen viele Pflanzen in unserem Garten gegossen werden. Wir wohnen auf dem Land, da sind die Grundstücke größer und das Blumengiessen war schon sehr zeitaufwendig.
Wir haben uns also mit einer Gartenbewässerung mit versenkbaren Regnern beschäftigt und haben uns für das Rohr-System von Gardena entschieden.Die Technik wollte ich aber „selber machen“ - ein solches System muß schließlich unbedingt in unser FHEM.
Bevor es an die Technik geht, mussten wir erstmal die Gräben für die Wasserrohre graben.
Da der Wasserdruck auf unserem Gartenwasserhahn relativ gering ist, habe ich mich für eine sternförmige Verlegung entschieden, also ein Rohr zu jedem Versenk-Regner.Ungefähr 200m 25mm-Rohr haben wir spatentief verbuddelt. Tiefer muß das nicht, denn zum Winter wird das System mit Druckluft durchgepustet. Das Gardena-System liefert jede Menge Steckverbinder, L-Stücke und T-Stücke. Die Rohre sind dadurch super einfach zu verbinden und die Verbindungen sind sofort druck- und wasserdicht.
Die Regner werden so eingegraben, dass sie bündig mit der Rasenkante abschließen – dann kann der Rasenmäher drüber fahren, ohne dass er die Dinger schrotet:
Es gibt verschiedene Regner für alle Flächen, wir haben uns für die einfachste Variante entschieden. Auch hier kann man die „Bewässerungsfläche“ perfekt einstellen – für unsere Bedürfnisse war das ideal. Anstelle der Gardena-Ventile haben wir uns für eine etwas günstigere Variante von Hunter entschieden. Wir haben einen kompletten „Headend-Bausatz“ mit 8 Ventilen und allen Verteilern im Internet gekauft.
Hier ein Bild des fertig montierten Headends:
Auf dem Bild sind neben den 8 Ventilen für die Bewässerung auch das Haupt-Ventil für die Versorgung unserer Ställe sowie 2 weitere Ventile für "Wassersteckdosen (dazu mehr in einem anderen Artikel) zu sehen .
Die Ansteuerung der 8 Sprinkler-Ventile habe ich über eine preisgünstige China-8fach-Relaiskarte realisiert. Diese Relaiskarte wird über die GPIO eines Raspberry-Pi angesteuert:
Zunächst habe ich mir also auf einem Raspberry Pi 3 B+ ein aktuelles Raspberry PI OS (vormals Raspbian) installiert.
Diesem Pi habe ich ein feste IP-Adresse zugewiesen und dann eine FHEM-Instanz zur Steuerung der GPIO-Ports darauf installiert.
Damit ich zusätzlich jederzeit auf den Pi per remote-Desktop zugreifen kann, habe ich mir einen XRDP-Server installiert (der standardmässige RealVNC-Server muß dafür deinstalliert werden):
sudo apt-get purge realvnc-vnc-server
sudo apt-get update
sudo apt-get install xrdp
Im FHEM gibt es das Modul RPI_GPIO - damit geht die Ansteuerung ganz einfach:
define [Name] RPI-GPI [port]
Ich habe die Relais meiner Relaiskarte p1 bis p8 genannt, also:
define p1 RPI_GPIO 14
(weil der GPIO-Port 14 verwendet wird)
zusätzlich muß definiert werden, ob der Port als Ein- oder Ausgang genutzt werden soll:
attr p1 direction output
Da die Relaiskarte auf LOW-Pegel einschaltet, muß man auch das dem FHEM mitteilen:
attr p1 active_low yes
Und das war‘s auch schon, der dummy „p1“ ist jetzt in der Lage, das Relais zu schalten.
Das Ganze machen wir jetzt für alle 8 Relais, die GPIO-Ports sind natürlich frei wählbar:define p2 RPI_GPIO 18
attr p2 direction output
attr p2 active_low yes
usw...
Die Relaiskarte wird übrigens direkt vom Pi mit 5V versorgt, eine eigene Stromversorgung ist nicht notwendig.
Jetzt zum Haupt-FHEM:
Weil ich die Relais über meine Haupt-FHEM-Instanz steuern möchte, habe ich den Remote-Pi mit der Relais-Platine über das Modul RFHEM eingebunden:define <name> RFHEM host[:port] [pw]
also:
define sprinkler RFHEM IP-DES_REMOTE_PI:port Passwort
Jetzt kann die Hauptinstanz bereits die Relais des Remote-Pi schalten:
set sprinkler cmd set p1 on
(„sprinkler“ ist der Name des definierten RFHEM-Pis und per „cmd set p1 on“ schaltet p1 auf dem Remote-Pi an)
Im Haupt-FHEM habe ich mir dazu noch dummys angelegt, die auch p1-p8 heissen und den RFHEM-Befehl ausführen:
define p1 dummy
attr p1 setList on off
dazu 2 DOIFs, die auf den dummy reagieren:
define p1AN DOIF ([p1:state] eq "on") (set sprinkler cmd set p1 on)
define p1AUS DOIF ([p1:state] eq "off") (set sprinkler cmd set p1 off)
define p2 dummy
...
Jetzt lassen sich die Relais genau wie im Remote-Pi schalten.
Die Relais habe ich ausgangsseitig an einen 24V Ringkerntrafo angeschlossen, der je nach aktiviertem Relais jeweils 1 Ventil schaltet.Primär- und sekundärseitig bekommt der Trafo noch eine Sicherung für den "Fall der Fälle".
Damit der Ringkerntrafo nicht ständig „unter Strom“ steht, schalte ich die Primärseite mit einem Homematic-Schalter. Ist dieser Schalter aus, schalten auch keine Ventile.
Wenn im Floorplan ein Sprinkler angeschaltet wird, sollen wegen des ansonsten zu geringen Wasserdrucks alle anderen ausgeschaltet sein. Und der Homematic-Schalter (ich habe ihn „sprinklerswitch“ genannt) soll natürlich schalten. Also habe für p1-p8 jeweils einen Hilfsdummy mit DOIF angelegt. Dieser sorgt dafür, das jeweils nur ein Ventil öffnet:define p1s dummy
attr p1s setList on off
define p1sACT DOIF
([p1s:state] eq "on") (set p2s off; set p3s off; set p4s off; set p5s off; set p6s off; set p7s off; set p8s off) (set sprinklerswitch on; set p1 on) DOELSEIF ([p1s:state] eq "off") (set sprinklerswitch off; set p1 off)
Um die Umschaltung zwischen 2 Sprinklern etwas zu verzögern bekommt das DOIF noch ein "wait"-Attribut:
attr p1sACT wait 0,2
Das DOIF für den zweiten dummy „p2s“ sieht dann so aus (=alle aus ausser „p2“):
([p2s:state] eq "on") (set p1s off; set p3s off; set p4s off; set p5s off; set p6s off; set p7s off; set p8s off) (set sprinklerswitch on; set p2 on) DOELSEIF ([p2s:state] eq "off") (set sprinklerswitch off; set p2 off)
Damit kann ich mir 8 Regner auf den Floorplan legen – sobald ich einen aktiviere, gehen andere aus:
Ich habe mir außerdem eine Automatik für den Regner ausgedacht: alle Regner sollen nacheinander einschalten: wenn Regner 1 eine Zeit gelaufen ist, wird der abgeschaltet. Dann kommt Regner 2, usw. - bis alle 8 Regner fertig sind.
Für den Floorplan-Dummy habe ich das Symbol einer Blume mit 8 weißen Blütenblättern gewählt.
Blütenblatt 1 färbt sich grün, wenn Regner 1 aktiv ist, dann Blütenblatt 2, usw – bis alle 8 Blütenblätter grün sind.
Dafür habe ich mir 8 .png-Grafiken mit den jeweiligen Blütenblatt-Färbungen angelegt und diese für den jeweiligen Zustand als devStateIcon definiert:define pcount dummy
attr pcount setList on off
attr pcount devStateIcon on:bew0.png off:bew0.png 0:bew0.png 1:bew1.png 2:bew2.png 3:bew3.png 4:bew4.png 5:bew5.png 6:bew6.png 7:bew7.png 8:bew8.png
Hier im Zeitraffer-Video:
Für den Floorplan sieht es zwar nett aus, es soll auf klick (oder touch) ja aber jederzeit an- und abschaltbar sein.
Das Problem ist, wenn der „state“ z.B. gerade auf „7“ steht, dann macht ein klick auf die blume den status „on“ und nicht „off“.
Ich setzte also (noch einen) dummy, quasi als variable:define vardum dummy
set vardum 1
An- und Aus bei klick auf die Blume geht mit Hilfe dieses dummys so:
define pcountAN DOIF ([pcount:state] eq "on" and [vardum:state] ne "2") (set pprog on; set vardum 2)
define pcountAUS ([pcount:state] eq "on" and [vardum:state] ne "1") (set pprog off; set vardum 1; set sprinklerswitch off)Das eigentliche „Bewässerungsprogramm“ erledigt ein weiterer dummy mit DOIF namens pprog:
define pprog dummy
attr pprog setList on off
attr pprogAN DOIF ([pprog:state] eq "on") (set sw1 on; set sprinklerswitch on; set pcount 1; set p1 on) (set sw1 on; set pcount 2; set p1 off; set p2 on) (set sw1 on; set pcount 3; set p2 off; set p3 on) (set sw1 on; set pcount 4; set p3 off; set p4 on) (set sw1 on; set pcount 5; set p4 off; set p5 on) (set sw1 on; set pcount 6; set p5 off; set p6 on) (set sw1 on; set pcount 7; set p6 off; set p7 on) (set sw1 on; set pcount 8; set p7 off; set p8 on) (set p8 off; set pprog off; set sw1 off) (set pcount 0) (set vardum 1) (set sprinklerswitch off) DOELSEIF ([pprog:state] eq "off") (set p1 off) (set set p2 off) (set p3 off) (set p4 off) (set p5 off) (set set p6 off) (set p7 off) (set p8 off) (set pcount 0) (set vardum 1) (set sprinklerswitch off) (set sw1 off)
Über ein DOIF-wait laufen die Regner jeweils 64 Sekunden, andere Zeitspannen gehen natürlich auch:
attr pprogAN wait 0,64,64,64,64,64,64,64,64,0,0,0
Ich habe 64 Sekunden gewählt, weil dann 4 Sekunden für die „Hydraulik" berücksichtigt werden - der Regner läuft also jeweils ca. 1 Minute.
Jetzt fehlt noch der countdown über der Blume – so wird angezeigt, wieviel Zeit Regner x aktuell noch läuft:
https://forum.fhem.de/index.php/topic,72151.msg658696.html#msg658696
define wtime dummy
(der kommt in den Floorplan)
setreading wtime elapsed 60
setreading wtime total 0
attr wtime devStateIcon 60:transparent.png(bei state = 60 wird ein transparentes .png angezeigt, 1 Pixel reicht)
attr devStateStyle style= "color:orange;;font-size:120%;;font-weight:bold;;"
define sw1 dummy
attr sw1 setList on off
define n_set_timer_action notify sw1 { if ($EVENT eq "on") {fhem("set on_timer_action active")} else {fhem("set on_timer_action inactive"); fhem("setreading wtime elapsed 60")} }
define on_timer_action +*00:00:01 {my $e = ReadingsVal("wtime", "elapsed", 0);; $e += -1;; if ($e < ReadingsVal("wtime", "total", 0)) {fhem("set on_timer_action inactive");; $e = 60;;} fhem("setreading wtime elapsed $e");;}
set on_timer_action inactive
Der Countdown zählt jetzt für jeden Regner herunter, wenn alle Regner fertig sind (der wtime hat den state „60“) wird er aufgrund des transparenten devStateIcons „ausgeblendet“.
Zum Schluß bekommt das ganze noch ein wetterfestes Häuschen:
Jetzt können wir auf "Knopfdruck" das Grundstück bewässern. Weitere Anwendungen wie Bewässung nach Zeit, nach Trockenheit (Bodenfeuchtesensor) oder
nach Wetterbericht sind natürlich denkbar (und da die "Infrastruktur" steht auch relativ einfach umzusetzen). Uns reicht allerdings erstmal diese Variante, mit
ein paar Zeilen Code kann das sicher ausgebaut werden.
Die Sprachsteuerung ("Moneypenny, schalte die Bewässerungsautomatik an") haben wir natürlich schon umgesetzt ;-)
Hierzu gibt es wieder einen "Hilfsdummy", der die "Blume" und somit die Sprinklerautomatik aktiviert und deaktiviert:
define mp_sprinkler dummy
attr mp_sprinkler setList on off
define mp_sprinklerAN DOIF ([mp_sprinkler:state] eq "on") (set pprog on; set vardum 2)
define mp_sprinklerAUS DOIF ([mp_sprinkler:state] eq "off") (set pprog off; set vardum 1; set sprinklerswitch off)Sprinkler "in action":
Wo der Bewuchs höher ist, habe ich den Sprinkler auf ein "Stativ" montiert: