<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tipps &amp; Tricks &#8211; SmartHomeNG | smarthome knx homematic mqtt hue 1wire home automation</title>
	<atom:link href="https://www.smarthomeng.de/category/tipps_tricks/feed" rel="self" type="application/rss+xml" />
	<link>https://www.smarthomeng.de</link>
	<description>Die Device Integrations-Plattform für Dein Smart Home</description>
	<lastBuildDate>Sat, 02 Nov 2024 12:51:49 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.5.5</generator>

<image>
	<url>https://www.smarthomeng.de/wp-content/uploads/global/logo_small_152x152-150x150.png</url>
	<title>Tipps &amp; Tricks &#8211; SmartHomeNG | smarthome knx homematic mqtt hue 1wire home automation</title>
	<link>https://www.smarthomeng.de</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Steuerung von Panasonic Klimaanlagen mit SmartHomeNG</title>
		<link>https://www.smarthomeng.de/steuerung-von-panasonic-klimaanlagen-mit-smarthomeng</link>
					<comments>https://www.smarthomeng.de/steuerung-von-panasonic-klimaanlagen-mit-smarthomeng#respond</comments>
		
		<dc:creator><![CDATA[Martin Sinn]]></dc:creator>
		<pubDate>Sat, 02 Nov 2024 12:50:42 +0000</pubDate>
				<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[Panasonic Klimaanlage]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=2803</guid>

					<description><![CDATA[Panasonic Klimaanlagen ansteuern Wir haben bei uns in der Wohnung zwei Klimaanlagen von Panasonic im Einsatz. Beides sind eigenständige Split-Geräte. Im Schlafzimmer ist ein Kit (Innen CS-Z20VKEW und Außen CU-Z20VKE) verbaut.Im Wohnbereich ist ein Kit (Innen CS-XZ42ZKEW-H und Außen CU-Z42ZKE) verbaut. Beide Klimaanlagen möchte ich mit SmartHomeNG ansteuern. 1. Ansatz:<a class="moretag" href="https://www.smarthomeng.de/steuerung-von-panasonic-klimaanlagen-mit-smarthomeng"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<h2>Panasonic Klimaanlagen ansteuern</h2>
<p>Wir haben bei uns in der Wohnung zwei Klimaanlagen von Panasonic im Einsatz. Beides sind eigenständige Split-Geräte.</p>
<p>Im Schlafzimmer ist ein Kit (Innen CS-Z20VKEW und Außen CU-Z20VKE) verbaut.<br />Im Wohnbereich ist ein Kit (Innen CS-XZ42ZKEW-H und Außen CU-Z42ZKE) verbaut.</p>
<p>Beide Klimaanlagen möchte ich mit SmartHomeNG ansteuern.</p>
<h4>1. Ansatz: Anbindung an KNX</h4>
<p>Eine Möglichkeit ist der Einsatz von jeweils einem INTESIS INKNXPAN001I000 KNX-Klima-Gateway, um eine Verbindung der Klimaanlagen zu meinem KNX Bus herzustellen. Diese Lösung setzt voraus, dass in der Nähe der Klimaanlagen ein grünes Buskabel liegt. Außerdem ist die Lösung nicht gerade preiswert. Der offizielle Katalogpreis im Panasonic Katalog liegt über 500 Euro. Der günstigste Preis den ich gefunden habe, liegt immer noch bei 260 Euro je Stück.</p>
<p>Da bei einer Klimaanlage kein Buskabel in der Nähe ist (und aufgrund der hohen Kosten), fiel diese Lösung aus.</p>
<h4>2. Ansatz: Eingebautes WLAN Interface</h4>
<p>In den Klimaanlagen ist serienmäßig zwar ein WLAN Interface verbaut, dieses kann jedoch nur eine Verbindung zur Panasonic Comfort Cloud aufbauen und nicht lokal angesteuert werden.</p>
<p>Auf pypi.org fand ich ein Python Package, welches die Kommunikation mit der Panasonic Comfort Cloud ermöglichte. Dieses Package setzt auf dem API auf, welches die Panasonic App auf iOS und Android nutzt. Allerdings ist dieses API von Panasonic nicht veröffentlicht, so dass das Package per Reverse-Engineering des API entstand.</p>
<p>Nach Anlaufproblemen, da die Comfort Cloud gerade das Login Verfahren geändert hat und ich auf eine neue Version des Python Packages warten musste, verliefen die ersten Tests vielversprechend. Alle Aspekte der Klimaanlagen waren steuerbar.</p>
<p>Ich habe daraufhin in den sauren Apfel gebissen, die Nutzungs-Daten der Klimaanlagen einer Cloud anzuvertrauen und begonnen ein Plugin für SmartHomeNG zu entwickeln. Das Plugin hat auch einen nutzbaren Status erreicht, aber dann begannen für mich die Probleme. Die Panasonic Comfort Cloud hatte mehrere Störungen und war Stunden- bzw. Tageweise nicht zu erreichen. In diesen Zeiten konnten die Klimaanlagen über SmartHomeNG nicht gesteuert werden und die Infrarot-Fernbedienungen der Klimaanlagen mussten wieder ausgepackt werden. Im Internet fand ich diverse Beiträge von Usern, die sich über die störanfällige Panasonic Comfort Cloud ausliessen. Diese Beiträge waren zum teil aktuell, zum Teil jedoch bereits Jahre alt. Das war ein Zeichen, dass Panasonic anscheinend nicht an der Zuverlässigkeit der Comfort Cloud arbeitet. </p>
<p>Da wir mit der Cloud Lösung nicht zufrieden waren:</p>
<ul>
<li>Daten auf Systemen, bei denen ich keine Kontrolle über den Zugriff habe</li>
<li>Möglichkeit die Klimaanlagen durch jemand zu steuern, der sich Zugang zur Cloud verschafft</li>
<li>Störungsanfälligkeit der Panasonic Comfort Cloud</li>
<li>Durch dass nicht veröffentlichte API jederzeit der Ausfall des Zugriffs auf die Cloud möglich war (wie zuletzt bei der Änderung des Login-Verfahrens)</li>
</ul>
<p>fiel diese Lösung bei uns auch aus.</p>
<h4>3. Suche nach einer anderen Lösung</h4>
<p>Die Panasonic Klimaanlagen verfügen über zwei Möglichkeiten sie ohne Cloud zu steuern:</p>
<ul>
<li>Infrarot Fernbedienung<br /><a href="https://www.smarthomeng.de/wp-content/uploads/2024/11/CONTROL-RE-TZ20WKEW-O.jpg"><img decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2024/11/CONTROL-RE-TZ20WKEW-O-98x300.jpg" alt="" width="98" height="300" class="alignnone size-medium wp-image-2826" srcset="https://www.smarthomeng.de/wp-content/uploads/2024/11/CONTROL-RE-TZ20WKEW-O-98x300.jpg 98w, https://www.smarthomeng.de/wp-content/uploads/2024/11/CONTROL-RE-TZ20WKEW-O.jpg 328w" sizes="(max-width: 98px) 100vw, 98px" /></a></li>
<li>Gateways (z.B. das INTESIS KNX-Klima-Gateway), die an den CN-CNT Anschluß der Klimaanlage angeschlossen werden. <br />
<div id="attachment_2813" style="width: 310px" class="wp-caption alignnone"><a href="https://www.smarthomeng.de/wp-content/uploads/2024/11/CN-CNT.png"><img fetchpriority="high" decoding="async" aria-describedby="caption-attachment-2813" src="https://www.smarthomeng.de/wp-content/uploads/2024/11/CN-CNT-300x186.png" alt="" width="300" height="186" class="wp-image-2813 size-medium" srcset="https://www.smarthomeng.de/wp-content/uploads/2024/11/CN-CNT-300x186.png 300w, https://www.smarthomeng.de/wp-content/uploads/2024/11/CN-CNT-768x477.png 768w, https://www.smarthomeng.de/wp-content/uploads/2024/11/CN-CNT.png 800w" sizes="(max-width: 300px) 100vw, 300px" /></a><p id="caption-attachment-2813" class="wp-caption-text">CN-CNT Anschluß</p></div>
</li>
</ul>
<p>Der erste Ansatz (ein Device zu bauen, welches die IR Codes der Fernbedienung aussendet) hat einen entscheidenden Nachteil: Die Kommunikation ist uni-direktional. Das bedeutet, dass SmartHomeNG keine Veränderungen am Status der Klimaanlage mitbekommt, die z.B. durch die Fernbedienung oder durch Unterbrechung der Stromzufuhr herbeigeführt wurden.</p>
<p>Deshalb ist es besser eine Lösung zu suchen, die über den CN-CNT Anschluß mit der Klimaanlage kommuniziert, da hierbei eine bi-direktionale Kommunikation möglich ist.</p>
<p>Ich bin daraufhin längere Zeit tief im Internet verschwunden und habe nach einer Lösung gesucht, die über den CN-CNT Anschluß kommuniziert.</p>
<p>Bei der Suche bin ich auf eine Lösung gestoßen, die auf einer dafür designten Platine mit einem ESP32-C3 Mini Platine, einer selbst zu erstellenden Platine und der ESPHome Software besteht. Diese Lösung wird allerdings seit September 2023 nicht mehr als Fertiggerät angeboten. Es besteht dort ein Link zu einer Selbstbau-Anleitung, bei der allerdings die Platine selbst geätzt (oder bei PCBway in Auftrag gegeben) werden müsste. Die Platine ist nötig, um eine 3.3V zu 5V Wandlung durchzuführen. Das war mir doch zu viel Eigenarbeit, so dass ich auf Basis der hier gefundenen Informationen weiter gesucht habe.</p>
<p>Bei der Suche bin ich auf einen Forenbeitrag gestoßen, der beschrieb, dass die 3.3V zu 5V Wandlung nur für den ESP8266 notwendig ist, da die GPIO Anschlüsse des ESP32 Prozessors 5V tolerant sind. Das senkt den Aufwand deutlich.</p>
<p>Ich habe mir also ein Kabel mit dem Stecker für den CN-CNT, ein ESP32-C3 Supermini und ein Gehäuse besorgt und angefangen.</p>
<div id="attachment_2823" style="width: 650px" class="wp-caption alignnone"><a href="https://www.smarthomeng.de/wp-content/uploads/2024/11/IMG_1707-low.jpeg"><img decoding="async" aria-describedby="caption-attachment-2823" src="https://www.smarthomeng.de/wp-content/uploads/2024/11/IMG_1707-low.jpeg" alt="" width="640" height="480" class="wp-image-2823 size-full" srcset="https://www.smarthomeng.de/wp-content/uploads/2024/11/IMG_1707-low.jpeg 640w, https://www.smarthomeng.de/wp-content/uploads/2024/11/IMG_1707-low-300x225.jpeg 300w" sizes="(max-width: 640px) 100vw, 640px" /></a><p id="caption-attachment-2823" class="wp-caption-text">Bauteile</p></div>
<p>Meine gesammelten Erfahrungen und der Weg zur fertigen Lösung beschreibe ich in einem seperaten Beitrag.</p>


<p></p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.smarthomeng.de/steuerung-von-panasonic-klimaanlagen-mit-smarthomeng/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Tablet als SmartHome Zentrale für smartVISU (mit &#8222;Fully Kiosk Browser&#8220; / Motion Detection)</title>
		<link>https://www.smarthomeng.de/tablet-als-smarthome-zentrale-fuer-smartvisu-mit-fully-kiosk-browser-und-bewegungserkennung</link>
					<comments>https://www.smarthomeng.de/tablet-als-smarthome-zentrale-fuer-smartvisu-mit-fully-kiosk-browser-und-bewegungserkennung#comments</comments>
		
		<dc:creator><![CDATA[Marc René Frieß]]></dc:creator>
		<pubDate>Wed, 30 Dec 2020 15:34:27 +0000</pubDate>
				<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[Bewegungserkennung]]></category>
		<category><![CDATA[Fully Kiosk Browser]]></category>
		<category><![CDATA[Motion Detection]]></category>
		<category><![CDATA[smartVISU]]></category>
		<category><![CDATA[Tablet]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=2683</guid>

					<description><![CDATA[Schon lange war ich auf der Suche nach einer Lösung für eine Steuerung meines SmartHomes vom Eingangsbereich unseres Hauses aus. Alle meine Versuche in den letzten Jahren, ein Android Tablet mit Bewegungserkennung und dauerhaft laufender smartVISU aufzusetzen, schlugen an der Umsetzung der Bewegungserkennung fehl. Weihnachten 2020 wollte endlich ich einen<a class="moretag" href="https://www.smarthomeng.de/tablet-als-smarthome-zentrale-fuer-smartvisu-mit-fully-kiosk-browser-und-bewegungserkennung"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<p>Schon lange war ich auf der Suche nach einer Lösung für eine Steuerung meines SmartHomes vom Eingangsbereich unseres Hauses aus. Alle meine Versuche in den letzten Jahren, ein Android Tablet mit Bewegungserkennung und dauerhaft laufender smartVISU aufzusetzen, schlugen an der Umsetzung der Bewegungserkennung fehl.<br />
Weihnachten 2020 wollte endlich ich einen neuen Anlauf unternehmen, diesmal auf Basis eines erschwinglichen Samsung Galaxy Tab A7.<br />
Den am Ende erfolgreichen Ansatz beschreibe ich in diesem Artikel.</p>
<p><strong>Ausgangspunkt</strong></p>
<p>Basis meines Setups ist SmartHomeNG in neuster Version, dazu die SmartVISU 2.9. Vorgeschaltet ist NGINX als ReverseProxy wie einst in <a href="https://www.smarthomeng.de/nginx-als-reverseproxy">https://www.smarthomeng.de/nginx-als-reverseproxy</a> beschrieben. Auf dem Tablet selber testete ich mich erneut durch diverseste Anleitungen zum automatischen Einschalten via Bewegungserkennung. Die Anleitungen basierten auf den Apps / Kombinationen der Apps MacroDroid, Tasker und Motion Detector. Ein Teil dieser Apps ist kostenpflichtig. Via Tasker und Motion Detector konnte ich das Ganze zumindest für 24 Stunden lauffähig bekommen. Allerdings stellte ich fest, dass oft eine der Apps wegen CPU Überlastung des Geräts beendet wurde. Auch landete ich regelmäßig in einem Zustand, in dem das Display des Tablets einfach nicht mehr ausgehen wollte, was sogar in leichtem Einbrenneffekt im OLED resultierte. Auch die Einrichtung des Ganzen war alles andere als einfach&#8230;</p>
<p>Frustriert wollte ich schon aufgeben, da bin ich auf die App &#8222;<a href="https://play.google.com/store/apps/details?id=de.ozerov.fully&amp;hl=de&amp;gl=US">Fully Kiosk Browser &amp; App Lockdown</a>&#8220; (bzw. <a href="https://www.fully-kiosk.com/de/">https://www.fully-kiosk.com/de/</a>) gestoßen. Vom Namen her klang das ganze etwas etwas seltsam, stellte sich im Nachhinein aber als praktikable und super einfache Lösung heraus.<br />
In der Basisversion ist die App kostenlos. Für das was ich vorhatte (Authentifizierung via Clientzertifikaten + Bewegungserkennung) musste ich leider die volle Version für stolze 6.90 € (pro Gerät) freischalten.</p>
<p><strong>Setup</strong></p>
<p>Nach dem Download aus dem Playstore und der kostenpflichtigen Freischaltung der vollen Features, geht man in der App erstmal über die linke Randleiste in den Bereich <strong>&#8222;Settings&#8220;</strong>.</p>
<p><img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2020/12/Einstieg-1.png" alt="" width="698" height="419" class="alignnone wp-image-2685" srcset="https://www.smarthomeng.de/wp-content/uploads/2020/12/Einstieg-1.png 2000w, https://www.smarthomeng.de/wp-content/uploads/2020/12/Einstieg-1-300x180.png 300w, https://www.smarthomeng.de/wp-content/uploads/2020/12/Einstieg-1-768x461.png 768w, https://www.smarthomeng.de/wp-content/uploads/2020/12/Einstieg-1-1024x614.png 1024w" sizes="(max-width: 698px) 100vw, 698px" /></p>
<p>Unter <strong>&#8222;Web Content Settings&#8220;</strong> muss als erstes die Start URL auf den DynDNS HTTPS-Einstiegspunkt für die smartVISU gelegt werden. Später habe ich die Start-URL hier noch angepasst, da ich ein 3-spaltiges Layout in die smartVISU implementiert habe, um die volle Breite des Tablets optimal zu nutzen.</p>
<p>Die <em>Authentifizierung</em> wird als nächstes im Bereich<strong> &#8222;Advanced Web Settings&#8220;</strong> eingerichtet.</p>
<p><img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2020/12/Settings-1.png" alt="" width="690" height="414" class="alignnone wp-image-2687" srcset="https://www.smarthomeng.de/wp-content/uploads/2020/12/Settings-1.png 2000w, https://www.smarthomeng.de/wp-content/uploads/2020/12/Settings-1-300x180.png 300w, https://www.smarthomeng.de/wp-content/uploads/2020/12/Settings-1-768x461.png 768w, https://www.smarthomeng.de/wp-content/uploads/2020/12/Settings-1-1024x614.png 1024w" sizes="(max-width: 690px) 100vw, 690px" /></p>
<p>Relativ weit unten kann man mit der kostenpflichtigen PLUS Version der App das <strong>&#8222;Client Certificate File&#8220;</strong> angeben. Über &#8222;PICK A FILE&#8220; kann hier der volle Pfad auf die <em>p12 </em>Zertifikatsdatei ausgewählt werden, welche auf dem Gerät abliegen muss. Da das Clientzertifikat mit Passwort geschützt ist, muss dieses im darunterliegenden Punkt <strong>&#8222;Client Certificate Password&#8220;</strong> gesetzt werden.</p>
<p><img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2020/12/certificate.png" alt="" width="687" height="412" class="alignnone wp-image-2689" srcset="https://www.smarthomeng.de/wp-content/uploads/2020/12/certificate.png 2000w, https://www.smarthomeng.de/wp-content/uploads/2020/12/certificate-300x180.png 300w, https://www.smarthomeng.de/wp-content/uploads/2020/12/certificate-768x461.png 768w, https://www.smarthomeng.de/wp-content/uploads/2020/12/certificate-1024x614.png 1024w" sizes="(max-width: 687px) 100vw, 687px" /></p>
<p>Würde man keine Clientzertifikate verwenden oder möchte man nicht für die PLUS Version zahlen, könnte man auch unter &#8222;Web Content Settings&#8220; einfach den User und das Passwort für eine Basic Authentication hinterlegen.</p>
<p>Schließt man die Konfiguration nun, kann man links unter &#8222;Goto Start URL&#8220; bereits den Zugriff testen.</p>
<p><strong>Motion Detection</strong></p>
<p>Der &#8222;Fully Kiosk Browser&#8220; verfügt über eine integrierte Bewegungserkennung, die sich in meinen Tests robust und wenig CPU-lastig erwiesen hat. Auch im Dauerbetrieb gibt es hier keinerlei Probleme und die Bewegungserkennung zum Einschalten des Displays funktioniert einwandfrei, so lange der Browser die aktive Anwendung ist.</p>
<p>Die Einstellungen könnt ihr ebenfalls unter<strong> &#8222;Settings&#8220;</strong> und dann<strong> &#8222;Motion Detection (PLUS)&#8220;</strong> setzen. Die Bewegungserkennung gibt es &#8211; genauso wie die Clientzertifikate &#8211; nur in der Vollversion. Die gesetzten Einstellungen sind unten zu sehen. Sicher kann man je nach räumlicher Situation auch an der <strong>Detector Sensitivity</strong> und der <strong>Detector Frame Rate</strong> noch Feintuning betreiben.</p>
<p><img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2020/12/motiondetection.jpg" alt="" width="688" height="413" class="alignnone wp-image-2692" srcset="https://www.smarthomeng.de/wp-content/uploads/2020/12/motiondetection.jpg 2000w, https://www.smarthomeng.de/wp-content/uploads/2020/12/motiondetection-300x180.jpg 300w, https://www.smarthomeng.de/wp-content/uploads/2020/12/motiondetection-768x461.jpg 768w, https://www.smarthomeng.de/wp-content/uploads/2020/12/motiondetection-1024x614.jpg 1024w" sizes="(max-width: 688px) 100vw, 688px" /></p>
<p>Nach diesen Einstellungen konnte ich das Ganz erfolgreich in Betrieb nehmen. Mit einem dreispaltigen Layout kommt die smartVISU hier zudem voll zur Geltung. Das dreispaltige Layout habe ich mit einem einfachen <span>&lt;div </span><span>class</span><span>=&#8220;block&#8220; </span><span>style</span><span>=&#8220;</span><span>width</span>: <span>33</span>%<span>;</span><span>&#8222;</span><span>&gt; in den &#8222;block&#8220; DIVs erreicht.</span></p>
<p><img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2020/12/20201230_162647.png" alt="" width="3110" height="1750" class="alignnone size-full wp-image-2694" srcset="https://www.smarthomeng.de/wp-content/uploads/2020/12/20201230_162647.png 3110w, https://www.smarthomeng.de/wp-content/uploads/2020/12/20201230_162647-300x169.png 300w, https://www.smarthomeng.de/wp-content/uploads/2020/12/20201230_162647-768x432.png 768w, https://www.smarthomeng.de/wp-content/uploads/2020/12/20201230_162647-1024x576.png 1024w" sizes="(max-width: 3110px) 100vw, 3110px" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.smarthomeng.de/tablet-als-smarthome-zentrale-fuer-smartvisu-mit-fully-kiosk-browser-und-bewegungserkennung/feed</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
		<item>
		<title>Nutzung von Szenen in SmartHomeNG</title>
		<link>https://www.smarthomeng.de/nutzung-von-szenen-in-smarthomeng</link>
					<comments>https://www.smarthomeng.de/nutzung-von-szenen-in-smarthomeng#comments</comments>
		
		<dc:creator><![CDATA[Martin Sinn]]></dc:creator>
		<pubDate>Mon, 25 May 2020 13:51:44 +0000</pubDate>
				<category><![CDATA[Beispiel-Implementierungen]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[eval]]></category>
		<category><![CDATA[HUE]]></category>
		<category><![CDATA[hue2]]></category>
		<category><![CDATA[Items]]></category>
		<category><![CDATA[Szenen]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=2574</guid>

					<description><![CDATA[Die Implementierung von Szenen in SmartHomeNG orientiert sich an der Art wie Szenen in KNX implementiert sind. Da nicht jeder Nutzer von SmartHomeNG mit KNX-Szenen vertraut ist, fasse ich im Folgenden die Funktionsweise von KNX-Szenen kurz zusammen. Wer mit KNX-Szenen bereits vertraut ist, kann diesen Abschnitt überspringen und sich gleich<a class="moretag" href="https://www.smarthomeng.de/nutzung-von-szenen-in-smarthomeng"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<p>Die Implementierung von Szenen in SmartHomeNG orientiert sich an der Art wie Szenen in KNX implementiert sind. Da nicht jeder Nutzer von SmartHomeNG mit KNX-Szenen vertraut ist, fasse ich im Folgenden die Funktionsweise von KNX-Szenen kurz zusammen. Wer mit KNX-Szenen bereits vertraut ist, kann diesen Abschnitt überspringen und sich gleich die Beispiel-Implementierung anschauen.</p>
<h3>Funktionsweise von KNX-Szenen</h3>
<p>Um Szenen in KNX nutzen zu können, müssen Aktoren verwendet werden, die Szenen unterstützen. Diese Aktoren verfügen über ein Kommunikationsobjekt, über welches Szenen angesteuert werden können. Szenen werden ausgelöst, indem auf die Gruppenadresse (GA) die mit diesem Kommunikationsobjekt verbunden ist, ein numerischer 8-Bit Wert gesendet wird. Gültige Werte sind hierfür 0 bis 63. Über eine Szene können also nur Aktoren angesteuert werden, die mit der selben Gruppenadresse verbunden sind.</p>
<p>Auf welche Werte (Szenennummern) der jeweilige Aktor reagiert, muss mit der ETS konfiguriert werden. In der ETS wird auch festgelegt, welchen Zustand der Aktor einnehmen soll, wenn über die Gruppenadresse eine Szene angesteuert wird.</p>
<p>Optional kann in der ETS eingestellt werden, dass Aktoren die Zustände die zu einer Szene gehören lernen kann. Das geschieht folgendermaßen: Die Aktoren werden manuell in den Zustand gebracht, den sie für eine Szene einnehmen sollen. Anschließend wird auf die Guppenadresse der Wert Szenennummer+128 (also 128 bis 191) gesendet. Dadurch werden die Aktoren, bei denen das &#8222;Lernen&#8220; aktiviert ist veranlasst, sich den aktuellen Zustand als Zustand für die entsprechende Szene zu merken.</p>
<h3>Ansteuerung von KNX-Szenen aus SmartHomeNG</h3>
<p>Um KNX-Szenen aus SmartHomeNG anzusteuern, muss ein numerisches Item angelegt werden und es muss den Wert auf die Gruppenadresse senden, die zur Szenensteuerung verwendet wird:</p>
<pre><code class="language-yaml">meine_items:
    knx_szenen:
        name: Beispiel für KNX-Szenen
        type: num
        enforce_updates: True
        knx_dpt: 5
        knx_send: 0/0/3
</code></pre>
<p><strong>enforce_updates</strong> muss auf True gesetzt werden, damit wenn mehrfach hintereinander die selbe Szene angesteuert werden soll, der Wert auch auf den KNX Bus geschrieben wird.<br />
Der <strong>knx_dpt</strong> Wert 5 (8 Bit 0-255) ist die ursprüngliche Art Szenen in KNX Anzusteuern. Hier werden die Szenen über Werte von 0 bis 63 angesteuert.</p>
<p>Es gibt inzwischen in KNX eigene DPT Werte um Szene anzusteuern (DPT 17 und 18). Bei diesen DPTs werden die Szenen von 1 bis 64 nummeriert. Es ist zu beachten, dass ganz alte KNX Aktoren diese DPTs eventuell nicht kennen (weshalb ich mir angewöhnt habe immer DPT 5 zu verwenden).</p>
<h3>Szenen in SmartHomeNG</h3>
<p>Szenen in SmartHomeNG funktionieren nach dem gleichen Prinzip wie KNX-Szenen. Damit SmartHomeNG erkennt, dass ein Item die Ansteuerung einer Szene bewirken soll, muss der Item-Type <strong>scene</strong> gewählt werden. Ein Szenen Item für SmartHomeNG Szenen sieht somit folgendermaßen aus:</p>
<pre><code class="language-yaml">meine_items:
    szenen:
        name: Beispiel für SmartHomeNG-Szenen
        type: scene
        enforce_updates: True
</code></pre>
<p>Die Festlegungen, welche Items auf die Szene reagieren sollen und welchen Zustand sie einnehmen sollen (was bei KNX in der ETS festgelegt wird), erfolgt im Verzeichnis <strong>../scenes</strong> in einer YAML Datei, die den Namen des Szenen-Items trägt. Im obigen Beispiel also <strong>meine_items.szenen.yaml</strong>. Detals zum Aufbau dieser Datei sind in der Anwender Dokumentation in der Beschreibung der <a href="http://www.smarthomeng.de/dev/user/konfiguration/konfigurationsdateien/scenes.html">Konfigurationsdateien</a> zu finiden.</p>
<p>Die Ansteuerung der Szenen erfolgt analog zur Ansteuerung von KNX-Szenen durch Zuweisung eines Wertes zwischen 0 und 63 zum Abruf (und 128 bis 191 zum speichern) von Szenen.</p>
<h3>Gemischte Szenen in SmartHomeNG und KNX</h3>
<p>Es ist auch möglich, Szenen zwischen SmartHomeNG und KNX zu mischen, ohne die Items der KNX Aktoren in die SmartHome Szenen Definition im <strong>../scenes</strong> Verzeichnis aufnehmen zu müssen. Es kann dabei auf die KNX Funktionalität zurück gegriffen werden. Dazu muss das Szenen Item einer SmartHomeNG Szene nur um die KNX Attribute erweitert werden:</p>
<pre><code class="language-yaml">meine_items:
    szenen:
        name: Beispiel für gemischte Szenen
        type: num
        enforce_updates: True
        knx_dpt: 5
        knx_send: 0/0/3
</code></pre>
<p>Wenn die Szenen Ansteuerung auch aus dem KNX Bus heraus erfolgen soll, also z.B. über einen Tastsensor der Szenen abruft oder speichert, muss das Beispiel nur noch um den KNX Listen-Befehl auf die Szenen-GA erweitert werden:</p>
<pre><code class="language-yaml">meine_items:
    szenen:
        name: Beispiel für gemischte Szenen
        type: num
        enforce_updates: True
        knx_dpt: 5
        knx_send: 0/0/3
        knx_listen: 0/0/3
</code></pre>
<p>Nun bewirkt ein Szenen Abruf durch einen KNX Taster, dass auch die Items der SmartHomeNG Szene mit angesteuert werden.</p>
<h3>Beispiel Implementierung</h3>
<p>Im folgenden wird die Implementierung der Lichtsteuerung gezeigt, bei der fast alle Leuchten über KNX-Szenen gesteuert werden. Allerdings soll eine Philips HUE Leuchte mit angesteuert werden, welche aus SmartHomeNG heraus mit dem hue Plugin gesteuert wird.</p>
<p>Das Szenen Item wird azu folgendermaßen definiert:</p>
<pre><code class="language-yaml">wohnung:
    buero:
        szenen_knx:
            comment: 0=aus, 1=Ambiente, 2=hell, 3=Putzen, 4=Party
            name: Beleuchtungsszenen Büro
            type: scene
            enforce_updates: 'on'
            knx_dpt: 5
            knx_send: 1/0/16
            knx_listen: 1/0/16
</code></pre>
<p>Die KNX Aktoren (Dimmer) sind entsprechend konfiguriert, dass sie auf der GA 1/0/16 auf die Szenennummern 0 bis 4 (gemäß KNX Definition Szenen 1 bis 5) reagieren und dass sie für die Szenennummern 1 und 2 das lernen zulassen.</p>
<p>Die SmartHomeNG Szene ist im Verzeichnis <strong>../scenes</strong> in der Datei <strong>wohnung.buero.szenen_knx.yaml</strong> folgendermaßen definiert:</p>
<pre><code class="language-yaml">
0:
    name: Aus
    # Leuchte Dreieckschrank ausschalten, falls die Schreibtischleuchte nicht eingeschaltet ist, sonst level 126 setzen
    actions:
        - {item: wohnung.buero.dreieckschrank.level, value: 0 if (sh.wohnung.buero.schreibtischleuchte.status() &lt; 2) else 126}
        - {item: wohnung.buero.dreieckschrank.ct, value: 345, learn: false}
        - {item: wohnung.buero.dreieckschrank.onoff, value: False if (sh.wohnung.buero.schreibtischleuchte.status() &lt; 2) else True}

1:
    name: Ambiente
    actions:
        - {item: wohnung.buero.dreieckschrank.level, value: sh...dreieckschrank.ambiente_level()+3, learn: false}
        - {item: wohnung.buero.dreieckschrank.ct, value: 345, learn: true}
        - {item: wohnung.buero.dreieckschrank.onoff, value: True, learn: true}

2:
    name: Hell
    actions:
        - {item: wohnung.buero.dreieckschrank.level, value: 126, learn: true}
        - {item: wohnung.buero.dreieckschrank.ct, value: 345, learn: true}

3:
    name: Putzen
    actions:
        - {item: wohnung.buero.dreieckschrank.onoff, value: True, learn: false}
        - {item: wohnung.buero.dreieckschrank.level, value: 255, learn: false}
        - {item: wohnung.buero.dreieckschrank.ct, value: 345, learn: false}

4:
    name: Party
    actions:
        - {item: wohnung.buero.dreieckschrank.level, value: 200, learn: false}
        - {item: wohnung.buero.dreieckschrank.hue, value: 59635, learn: false}
        - {item: wohnung.buero.dreieckschrank.sat, value: 230, learn: false}
        - {item: wohnung.buero.dreieckschrank.onoff, value: True, learn: false}
</code></pre>
<p>Zur Ansteuerung der Hue Leuchte über die Szene werden 3 Items gesteuert, welche die Leuchte ein- und ausschalten, den Dimmwert und die Farbe setzen.</p>
<p>Für jede der Szenen (0 bis 4) wird über <strong>value</strong> für diese Werte ein Wert gesetzt (der bei Abruf der Szene eingestellt werden soll) und über <strong>learn</strong> wird festgelegt, ob andere Werte gelernt werden können/dürfen. Für <strong>value</strong> können dabei nicht nur konstante Werte festgelegt werden, sondern auch <strong>eval Ausdrücke</strong>. Wenn ein eval Ausdruck angegeben wird, ist <strong>learn</strong> zwangsweise false. In diesem Fall können also keine Szenen Zustände gelernt werden.</p>
<p>Ein Beispiel für die Nutzung von eval Ausdrücken in Szenen ist bei Szene Nummer <strong>0</strong> zu finden, welche die Beleuchtung ausschalten soll. Falls im Büro die Schreibtisch Leuchte (die nicht Teil der Szenen ist) eingeschaltet ist, wird die HUE Leuchte jedoch nicht ausgeschaltet, sondern als Hintergrund Beleuchtung in einem gedimmten warmen Weiss eingeschaltet.</p>
<p>Bei Szene Nummer <strong>1</strong> wird eine andere eval Nutzung mit Anwendung relativer Item Adressierung gezeigt. Hier wird der Wert auf den Wert eines anderen Items plus 3 gesetzt. Hier kann nur der Weisston und Ein/Aus über die Szene gelernt werden.</p>
<p>Bei Szene Nummer <strong>4</strong> wird eine vorgewählte Farbe und Helligkeit der HUE Leuchte eingestellt, die bewusst nicht durch &#8222;Lernen&#8220; geändert werden kann.</p>
<h3>Ansteuerung der Szenen über smartVISU</h3>
<p>Die Ansteuerung der Szenen kann am besten über Buttons in der smartVISU erfolgen. Für das obige Beispiel wird die folgende Definition für die Autogenerierung verwendet:</p>
<p>&nbsp;</p>
<pre><code class="language-yaml">wohnung:
    buero:
        sv_page: room
        name: Büro
        sv_img: scene_office.svg

        visu:
            szenen_beleuchtung:
                name: Szenen Beleuchtung

                sv_widget: 'Szenen abrufen:
                    &lt;span data-role="controlgroup" data-type="horizontal"&gt;
                    {{ basic.button(''szenen_buero0'', ''wohnung.buero.szenen_knx'', ''Aus'', icon0~"control_standby.svg", ''0'', ''midi'') }}
                    {{ basic.button(''szenen_buero1'', ''wohnung.buero.szenen_knx'', ''Ambiente'', icon0~"light_light_dim_00.svg", ''1'', ''midi'') }}
                    {{ basic.button(''szenen_buero2'', ''wohnung.buero.szenen_knx'', ''Hell'', icon0~"light_ceiling_light.svg", ''2'', ''midi'') }}
                    {{ basic.button(''szenen_buero3'', ''wohnung.buero.szenen_knx'', ''Putzen'', icon0~"scene_cleaning.svg", ''3'', ''midi'') }}
                    {{ basic.button(''szenen_buero6'', ''wohnung.buero.szenen_knx'', ''Party'', icon0~"light_party.svg", ''4'', ''midi'') }}
                    &lt;/span&gt;&lt;br&gt;
                    &lt;div style="line-height: 30%;"&gt;
                         &lt;br&gt;br&gt;
                    &lt;/div&gt;
                    &lt;div&gt;Szenen speichern:&lt;br&gt;
                    &lt;span data-role="controlgroup" data-type="horizontal"&gt;
                    {{ basic.button(''szenen_bueroS0'', ''wohnung.buero.szenen_knx'', ''Aus'', icon0~''control_standby.svg'', ''128'', ''midi'', ''#4176a9'') }} 
                    {{ basic.button(''szenen_bueroS1'', ''wohnung.buero.szenen_knx'', ''Ambiente'', icon0~"light_light_dim_00.svg", ''129'', ''midi'', ''#4176a9'') }} 
                    {{ basic.button(''szenen_bueroS2'', ''wohnung.buero.szenen_knx'', ''Hell'', icon0~''light_ceiling_light.svg'', ''130'', ''midi'', ''#4176a9'') }} 
                    {{ basic.button(''szenen_bueroS3'', ''wohnung.buero.szenen_knx'', ''Putzen'', icon0~''scene_cleaning.svg'', ''131'', ''midi'', ''#4176a9'') }} 
                    {{ basic.button(''szenen_bueroS6'', ''wohnung.buero.szenen_knx'', ''Party'', icon0~''light_party.svg'', ''132'', ''midi'', ''#4176a9'') }} 
                    &lt;/span&gt;&lt;/div&gt;
</code></pre>
<p>Das erzeugt in der Visu:</p>
<ul>
<li>eine Seite &#8222;Büro&#8220; in der normalen Raum-Navigation.</li>
<li>auf dieser Seite einen Block mit dem Namen &#8218;Szenen Beleuchtung&#8216;</li>
<li>in diesem Block erzeuge ich zwei Button Reihen zur Szenen Steuerung: Der obere Block zum Abruf der Szenen, der untere Block zum Speichern von Szenen</li>
</ul>
<p>Das sieht dann so aus:</p>
<p><img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2020/05/smartVISU-Szenen-300x280.jpg" alt="" width="300" height="280" class="alignnone size-medium wp-image-2591" srcset="https://www.smarthomeng.de/wp-content/uploads/2020/05/smartVISU-Szenen-300x280.jpg 300w, https://www.smarthomeng.de/wp-content/uploads/2020/05/smartVISU-Szenen.jpg 398w" sizes="(max-width: 300px) 100vw, 300px" /></p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.smarthomeng.de/nutzung-von-szenen-in-smarthomeng/feed</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Extremwerte des Tages speichern</title>
		<link>https://www.smarthomeng.de/__trashed</link>
					<comments>https://www.smarthomeng.de/__trashed#comments</comments>
		
		<dc:creator><![CDATA[kex]]></dc:creator>
		<pubDate>Sun, 24 May 2020 19:59:01 +0000</pubDate>
				<category><![CDATA[Beispiel-Implementierungen]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[eval]]></category>
		<category><![CDATA[Items]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=2546</guid>

					<description><![CDATA[Meine Aufgabenstellung war die folgende: Speichern des höchsten gemessenen Temperaturwertes eines Tages und diesen einmal pro Tag zurücksetzten. Das ursprüngliche Item dessen Maximalwert ich speichern hat folgenden Aufbau. Wetterstation: Temperatur: type: num visu_acl: ro Um jetzt zusätzlich zum aktuellen Messwert den maximalen Messwert zu speichern habe ich das Item etwas<a class="moretag" href="https://www.smarthomeng.de/__trashed"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<p>Meine Aufgabenstellung war die folgende: Speichern des höchsten gemessenen Temperaturwertes eines Tages und diesen einmal pro Tag zurücksetzten.</p>
<p>Das ursprüngliche Item dessen Maximalwert ich speichern hat folgenden Aufbau.</p>
<pre class="line-numbers"><code class="language-yaml">
Wetterstation:
    Temperatur:
        type: num
        visu_acl: ro
</code></pre>
<p>Um jetzt zusätzlich zum aktuellen Messwert den maximalen Messwert zu speichern habe ich das Item etwas angepasst:</p>
<pre class="line-numbers"><code class="language-yaml">
Wetterstation:
    Temperatur:
        Aktuell:
            type: num
            visu_acl: ro
        Maximum_Heute:
            type: num
            visu_acl: ro
</code></pre>
<p>Für Wetterstation.Tempertatur.Maximum_Heute müssen jetzt noch folgende Dinge hinzufefügt werden:</p>
<ul>
<li><a href="#d1">Überprüfen auf Änderungen</a><br />
Immer wenn sich der Wert von <strong>Wetterstation.Temperatur.Aktuell</strong> ändert, soll überprüft werden, ob <strong>Wetterstation.Temperatur.Maximum_Heute</strong> aktualisiert werden muss.</li>
<li><a href="#d2">Aktualisieren des Wertes</a><br />
Wenn bei dieser Überprüfung der aktuelle Wert höher ist als der bisher in <strong>Wetterstation.Temperatur.Maxiumum_Heute</strong> gespeicherte Wert, soll der Wert aktualisiert werden.</li>
<li><a href="#d3">Zurücksetzen des Wertes</a><br />
Einmal am Tag muss <strong>Wetterstation.Temperatur.Maximum_Heute</strong> zurückgesetzt werden.</li>
</ul>
<h3 id="d1">Überprüfen auf Änderungen</h3>
<p>Das überprüfen, ob sich die aktuelle Temperatur ändert, geht ganz einfach indem man <strong>Wetterstation.Temperatur.Maximum_Heute</strong> einen eval_trigger auf das Item <strong>Wetterstation.Temperatur.Aktuell</strong> hinzufügt. Seit SmartHomeNG kann man das Item auch relativ angeben: ..Aktuell.<br />
es entsteht also folgender <strong>eval_trigger</strong>:</p>
<pre><code class="language-yaml">eval_trigger: ..Aktuell</code></pre>
<h3 id="d2">Aktualisieren des Wertes</h3>
<p>Wenn bei der Überprüfung der aktuelle Wert höher ist als der bisher in Wetterstation.Temperatur.Maxiumum_Heute gespeicherte Wert, soll der Wert aktualisiert werden.<br />
Das geht über ein <strong>eval</strong>:</p>
<pre><code class="language-yaml">eval: sh...Aktuell() if float(sh..self()) &gt; sh...Aktuell() else sh..self.property.value</code></pre>
<h3 id="d3">Zurücksetzen des Wertes</h3>
<p>Der Wert soll einmal pro Tag und bei einem Neustart zurückgesetzt werden. Das wird über ein <strong>crontab </strong>und ein <em>Magic Value</em> (99.9) erledigt. Es wird davon ausgegangen, dass ein Temperaturwert von 99.9 nie vorkommt und deshalb zum Zurücksetzen verwendet werden kann.</p>
<p>Verzögerung bei der Initialisierung: Meine Wetterstation liefert nur alle 5 Minuten (alle 300 Sekunden) einen neuen Temperaturwert. Das heisst nach einem Neustart von SmartHomeNG steht also für maximal 5 Minuten kein aktueller Messwert in <strong>Wetterstation.Temperatur.Aktuell</strong> sondern 0.0. Deshalb wird nach 5 Minuten und 10 Sekunden <strong>Wetterstation.Temperatur.Maximum_Heute</strong> auf die aktuelle Temperatur zurückgesetzt.</p>
<pre><code class="language-yaml">crontab:
 -init+310 = 99.9
 -0 0 * *  = 99.9
</code></pre>
<p>Auch der <strong>eval</strong> Ausdruck muss für das Zurücksetzen erweitert werden:</p>
<pre><code class="language-yaml">eval: sh...Aktuell() if <strong>value == 99.9 or</strong> float(sh..self()) &gt; sh...Aktuell() else sh..self.property.value
</code></pre>
<p>Natürlich kann dieses Prinzip Minimal-Werte angewendet werden. Dafür muss nur der Vergleich im <strong>eval</strong> Ausdruck angepasst werden.</p>
<p>Das endgültige Item sieht dann so aus:</p>
<pre class="line-numbers"><code class="language-yaml">
Wetterstation:
    Temperatur:
        Aktuell:
            type: num
            visu_acl: ro
        Maximum_Heute:
            type: num
            visu_acl: ro
            eval: sh...Aktuell() if value == 99.9 or float(sh..self()) &lt; sh...Aktuell() else sh..self.property.value
            eval_trigger: ..Aktuell
            # Reset am Ende des Tages durch "MagicValue" 99.9. Es wird angenommen, 
            # dass dieser Temperaturwert in der Praxis niemals auftritt. 
            crontab: 
             - 0 3 * * = 99.9
             # +310 weil die Wetterstation mindestens alle 300 Sekunden einen aktualisierten Temperatur Wert sendet
             # dadurch wird sichergestellt, dass nach einem Neustart von SmartHomeNG in ..Aktuell auf jeden Fall ein gültiger Wert steht. 
             - init+310 = 99.9
</code></pre>
<p>Wenn etwas anderes als Temperaturwerte gespeichert werden sollen, kann es auch sein, dass als <em>Magic Value</em> eine andere Zahl verwendet werden muss.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.smarthomeng.de/__trashed/feed</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Itemvorlagen nutzen (structs)</title>
		<link>https://www.smarthomeng.de/itemvorlagen-nutzen-structs</link>
					<comments>https://www.smarthomeng.de/itemvorlagen-nutzen-structs#comments</comments>
		
		<dc:creator><![CDATA[onkelandy]]></dc:creator>
		<pubDate>Thu, 30 May 2019 10:59:55 +0000</pubDate>
				<category><![CDATA[Beispiel-Implementierungen]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[Items]]></category>
		<category><![CDATA[Konfiguration]]></category>
		<category><![CDATA[struct]]></category>
		<category><![CDATA[Vorlagen]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=2381</guid>

					<description><![CDATA[Hinweis: Die hier beschriebene Funktion ist erst ab SmartHomeNG 1.6 verfügbar. Structs aus Plugins Die &#8222;struct&#8220; Vorlagen ermöglichen es zum einen, vorgegebene Item-Strukturen aus Plugins zu integrieren, zum anderen aber auch, eigene Vorlagen für immer wiederkehrende Item-Bäume bereitzustellen. Bei gleichen Gerätetypen ist die Struktur oft sehr ähnlich, was zu sehr<a class="moretag" href="https://www.smarthomeng.de/itemvorlagen-nutzen-structs"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<p><strong>Hinweis</strong>: Die hier beschriebene Funktion ist erst ab <strong>SmartHomeNG 1.6</strong> verfügbar.</p>
<h5>Structs aus Plugins</h5>
<p>Die &#8222;struct&#8220; Vorlagen ermöglichen es zum einen, vorgegebene Item-Strukturen aus Plugins zu integrieren, zum anderen aber auch, eigene Vorlagen für immer wiederkehrende Item-Bäume bereitzustellen.</p>
<p>Bei gleichen Gerätetypen ist die Struktur oft sehr ähnlich, was zu sehr vielen gleich aufgebauten Item-Definitionen führt. Leuchten, Jalousien, Bewegungsmelder können dabei ähnlich leicht vereinfacht werden wie Sollwerte, Vorgaben für Zustände des stateengine Plugins und vieles mehr. Zuerst ein Beispiel, wie mit nur einer Zeile ein Zeitschalt-Unteritem aus dem UZSU Plugin eingefügt werden kann. Da diese Vorlage bereits mit dem Plugin mitgeliefert wird, ist nichts weiter zu tun, also mittels struct Attribug darauf zuzugreifen. Welche Vorlagen von welchen Plugins bereitgestellt werden, ist zum einen in den jeweiligen plugin.yaml Dateien, zum anderen im Admin Tool einzusehen.</p>
<pre><code class="language-yaml">
    # item.yaml
    item:
        struct: uzsu.child
</code></pre>
<p>Durch diese Angabe entsteht beim Start von SmartHomeNG folgende Struktur, die zuvor noch bei jedem Item, das die Zeitschaltuhr nutzt, manuell angegeben werden musste:</p>
<pre><code class="language-yaml">
  # item.yaml
  item:
        uzsu:
            type: dict
            uzsu_item: ..
            cache: True
            visu_acl: rw
            
            active:
                type: bool
                eval: sh...activate(value)
                visu_acl: rw
</code></pre>
<h5>Eigene Vorlagen</h5>
<p>Folgendes Beispiel zeigt, wie Vorlagen selbst in der Datei etc/struct.yaml hinterlegt werden können. Generell bedarf es keinerlei besonderer Syntax. Strukturen werden dort genauso angelegt wie normale Item-Bäume. Die jeweils oberste Hierarchieebene definiert den Namen der Vorlage. Und genau auf dieses Item wird dann in der eigentlichen item.yaml Datei durch das Attribut <em>struct</em> verwiesen. Zuerst der Inhalt der struct.yaml für ein dimmbares Licht mit einigen Zusatzfunktionen:</p>
<pre><code class="language-yaml">
    # struct.yaml
    dimmervorlage:
        name: Vorlage für dimmbare Leuchten
	knx_dpt: 1
	visu_acl: rw
	type: bool
        knx_send: 0/0/0
        knx_cache: 0/0/0

	bwm:
		knx_dpt: 1
		visu_acl: rw
		type: bool

	zwangvalue:
		knx_dpt: 5001
		visu_acl: rw
		type: num
		cache: True

		zwangsstellung:
			knx_dpt: 2
			visu_acl: rw
			type: list
			enforce_updates: yes

	dimmen:
		knx_dpt: 5001
		visu_acl: rw
		type: num
		database: yes
		influxdb: yes
		sim: track

		sollwert:
			knx_dpt: 5001
			visu_acl: rw
			type: num
			enforce_updates: yes
			cache: True
</code></pre>
<p>Und hier die Einbindung in die yaml Datei im items Verzeichnis für ein Licht mit separaten warm- und kaltweißen Leuchtmitteln:</p>
<pre><code class="language-yaml">
# item.yaml
licht1:
    warm:
        <strong>struct: dimmervorlage</strong>
	knx_send: 3/0/21
	knx_cache: 3/0/27

	bwm:
		knx_send: 3/3/67
		knx_cache: 3/3/67

	zwangvalue:
		zwangsstellung:
			knx_send: 3/0/50
			knx_cache: 3/0/50

	dimmen:
		knx_send: 3/0/23
		knx_cache: 3/0/28

		sollwert:
			knx_send: 3/3/53

    kalt:
        <strong>struct: dimmervorlage</strong>
	knx_send: 3/0/24
	knx_cache: 3/0/29

	bwm:
		knx_send: 3/3/68
		knx_cache: 3/3/68

	zwangvalue:
		zwangsstellung:
			knx_send: 3/0/51
			knx_cache: 3/0/51

	dimmen:
		knx_send: 3/0/26
		knx_cache: 3/0/30

		sollwert:
			knx_send: 3/3/54
</code></pre>
<p>Was passiert hier? Es wird jeweils zuerst die Vorlage geladen, in der die Grundinformationen zu den Items verankert ist. Also Infos zu Typ, Cache, KNX DPT, Visu, Datenbank, etc. Diese Vorlage wird nun im tatsächlichen Item nur noch durch die KNX Adressen ergänzt. Etwaige gleich benannte Attribute werden dabei überschrieben (im Beispiel knx_send: 0/0/0).</p>
<p>In der Version 1.6.0 ist zu beachten, dass auch tatsächlich alle bereits definierten Attribute überschrieben werden, also beispielsweise auch Listeneinträge für eval_trigger. Möchte man also verschiedene Vorlagen mit verschiedenen eval_trigger Einträgen miteinander kombinieren, muss das Attribut nach den struct Einträgen manuell mit allen gewünschten Listeneinträgen überschrieben werden.</p>
<p>Zum Abschluss noch ein weiteres Beispiel, das neben einer klassischen Schaltfunktion für das entsprechende Item auch die Einschaltdauer über die Datenbankeinträge evaluiert. Dank relativer Item-Angaben können somit komplexere Konfigurationsblöcke problemlos wiederverwendet werden. Zum einen erleichtert dieser Ansatz ein Aktualisieren und Erweitern von Itemconfigs ungemein, zum anderen bleibt in den yaml Files die Übersicht bewahrt (auch wenn Letzteres Dank Admin Tool zukünftig weniger Relevanz haben wird). Folgend zwei separate Vorlagen:</p>
<pre><code class="language-yaml">
#struct.yaml
schaltervorlage:
    name: einfache Vorlage für Schalter
    sa:
        knx_dpt: 1
        visu_acl: rw
        type: bool
        database: yes
        cache: yes

    sperren:
        knx_dpt: 1
        visu_acl: rw
        type: bool

laufzeitvorlage:
    name: Vorlage für Laufzeitmessung
    laufzeit_1w:
        type: num
        visu_acl: ro
        crontab: init
        eval: (sh...sa.db('on', '1w') or 0) * 10080
        eval_trigger:
          - ..sa

    laufzeit_24h:
        type: num
        visu_acl: ro
        crontab: init
        eval: (sh...sa.db('on', '24h') or 0) * 1440
        eval_trigger:
          - ..sa
</code></pre>
<p>Die tatsächlichen Items benötigen schließlich wieder nur eine Angabe der KNX Adressen, alle anderen Funktionalitäten und Definition werden über die Vorlage eingebunden:</p>
<pre><code class="language-yaml">
#item.yaml
schalter1:
    <strong>struct: schaltervorlage</strong>
    sa: 
        knx_send: 1/1/1
    sperren:
        knx_send: 1/1/2

schalter2:
    <strong>struct: 
      - schaltervorlage
      - laufzeitvorlage</strong>

    sa: 
        knx_send: 1/1/3

    sperren:
        knx_send: 1/1/4

    laufzeit_1w:
        eval_trigger:
          - ..sa
          - ..sperren

schalter3:
    <strong>struct: schaltervorlage</strong>

    laufzeit:
          <strong>struct: laufzeitvorlage</strong>
</code></pre>
<p>Schalter1 greift ledigilich auf eine Vorlage (schaltervorlage) zurück, während Schalter2 mehrere Vorlagen als Liste miteinander kombiniert. Für Schalter2 existieren also auch die Einträge laufzeit_1w und laufzeit_24h, die eben die Einschaltdauer während der letzten Woche bzw. 24 Stunden von der Datenbank auslesen. Die Triggerung der laufzeit_1w soll in diesem Fall auch vom Sperritem erfolgen, während dies bei Schalter3 lediglich durch das in der Vorlage angegebene Schaltitem geschieht. Da Schalter3 keine Angaben zu den KNX Gruppenadressen macht, handelt es sich hier auch nicht um einen KNX Schalter, sondern z.B. ein Item, das nur über eine Logik oder die Visu geschalten werden kann/soll. Das schalter3 Beispiel zeigt auch, dass die Structs auf jeder beliebigen Hierarchieebene eingebunden werden können.</p>
<h5>Limitierungen</h5>
<p>Aktuell (inkl. Version 1.9) ist es nicht möglich, structs beliebig zu verschachteln. Das Einbeziehen von anderen structs in einem selbst kreierten struct ist nur auf Rootebene möglich, also beispielsweise so:</p>
<pre><code class="language-yaml">
    # struct.yaml
    beispielstruct1:
        test1:
            type: bool
            initial_value: True

    beispielstruct2:
        test2:
            type: bool
            initial_value: False

    combinedstruct:
        struct:
          - beispielstruct1
          - beispielstruct2
</code></pre>
<h5>Debugging</h5>
<p>Im Admin Interface sind alle structs, sowohl die von den aktiven Plugins als auch die selbst erstellten einsehbar. Hier lässt sich somit auch prüfen, wie die Structs miteinander kombiniert wurden. Ob und wie der Merge mit Attributen aus den Items geklappt hat, lässt sich am besten im Item Baum nachvollziehen.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.smarthomeng.de/itemvorlagen-nutzen-structs/feed</wfw:commentRss>
			<slash:comments>8</slash:comments>
		
		
			</item>
		<item>
		<title>Blinken &#8211; per Logik</title>
		<link>https://www.smarthomeng.de/blinken-per-logik</link>
					<comments>https://www.smarthomeng.de/blinken-per-logik#comments</comments>
		
		<dc:creator><![CDATA[gama]]></dc:creator>
		<pubDate>Sun, 04 Nov 2018 09:16:27 +0000</pubDate>
				<category><![CDATA[Beispiel-Implementierungen]]></category>
		<category><![CDATA[Logics]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[Alarm]]></category>
		<category><![CDATA[Blinklicht]]></category>
		<category><![CDATA[Logiken]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=2188</guid>

					<description><![CDATA[Die Idee für die Logik kam aus meinem Alarmmodul. Dort sollten im Alarm-/Feuer-/Panikfall die Lichter an der Hauswand und die Gartenbeleuchtung im Wechsel blinken. Aber auch für die Signalisieren auf Taster LEDs könnte die Logik ihren Einsatz finden. Beispielsweise um im Schlafzimmer einen Status per LED auszugeben, ohne dass die<a class="moretag" href="https://www.smarthomeng.de/blinken-per-logik"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<p>Die Idee für die Logik kam aus meinem Alarmmodul. Dort sollten im Alarm-/Feuer-/Panikfall die Lichter an der Hauswand und die Gartenbeleuchtung im Wechsel blinken. Aber auch für die Signalisieren auf Taster LEDs könnte die Logik ihren Einsatz finden. Beispielsweise um im Schlafzimmer einen Status per LED auszugeben, ohne dass die LED die ganze Nacht leuchtet.</p>
<p>Somit war der Grundstein für die Logik gelegt, die möglichst flexibel, für unterschiedliche Anwendungen, konfigurierbar sein soll.</p>
<h4>Funktion:</h4>
<p>Gesteuert wird die Logik über ein control-item, welches zugleich in der Logik Konfiguration als watch-item dient. Wir das control-item auf True gesetzt, so läuft die Logik. False stoppt die Blinkroutine.</p>
<p><span><strong>blink_cycles</strong> setzt Initial den Countdown, der mit jedem Aufruf um 1 nach unten zählt. Bei 0 stoppt die Logik und setzt zudem das control-item auf False. </span></p>
<p><span><strong>blink_interval</strong> bestimmt die Blinkabstand in Sekunden. </span></p>
<p><span>Mit <strong>items_cyclic</strong> und </span><span><strong>items_anticyclic</strong> werden die Items übergeben, die blinken sollen. Antizyklische Items werden immer dann aus/an wenn die zyklischen Items an/aus sind. </span></p>
<p>Bevor die items zum blinken gebracht werden, sichert die Logik die ursprünglichen Werte, die auch am Ende wieder hergestellt werden.</p>
<p>Um die Routine ohne aktives schalten der Items testen zu können, wurde noch dry_run aufgenommen.</p>
<p>Zusammengefasst ergibt sich folgende Beispiel-Konfiguration für <strong>../etc/logic.yaml</strong>:</p>
<pre class="line-numbers"><code class="language-yaml">visual_alarm:
    filename: blinker.py
    watch_item: HOME.alarm.action.blinkinglight
    set_items_cyclic:
        - AUSSEN.south.light.outer
        - AUSSEN.west.light.outer
    set_items_anticyclic:
        - AUSSEN.south.light.inner
        - AUSSEN.east.light.door
        - AUSSEN.west.light.nested
    set_blink_cycles: 4 # -1 for endless loop 
    set_blink_interval: 4
    dry_run: 1</code></pre>
<p>Alle items müssen vom Typ boolean sein, da nur einfache Schaltoperationen durchgeführt werden.</p>
<p>Die Logik lässt sich relativ einfach nutzen, indem das im watch_item verbundene Item, also im Beispiel <code class="language-python">HOME.alarm.action.blinkinglight</code>, auf True gesetzt wird. Die Logik ruft sich selbst solange auf, bis <code class="language-python">set_blink_cycles</code> erreicht ist oder vorher das watch_item auf False gesetzt wurde. Am Ende wird das watch_item auf von der Logik auf False gesetzt.</p>
<p>Die Logik selbst ist in <strong>../logics/blinker.py</strong>:</p>
<pre class="line-numbers"><code class="language-python">
#!/usr/bin/env python3
# vim: tabstop=2 softtabstop=2 shiftwidth=2 expandtab

# Logic blinker.py

# LOGIC config
# -------------------------------------------------------
# visual_alarm:
#   filename: blinker.py
#   watch_item: HOME.alarm.action.blinkinglight
#   set_items_cyclic:
#     - AUSSEN.south.light.outer
#     - AUSSEN.west.light.outer
#   set_items_anticyclic: 
#     - AUSSEN.south.light.inner
#     - AUSSEN.east.light.door 
#     - AUSSEN.west.light.nested
#   set_blink_cycles: -1 " -1: endless 
#   set_blink_interval: 2
#   dry_run: 0 

control_item_name = trigger['source'] 
control_item = sh.return_item(control_item_name)
triggered_by = trigger['by'] 


if control_item is not None:
  logger.info("LOGIC blinker.py: {0} triggered from source {1} by {2}".format(logic.name, control_item_name, triggered_by))

  # control_item_active = trigger['value']
  control_item_active = control_item()

  # set parameters from logic config
  if hasattr(logic, 'set_items_cyclic'):
    blink_items_cyclic = logic.set_items_cyclic

  if hasattr(logic, 'set_items_anticyclic'):
    blink_items_anticyclic = logic.set_items_anticyclic

  if hasattr(logic, 'set_blink_cycles'):
    blink_cycles = int(logic.set_blink_cycles)
  else:
    blink_cycles = 2
    logger.info("LOGIC blinker.py: no blink cycles set, setting to default: {2}".format(blink_cycles))

  if hasattr(logic, 'set_blink_interval'):
    blink_interval = int(logic.set_blink_interval)
  else:
    blink_interval = 2
    logger.info("LOGIC blinker.py: no blink interval set, setting to default: {2}".format(blink_interval))

  if hasattr(logic, 'dry_run'):
    dry_run = (int(logic.dry_run) &gt; 0)
  else:
    dry_run = False

  if control_item_active == True:

    # first call?
    if not hasattr(logic, 'blink_init'):
      logger.info("LOGIC blinker.py: initiating {0} blinks for {1} cyclic and {2} anti-cyclic items".format(blink_cycles, len(blink_items_cyclic), len(blink_items_anticyclic)))
      logic.blink_init = True

      blink_items = blink_items_cyclic + blink_items_anticyclic
      if len(blink_items) &gt; 0:
        # SAVE item states
        logic.saved_items = {}
        for item_name in blink_items:
          item = sh.return_item(item_name)
          logic.saved_items[item_name] = item()
          logger.info("LOGIC blinker.py: save {0} = {1}".format(item_name, item()))

      if dry_run == True:
        logger.warn("LOGIC blinker.py: test mode, dry run active")

      else:
        logger.warn("LOGIC blinker.py: no blink items set")
 

    # prepare blink
    if hasattr(logic, 'blink_value'):
      logic.blink_value = not logic.blink_value
    else:
      logic.blink_value = True

    if hasattr(logic, 'blink_countdown'):
      logic.blink_countdown -= 1
    else:
      logic.blink_countdown = blink_cycles
     
    # any blinks left?
    if logic.blink_countdown &gt; 0 or blink_cycles == -1:
      if blink_cycles == -1:
        logger.info("LOGIC blinker.py BLINK (endless)")
      else:
        logger.info("LOGIC blinker.py BLINK ({0} cycles remaining)".format(logic.blink_countdown))

      # set all cyclic items
      for item_name in blink_items_cyclic:
        item = sh.return_item(item_name)
        logger.info("LOGIC blinker.py SET {item} to {value})".format(item=item_name, value=logic.blink_value))
        if dry_run == False:
          item(logic.blink_value)

      # set all anti-cyclic items
      for item_name in blink_items_anticyclic:
        item = sh.return_item(item_name)
        logger.info("LOGIC blinker.py SET {item} to {value})".format(item=item_name, value=(not logic.blink_value)))
        if dry_run == False:
          item(not logic.blink_value)

      sh.trigger("logics.{0}".format(logic.name), by=trigger['by'], source=trigger['source'], value=trigger['value'], dt=sh.now() + datetime.timedelta(seconds=blink_interval))

    else:
      logger.info("LOGIC blinker.py countdown finished, set control item to False")
      control_item(False) # this triggers logic again!

  else:
    logger.info("LOGIC blinker.py control item set to false: stop blink logic, restore saved item values")

    # RESTORE item states
    if hasattr(logic, 'saved_items'):
      for item_name in logic.saved_items:
        item = sh.return_item(item_name)
        value = logic.saved_items[item_name]
        logger.info("LOGIC blinker.py: restore {0} = {1}".format(item_name, item()))
        if dry_run == False:
          item(value)
      
    # reset persistent values
    if hasattr(logic, 'saved_items'):
      delattr(logic, 'saved_items')  
    if hasattr(logic, 'blink_countdown'):
      delattr(logic, 'blink_countdown')  
    if hasattr(logic, 'blink_value'):
      delattr(logic, 'blink_value')  
    if hasattr(logic, 'blink_init'):
      delattr(logic, 'blink_init')  
    
else:
  logger.info("LOGIC blinker.py triggered without source... ignoring...")</code></pre>
<p>&nbsp;</p>
<h4>Überarbeitung im Januar 2021:</h4>
<p>Diese Logik wurde aufgrund weitere Anforderungen im Januar 2021 ergänzt. (siehe <a href="https://knx-user-forum.de/forum/supportforen/smarthome-py/1600954-blinker-py-konfigurieren">Thread im Forum</a>) Die folgende Version vom 18. Januar 2021 blinkt mit einem oder zwei Items:</p>
<p>&nbsp;</p>
<pre class="line-numbers"><code class="language-python">
#!/usr/bin/env python3
# vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab

# Logic blinker2.py

# LOGIC config
# -------------------------------------------------------
# visual_alarm:
#     filename: blinker2.py
#     watch_item: HOME.alarm.action.blinkinglight
#     set_items_cyclic:
#         - AUSSEN.south.light.outer
#         - AUSSEN.west.light.outer
#     set_items_anticyclic:
#         - AUSSEN.south.light.inner
#         - AUSSEN.east.light.door
#         - AUSSEN.west.light.nested
#     set_blink_cycles: -1 ' -1: endless
#     set_blink_interval: 2
#     dry_run: 0

control_item_name = trigger['source']
control_item = sh.return_item(control_item_name)
triggered_by = trigger['by']

if control_item is not None:
    logger.info(f'LOGIC blinker.py: {logic.name} triggered from source {control_item_name} by {triggered_by}')

    # control_item_active = trigger['value']
    control_item_active = control_item()

    # set parameters from logic config
    blink_items_cyclic = []
    if hasattr(logic, 'set_items_cyclic'):
        blink_items_cyclic = logic.set_items_cyclic
    if blink_items_cyclic == 'None':
        blink_items_cyclic = []
    if isinstance(blink_items_cyclic, str):
        blink_items_cyclic = [blink_items_cyclic, ]

    # do we have blink items?
    if not isinstance(blink_items_cyclic, list) or len(blink_items_cyclic) == 0:
        logger.info('LOGIC blinker.py: error, no cyclic blink items set. Aborting')
    else:

        blink_items_anticyclic = []
        if hasattr(logic, 'set_items_anticyclic'):
            blink_items_anticyclic = logic.set_items_anticyclic
        if blink_items_anticyclic == 'None':
            blink_items_anticyclic = []
        elif isinstance(blink_items_anticyclic, str):
            blink_items_anticyclic = [blink_items_anticyclic, ]

        # did we get strange data?
        if not isinstance(blink_items_anticyclic, list):
            blink_items_anticyclic = []

        if hasattr(logic, 'set_blink_cycles'):
            blink_cycles = int(logic.set_blink_cycles)
        else:
            blink_cycles = 2
            logger.info(f'LOGIC blinker.py: no blink cycles set, setting to default: {blink_cycles}')

        if hasattr(logic, 'set_blink_interval'):
            blink_interval = int(logic.set_blink_interval)
        else:
            blink_interval = 2
            logger.info(f'LOGIC blinker.py: no blink interval set, setting to default: {blink_interval}')

        if hasattr(logic, 'dry_run'):
            dry_run = (int(logic.dry_run) &gt; 0)
        else:
            dry_run = False

        if control_item_active:

            # first call?
            if not hasattr(logic, 'blink_init'):
                logger.info(f'LOGIC blinker.py: initiating {blink_cycles} blinks for {len(blink_items_cyclic)} cyclic and {len(blink_items_anticyclic)} anti-cyclic items')
                logic.blink_init = True

                blink_items = blink_items_cyclic + blink_items_anticyclic
                if len(blink_items) &gt; 0:
                    # SAVE item states
                    logic.saved_items = {}
                    for item_name in blink_items:
                        item = sh.return_item(item_name)
                        if item:
                            logic.saved_items[item_name] = item()
                            logger.info(f'LOGIC blinker.py: save {item_name} = {item()}')

                    if dry_run:
                        logger.warn('LOGIC blinker.py: test mode, dry run active')

                else:
                    logger.warn('LOGIC blinker.py: no blink items set')

            # prepare blink
            if hasattr(logic, 'blink_value'):
                logic.blink_value = not logic.blink_value
            else:
                logic.blink_value = True

            if hasattr(logic, 'blink_countdown'):
                logic.blink_countdown -= 1
            else:
                logic.blink_countdown = blink_cycles

            # any blinks left?
            if logic.blink_countdown &gt; 0 or blink_cycles == -1:
                if blink_cycles == -1:
                    logger.info('LOGIC blinker.py BLINK (endless)')
                else:
                    logger.info(f'LOGIC blinker.py BLINK ({logic.blink_countdown} cycles remaining)')

                # set all cyclic items
                for item_name in blink_items_cyclic:
                    item = sh.return_item(item_name)
                    logger.info(f'LOGIC blinker.py SET {item_name} to {logic.blink_value}')
                    if not dry_run:
                        item(logic.blink_value)
                        print(f'    - {item.id()}:{item()}')

                # set all anti-cyclic items
                for item_name in blink_items_anticyclic:
                    item = sh.return_item(item_name)
                    logger.info(f'LOGIC blinker.py SET {item_name} to {not logic.blink_value}')
                    if not dry_run:
                        item(not logic.blink_value)
                        print(f'    - {item.id()}:{item()}')

                sh.trigger(f'logics.{logic.name}', by=trigger['by'], source=trigger['source'], value=trigger['value'], dt=sh.now() + datetime.timedelta(seconds=blink_interval))

            else:
                logger.info('LOGIC blinker.py countdown finished, set control item to False')
                control_item(False)  # this triggers logic again!

        else:
            logger.info('LOGIC blinker.py control item set to false: stop blink logic, restore saved item values')

            # RESTORE item states
            if hasattr(logic, 'saved_items'):
                for item_name in logic.saved_items:
                    item = sh.return_item(item_name)
                    value = logic.saved_items[item_name]
                    logger.info(f'LOGIC blinker.py: restore {item_name} = {item()}')
                    if not dry_run:
                        item(value)

            # reset persistent values
            if hasattr(logic, 'saved_items'):
                delattr(logic, 'saved_items')
            if hasattr(logic, 'blink_countdown'):
                delattr(logic, 'blink_countdown')
            if hasattr(logic, 'blink_value'):
                delattr(logic, 'blink_value')
            if hasattr(logic, 'blink_init'):
                delattr(logic, 'blink_init')

else:
    logger.info('LOGIC blinker.py triggered without source... ignoring...')
</code></pre>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.smarthomeng.de/blinken-per-logik/feed</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Reverse Proxy für Websocket der VISU mit Apache</title>
		<link>https://www.smarthomeng.de/reverse-proxy-fuer-websocket-der-visu-mit-apache</link>
					<comments>https://www.smarthomeng.de/reverse-proxy-fuer-websocket-der-visu-mit-apache#respond</comments>
		
		<dc:creator><![CDATA[Thomas Creutz]]></dc:creator>
		<pubDate>Tue, 18 Sep 2018 06:36:52 +0000</pubDate>
				<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Reverse Proxy]]></category>
		<category><![CDATA[smartVISU]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=2095</guid>

					<description><![CDATA[Hallo Zusammen, ich wurde vor längerer Zeit gefragt, ob ich den Weg meiner Implementierung mit Apache hier niederschreiben könnte, was ich hiermit erledigen möchte. Warum man das macht und wie das ganze mit NGINX funktioniert hat psilo sehr gut auf dieser Seite erklärt! Deswegen möchte ich auch hier nur auf die<a class="moretag" href="https://www.smarthomeng.de/reverse-proxy-fuer-websocket-der-visu-mit-apache"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<p>Hallo Zusammen,</p>
<p>ich wurde vor längerer Zeit gefragt, ob ich den Weg meiner Implementierung mit Apache hier niederschreiben könnte, was ich hiermit erledigen möchte.</p>
<p>Warum man das macht und wie das ganze mit NGINX funktioniert hat <a href="https://www.smarthomeng.de/author/psilo">psilo</a> sehr gut auf <a href="https://www.smarthomeng.de/nginx-als-reverseproxy">dieser Seite</a> erklärt!</p>
<p>Deswegen möchte ich auch hier nur auf die Änderungen zu Apache eingehen und setzte also Voraus, dass man weiß was man erreichen will und auch über die genannte Seite von psilo geschaut hat!</p>
<p>Als kleine Änderung will ich hier gleich anmerken, dass ich keine extra Maschine als Reverse Proxy einsetzte, da ich bei mir soweit alles abgesichert habe und darin einige Erfahrung habe <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Damit gehe ich also auch davon aus, dass ihr Apache auch für eure smartVISU einsetzt, wie ich es mache. Falls nicht müsst ihr natürlich apache nachinstallieren.</p>
<p>Unter Debian/Ubuntu/Raspbian funktioniert das mit:</p>
<pre><code class="language-bash">sudo apt-get update
sudo apt-get install apache2</code></pre>
<p>Unter Ubuntu 18.04 habe ich auch keine weiteren Module (wie libapache2-mod-XXX) für Apache benötigt. Ob dies bei allen Debian-basierenden Distributionen der Fall ist müsste man im Einzelfall prüfen. Man wird es auf jeden Fall merken, wenn sich die kommenden Befehle zum aktivieren der Module nicht durchführen lassen.</p>
<p>Nun müssen wir die folgenden Module aktivieren:</p>
<pre><code class="language-bash">sudo a2enmod proxy_wstunnel
sudo a2enmod rewrite
sudo a2enmod setenvif</code></pre>
<p>Bei Apache arbeite ich gerne nach dem modularen Prinzip, weswegen ich mir für die Einstellungen die ich brauche, einer eigene Konfigurationsdatei mit dem Namen <code>/etc/apache2/smartvisu.conf</code> angelegt habe, die ich hier entsprechend erläutern möchte.</p>
<pre><code class="language-apacheconf">
&lt;IfModule mod_rewrite.c&gt;
   RewriteEngine on

   # Eine Umleitung vom Ordner zur index.php (es gab da mal einen Bug,
   # in der alten VISU, keine Ahnung ob das noch aktuell ist, schaden
   # tut es aber nicht, man kann es aber gerne auch weglassen)
   RewriteCond %{REQUEST_URI} ^/smartVISU$ [NC,OR]
   RewriteCond %{REQUEST_URI} ^/smartVISU/$ [NC]
   RewriteRule .* /smartVISU/index.php [R=302,L]

   # Mit dieser Definition wird der Reverse Proxy für Websocket aktiviert
   # Da wie oben schon erwähnt, die VISU und SH bei mir auf dem lokalen Host
   # läuft, verwende ich hier als Ziel auch localhost. Das kann man aber
   # natürlich Anpassen und soll auch nur als Beispiel dienen.
   &lt;IfModule mod_proxy.c&gt;

      ProxyPreserveHost On
      ProxyVia On

      # socket.io 1.0+ starts all connections with an HTTP polling request
      RewriteCond %{QUERY_STRING} transport=polling [NC]
      RewriteRule /(.*) http://localhost:2424/$1 [P]

      # When socket.io wants to initiate a WebSocket connection, it sends an
      # "upgrade: websocket" request that should be transferred to ws://
      RewriteCond %{HTTP:Upgrade} websocket [NC]
      RewriteRule /(.*) ws://localhost:2424/$1 [P]
   &lt;/IfModule&gt;

   # Hier ist Platz für spezielle Ausnahmen (die wie unten mit SetEnvIf
   # gezeigt nicht abgebildet werden können), z.B. für eine Manifest-Datei die
   # ich mir in die VISU rein Programmiert habe. Hier wird beim Auffinden
   # des entsprechenden Query-Strings die Umgebungsvariable
   # no_auth_required auf 1 gesetzt, was dann weiter unten ausgewertet wird
   # und dann dazu führt, dass keine Anmeldung erforderlich ist
   RewriteCond %{QUERY_STRING} page=manifest
   RewriteRule ^/smartVISU/index.php - [E=no_auth_required:1]
   # !! Das ist natürlich nur ein Beispiel und wäre bei euch nicht erforderlich !!

&lt;/IfModule&gt;

# Hier definiere ich wann man sich anmelden muss und wann nicht und
# das gilt dabei für den kompletten Webserver Stamm also ab der Wurzel.
# Das ist !Wichtig!, da so auch automatisch die Websocket-Verbindung
# per Basic Auth geschützt wird!
&lt;Location /&gt;
   # Hier kann ich dann wieder Dinge freigeben, die ohne Anmeldung funktionieren sollen
   # (wie auch weiter oben im Beispiel, nur das es mit SetEnvIf etwas einfacher geht)
   # z.B. kann sich jeder meine Temperatur Statistik im Unterordner /mytemplogger ohne
   # Anmeldung ansehen, dazu setzte ich wieder die Umgebungsvariable no_auth_required auf 1
   SetEnvIf Request_URI ^/mytemplogger no_auth_required=1

   # Dann definiere ich die Basic Auth Parameter
   AuthName "Private"
   AuthType Basic
   AuthUserFile /etc/apache2/htpasswd
   Require valid-user

   # Hier gebe ich an, dass man sich über die lokalen Netze nicht anmelden muss,
   # dass muss also jeder für sich Anpassen. Wer kein IPv6 hat kann die /64 Adressen
   # natürlich auch weg lassen
   Require ip 192.168.XX.0/24 2a02:810c:XXX:XXX::/64 fd00:XXXX:XXXX:XXXX::/64 fe80::/64
   # Und hier wird die Ausnahme mit der Umgebungsvariable definiert, so kann man einfacher
   # Seiten oder Aufrufe als Ausnahme definieren
   Require env no_auth_required

&lt;/Location&gt;</code></pre>
<p>Dann müssen wir uns natürlich die zuvor verwendete <code>/etc/apache2/htpasswd</code> anlegen:</p>
<pre><code class="language-bash">htpasswd -cB /etc/apache2/htpasswd BENUTZER
New password: MEINSUPERPASSWORD
Re-type new password: MEINSUPERPASSWORD
Adding password for user visu

# Und dann die Rechte anpassen:
chmod 660 /etc/apache2/htpasswd</code></pre>
<p>Wobei BENUTZER der Benutzername ist den man anlegen möchte. Es können natürlich mehrere Benutzer angelegt werden. Man sollte aber hier wirklich ein sicheres Passwort verwenden, da dies nicht vor Brute-Force Angriffen geschützt ist. Wobei man ganz klar die Webseite nochmal in mehreren wegen etwas weiter Schützen kann. Aber dazu später mehr.</p>
<p>Nun kann man auf jeden fall schon seine Konfiguration für den virtuellen Host anpassen. Im Standardfall wäre dass die <code>/etc/apache2/sites-enabled/000-default.conf</code> oder eben die von euch genutzte Datei. Da ich bei mir mehrere virtuelle Hosts habe, die jewels ein eigenes Zertifikat (Stichwort SSL) haben (für internen Host &#8211; ohne SSL, für externen Host &#8211; mit SSL, für den vom Internet und Intern aus erreichbaren IPv6 Host &#8211; mit SSL), kann ich jetzt die <code>smartvisu.conf</code> überall einbinden und hab eine zentrale Stelle für die Anpassungen.</p>
<p>Die nötige Anpassung zum Einbinden der Konfiguration sieht wie folgt aus:</p>
<p>Innerhalb des <code>&lt;VirtualHost&gt;&lt;/VirtualHost&gt;</code> Blocks muss nur noch folgende Zeile eingefügt werden:</p>
<p><code class="language-apacheconf">Include /etc/apache2/smartvisu.conf</code></p>
<p>Jetzt könnte man den Apache2 neustarten und testen.</p>
<p><code class="language-bash">service apache2 restart</code></p>
<h2>Nützliche Tipps zur Absicherung</h2>
<p>Zum Absichern gibt es mehrere Faktoren &#8211; vieles hier setzt zwar auf Verschleierung/Tarnung (was eine gute Methode ist, Angriffe gar nicht erst aufkommen zu lassen), aber natürlich nicht ausschließlich:</p>
<ul style="list-style-type: lower-alpha">
<li>) Die Webseite auf <strong>jeden</strong> Fall mit SSL absichern!! Auch ich verwende für die externen Zugriffe den kostenfreien Service von Let’s Encrypt. Möglich wäre aber auch ein self-signed Zertifikat (Anleitungen gibt es dazu wie Sand am Meer) aber eben nicht so schön und nicht ganz so sicher, oder wer von euch prüft schon den Fingerabdruck den Zertifikats?!</li>
<li>) die Brute-Force Angriffe auf die Basic-Anmeldung kann man ganz einfach mit fail2ban Abfangen/-mildern (Abmildern deswegen, da es möglich wäre auch ein Angriff von mehreren IPs zu koordinieren, was fail2ban nicht abfangen könnte), was ich trotzdem nur jeden empfehlen kann, weswegen ich es auch kurz erklären möchte:<br />
Zuerst installiert man das Paket mit <code class="language-bash">sudo apt-get install fail2ban</code><br />
dann erstellen wir uns eine local.conf, in dem wir das definieren was nicht in der Standardkonfiguration erfasst ist. Man könnte zwar auch die Standardkonfiguration unter <code>/etc/fail2ban/jail.conf</code> bearbeiten, aber übersichtlicher wird es mit meiner vorgeschlagenen Variante. Dazu öffnen wir mit dem Editor unserer Wahl die Datei <code>/etc/fail2ban/jail.d/local.conf</code> und aktivieren die Jail für die Definition von <code>apache-auth</code> wie folgt:</p>
<pre><code>[apache-auth]
enabled = true
</code></pre>
<p>und danach können wir fail2ban neu laden mit <code class="language-bash">sudo fail2ban-client reload</code> und den Status prüfen mit <code class="language-bash">sudo fail2ban-client status</code>.<br />
<strong><br />
Wichtig</strong>: Hat man den Protokollpfad seines Apache Vhosts modifiziert, muss man den Pfad für die Jail nochmals prüfen und ggf. in unserer local.conf überschreiben. Prüfen kann man das nochmal in der Datei <code>/etc/fail2ban/jail.conf</code> bzw. <code>/etc/fail2ban/paths-arch.conf</code> (dort steht bei meinem Ubuntu die Variable apache_error_log).</li>
<li>) Keine Standard-Ports für den Zugriff auf den Webserver von Extern verwenden. Das hält die ganzen Scanner davon ab die Seite zufällig zu finden. Natürlich wird ein gezielter Angriff (mit Port-Scan) die Seite trotzdem aufdecken, egal welcher Port verwendet wird. Dies wiederum könnte man mit Port Knocking (<a href="http://www.cipherdyne.org/fwknop/" target="_blank" rel="noopener">fwknop</a>/<a href="http://www.zeroflux.org/projects/knock" target="_blank" rel="noopener">knockd</a>) ausschalten, finde ich aber überflüssig, da es das ganze wieder unnötig verkompliziert.</li>
<li>) zusätzlichen Schutz würde auch noch eine zwei-Faktor Anmeldung bringen, z.B. über den Google Authenticator, der den offener Standard OATH (Initiative for Open Authentication) umsetzt und leicht verwendet werden kann. Dazu verweise ich aber z.B. auf <a href="https://www.linuxjournal.com/content/two-factor-authentication-system-apache-and-ssh" target="_blank" rel="noopener">diese Anleitung</a>.</li>
<li>) Client Zertifikate wären natürlich auch möglich, halte ich aber auch für Übertrieben/zu kompliziert und diese können genau so gut über einen Trojaner geklaut werden &#8211; dann lieber 2-Faktor <img src="https://s.w.org/images/core/emoji/15.0.3/72x72/1f609.png" alt="😉" class="wp-smiley" style="height: 1em; max-height: 1em;" /></li>
<li>) den Webserver vor Zugriffen aus dem Ausland schützen wäre natürlich auch unter Apache möglich, alternativ mit iptables. Aber mal ehrlich, wenn ich im Urlaub bin will ich auch darauf zugreifen und nicht extra dran denken müssen es frei zu schalten.</li>
<li>) die Seite nicht öffentlich im Web verlinken, da b) sonnst auch keinen Sinn macht. Nicht dass wir was zu verbergen haben &#8211; aber wie heist es so schön: Schlafende Hunde soll man nicht wecken</li>
<li>) dafür sorgen dass das System aktuell gehalten wird &#8211; Stichpunkt <a href="https://www.google.de/search?q=unattended-upgrades" target="_blank" rel="noopener">UnattendedUpgrades</a>, was es sowohl unter Debian und Ubuntu gibt. Auch sollte nur eine Distribution eingesetzt werden, welche auch noch vom Anbieter unterstützt wird.</li>
<li>) Keine öffentliche (also ohne Anmeldung zugängliche) Index Seite auf dem internen Webserver anlegen, wo mögliche öffentliche Inhalte &#8222;sichtbar&#8220; verlinkt sind. Auch sollten die öffentlichen Inhalte (wenn überhaupt unbedingt benötigt &#8211; man kann diese ja auch nur Intern erreichbar machen) nicht über Standard-Ordner laufen, wie z.B. wp (WordPress), Joomla, phpmyadmin, Webmail usw&#8230;<br />
Die Gefahr dabei besteht, dass in den gehosteten Inhalten, eine Sicherheitslücke dafür sorgt, dass jemand sich Zugriffsrechte auf den Webserver erschleichen kann, was dann wieder durch Intensivierung des Angriffs über eine Rechteausweitung zu ROOT-Rechte führen kann!!</li>
</ul>
<p><strong>TODO</strong>: Konfiguration LetsEncrypt</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.smarthomeng.de/reverse-proxy-fuer-websocket-der-visu-mit-apache/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Fehlerbehandlung für Plugins bei nicht installierten Python Packages</title>
		<link>https://www.smarthomeng.de/fehlerbehandlung-fuer-plugins-bei-nicht-installierten-python-packages</link>
					<comments>https://www.smarthomeng.de/fehlerbehandlung-fuer-plugins-bei-nicht-installierten-python-packages#comments</comments>
		
		<dc:creator><![CDATA[Martin Sinn]]></dc:creator>
		<pubDate>Sun, 12 Aug 2018 08:54:08 +0000</pubDate>
				<category><![CDATA[Plugins]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[Entwicklung]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=1973</guid>

					<description><![CDATA[UPDATE: Im develop Branch (also für SmartHomeNG v1.6) ist eine allgemein gültige Lösung implementiert. (Danke an ohinckel für die Idee). Ab der Version muss der Fehler nicht mehr im einzelnen Plugin abgefangen werden, es sei denn, man möchte nicht das Laden des Plugins unterbinden, sondern vielleicht nur einzelne Funktionen des<a class="moretag" href="https://www.smarthomeng.de/fehlerbehandlung-fuer-plugins-bei-nicht-installierten-python-packages"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<p><strong>UPDATE</strong>:</p>
<p>Im develop Branch (also für SmartHomeNG v1.6) ist eine allgemein gültige Lösung implementiert. (Danke an ohinckel für die Idee).</p>
<p>Ab der Version muss der Fehler nicht mehr im einzelnen Plugin abgefangen werden, es sei denn, man möchte nicht das Laden des Plugins unterbinden, sondern vielleicht nur einzelne Funktionen des Plugins deaktivieren.</p>
<hr />
<p>&nbsp;</p>
<p>Wenn ein Plugin ein spezielles Python Package benötigt (Requirement) und dieses auf dem System des Anwenders nicht installiert ist, wird im Log beim ersten Zugriff auf Funktionen dieses Packages eine Exception in das Logfile geschrieben.</p>
<p>Für viele Anwender ist es schwierig, aus der Fehlermeldung auf die eigentliche Ursache zu schließen.</p>
<p>Durch einen kleinen Kniff im Plugin, kann im Logfile eine klare Fehlermeldung geschrieben werden. Außerdem kann das Laden des Plugins unterbunden werden, um Folgefehler zu vermeiden.</p>
<p>&nbsp;</p>
<h3>Vorgehen</h3>
<p>Die zwei notwendigen Änderungen sind hier Beispiel des <strong>homematic</strong> Plugins und des benötigten Packages <strong>pyhomematic</strong> beschrieben.</p>
<p>&nbsp;</p>
<p>Normalerweise wird das Package folgendermaßen importiert:</p>
<pre><code class="language-python">
from pyhomematic import HMConnection
</code></pre>
<p>Um den Fehler zu behandeln, werden folgende zwei Änderungen vorgenommen:</p>
<ol>
<li>Um den Fehler zu erkennen, wird die <strong>import</strong> Anweisung in ein <strong>try/except</strong> Konstrukt eingebettet und abhängig vom Ergebnis eine Variable gesetzt. (Zeilen 8 bis 12 im folgenden Beispiel)</li>
<li>Um den erkannten Fehler auszuwerten, wird eine <strong>If-Anweisung</strong> zur<strong>__init__</strong> Methode hinzugefügt (Zeilen 37 bis 41), die Im Fehlerfall einen sinnvollen Log-Eintrag schreibt und durch das setzen der Variable self._init_complete signaliseiert, dass das Plugin sich nicht fehlerfrei initialisieren konnte. Das anschließende <strong>return</strong> sorgt dann noch für den Abbruch der Initialisierung.</li>
</ol>
<p>&nbsp;</p>
<pre data-line="8-12,37-41"><code class="language-python">
#  You should have received a copy of the GNU General Public License
#  along with SmartHomeNG. If not, see &lt;http://www.gnu.org/licenses/&gt;.
#
#########################################################################

import logging

try:
    from pyhomematic import HMConnection
    REQUIRED_PACKAGE_IMPORTED = True
except:
    REQUIRED_PACKAGE_IMPORTED = False

from lib.module import Modules
from lib.model.smartplugin import *

from time import sleep


class Homematic(SmartPlugin):
    """
    Main class of the Plugin. Does all plugin specific stuff and provides
    the update functions for the items
    """
    
    PLUGIN_VERSION = '1.5.0'
    
    connected = False
    

    def __init__(self, sh, *args, **kwargs):
        """
        Initalizes the plugin. The parameters descriptions for this method are pulled from the entry in plugin.yaml.
        """
        self.logger = logging.getLogger(__name__)

        # Exit if the required package(s) could not be imported
        if not REQUIRED_PACKAGE_IMPORTED:
            self.logger.error("{}: Unable to import Python package 'pyhomematic'".format(self.get_fullname()))
            self._init_complete = False
            return

        # get the parameters for the plugin (as defined in metadata plugin.yaml):
        #   self.param1 = self.get_parameter_value('param1')


</code></pre>
<p>Im Logfile wird der Fehler dann durch zwei Zeilen, wie im folgenden Beispiel angezeigt:</p>
<pre><code class="language-batch">
2018-08-12  09:59:03 ERROR    plugins.homematic   homematic_hm1: Unable to import Python package 'pyhomematic'
2018-08-12  09:59:03 ERROR    lib.plugin          Plugins: Plugin 'homematic' initialization failed, plugin not loaded
</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://www.smarthomeng.de/fehlerbehandlung-fuer-plugins-bei-nicht-installierten-python-packages/feed</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Entfernungsmessung mit ESP32 und SmartHomeNG &#8211; Teil 2: Anbindung eines SSD1306 OLED Displays</title>
		<link>https://www.smarthomeng.de/entfernungsmessung-mit-esp32-und-smarthomeng-teil-2-anbindung-eines-ssd1306-oled-displays</link>
					<comments>https://www.smarthomeng.de/entfernungsmessung-mit-esp32-und-smarthomeng-teil-2-anbindung-eines-ssd1306-oled-displays#respond</comments>
		
		<dc:creator><![CDATA[Marc René Frieß]]></dc:creator>
		<pubDate>Sat, 19 May 2018 17:46:32 +0000</pubDate>
				<category><![CDATA[Beispiel-Implementierungen]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[ESP32]]></category>
		<category><![CDATA[OLED Display]]></category>
		<category><![CDATA[SSD1306]]></category>
		<category><![CDATA[Wasserstand]]></category>
		<category><![CDATA[Webservices]]></category>
		<category><![CDATA[Zisterne]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=1671</guid>

					<description><![CDATA[Als nächsten Schritt meines Projekts zur Überwachung des Wasserstands meiner Zisterne, habe ich ein SSD1306 OLED Display ergänzt, das in meiner Garage in der Nähe der Pumpe installiert werden soll. Hier möchte ich die Wasserhöhe und &#8211; eines Tages &#8211; den Wasserstand anzeigen. Als Vorarbeiten wird im Wesentlichen der Artikel<a class="moretag" href="https://www.smarthomeng.de/entfernungsmessung-mit-esp32-und-smarthomeng-teil-2-anbindung-eines-ssd1306-oled-displays"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<p>Als nächsten Schritt meines Projekts zur Überwachung des Wasserstands meiner Zisterne, habe ich ein SSD1306 OLED Display ergänzt, das in meiner Garage in der Nähe der Pumpe installiert werden soll. Hier möchte ich die Wasserhöhe und &#8211; eines Tages &#8211; den Wasserstand anzeigen.</p>
<p>Als Vorarbeiten wird im Wesentlichen der Artikel &#8222;<a href="https://www.smarthomeng.de/entfernungsmessung-auf-basis-eines-esp32-und-smarthomeng" target="_blank" rel="noopener">Entfernungsmessung auf Basis eines ESP32 und SmartHomeNG</a>&#8220; vorausgesetzt.<a href="https://www.smarthomeng.de/entfernungsmessung-auf-basis-eines-esp32-und-smarthomeng"></a></p>
<p>Mittlerweile bin ich bei der Messung des Ultraschallsignales des HR-SR04 allerdings auf die Arduino Bibliothek <a href="https://playground.arduino.cc/Code/NewPing" target="_blank" rel="noopener">NewPing</a> umgestiegen, die die Messung übernimmt:<img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2018/05/newping_lib.jpg" alt="" width="726" height="96" class="alignnone size-full wp-image-1710" srcset="https://www.smarthomeng.de/wp-content/uploads/2018/05/newping_lib.jpg 726w, https://www.smarthomeng.de/wp-content/uploads/2018/05/newping_lib-300x40.jpg 300w" sizes="(max-width: 726px) 100vw, 726px" />Als Display kommt ein kleines OLED Display mit SSD 1306 Controller zum Einsatz (<a href="https://www.az-delivery.de/products/0-96zolldisplay" target="_blank" rel="noopener">https://www.az-delivery.de/products/0-96zolldisplay</a>, ca. 7 Euro).</p>
<p>Das Display wird wie folgt zusätzlich zum HC-SR04 angeschlossen:</p>
<p><img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2018/05/Untitled-Sketch-2_Steckplatine.png" alt="" width="529" height="460" class="alignnone wp-image-1673" srcset="https://www.smarthomeng.de/wp-content/uploads/2018/05/Untitled-Sketch-2_Steckplatine.png 1098w, https://www.smarthomeng.de/wp-content/uploads/2018/05/Untitled-Sketch-2_Steckplatine-300x261.png 300w, https://www.smarthomeng.de/wp-content/uploads/2018/05/Untitled-Sketch-2_Steckplatine-768x667.png 768w, https://www.smarthomeng.de/wp-content/uploads/2018/05/Untitled-Sketch-2_Steckplatine-1024x890.png 1024w" sizes="(max-width: 529px) 100vw, 529px" /></p>
<p>Als Bibliothek kommt die &#8222;<a href="https://github.com/ThingPulse/esp8266-oled-ssd1306" target="_blank" rel="noopener">ESP8266 and ESP32 Oled Driver for SSD1306 display</a>&#8220; von Daniel Eichhorn und Fabrice Weinberg in Version 4.0.0 zum Einsatz:</p>
<p><img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2018/05/display_lib.jpg" alt="" width="734" height="90" class="alignnone size-full wp-image-1685" srcset="https://www.smarthomeng.de/wp-content/uploads/2018/05/display_lib.jpg 734w, https://www.smarthomeng.de/wp-content/uploads/2018/05/display_lib-300x37.jpg 300w" sizes="(max-width: 734px) 100vw, 734px" /></p>
<p>Der angepasst Sourcecode sieht nun wie folgt aus. Es ist dabei zu beachten, dass das Webservices- Plugin inzwischen über die REST Schnittstelle angesteuert wird. Weiterhin sind alle Log-Outputs für den Seriellen Monitor entfernt worden. Sämtliche relevanten Outputs werden jetzt auf dem Display ausgegeben.</p>
<pre><code class="language-c">
#include &lt;HTTPClient.h&gt;
#include &lt;NewPing.h&gt;
#include &lt;WiFi.h&gt;
#include &lt;WiFiClient.h&gt;
#include &lt;WiFiServer.h&gt;
#include &lt;WiFiUdp.h&gt;
#include &lt;Wire.h&gt;
#include "SSD1306.h"

const int triggerPin = 15;   // HC-SR04: Trigger Pin
const int echoPin = 4;       // HC-SR04: Echo Pin
const int sdaPin = 21;       // Display: SDA Pin
const int sclPin = 22;       // Display: SCL Pin
const int sensorRange = 280; // Reichweite (&lt; maximale Reichweite)

// HC-SR04
NewPing sonar(triggerPin, echoPin, sensorRange); // create NewPing instance

// Wifi
char ssid[] = "&lt;wlan_ssid&gt;";     // your network SSID (name)
char pass[] = "&lt;wlan_password&gt;"; // your network password
char host[] = "192.168.178.100"; // ip of service interface in SmartHomeNG
int port = 4321;                 // port of service interface in SmartHomeNG
char cm_item[] = "test.numeric";
int status = WL_IDLE_STATUS;
WiFiClient client;

// Display
SSD1306Wire display(0x3c, sdaPin, sclPin);

void setup() {
  Serial.begin(19200);
  // Init Display
  display.init();
  display.flipScreenVertically();
  // Init Wifi
  initialise_wifi();
}

void loop() {
  delay(50);
  unsigned int result = sonar.ping();
  float cm = sonar.convert_cm(result); //(result/2)/29.1; //

  while (client.available()) {
    char c = client.read();
    Serial.write(c);
  }

  if (cm &gt; 0) {
    if (client.connect(host, port)) {
      HTTPClient http;
      char portStr[12];
      sprintf(portStr, "%d", port);
      char url[128];
      sprintf(url, "http://%s:%s/rest/items/%s", host, portStr, cm_item);
      http.begin(url);
      http.addHeader("Content-Type", "application/json");
      char cmStr[12];
      char cmStrFull[24];
      sprintf(cmStr, "%f", cm);
      sprintf(cmStrFull, "%i cm", (int)cm);
      int httpCode = http.PUT(cmStr);
      String payload = http.getString();
      http.end();

      display.clear();
      display.setFont(ArialMT_Plain_16);
      display.drawString(0, 0, "Wasserstand:");
      display.setFont(ArialMT_Plain_24);
      display.drawString(0, 17, cmStrFull);
      display.display();
    }
  }
  // Wait 5 seconds and do next measurement
  delay(5000);
}

static void initialise_wifi(void) {
  display.setFont(ArialMT_Plain_10);
  display.drawString(0, 0, "Setting up wifi...");
  display.display();

  while (status != WL_CONNECTED) {
    display.drawString(0, 11, "Attempting to connect...");
    display.display();
    status = WiFi.begin(ssid, pass);
    delay(10000);
  }
  display.drawString(0, 22, "Connected to wifi!");
  display.display();
  printWifiStatus();
}

void printWifiStatus() {
  IPAddress ip = WiFi.localIP();
  String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]);
  display.drawString(0, 33, "IP: "+ipStr);
  display.display();
  long rssi = WiFi.RSSI();
  char rssiStr[255];
  sprintf(rssiStr, "RSSI: %d dBm", rssi);
  display.drawString(0, 44, rssiStr);
  display.display();
}</code></pre>
<p>Nach der Initialisierung des Displays in der Methode <code>setup</code>, kann mittels <code>display.drawString(...)</code> Text auf das Display gesendet werden. Der erste Parameter ist dabei die X-, der zweite die Y-Koordinate. Im dritten Parameter wird der String gesetzt. Mit <code>display.display();</code> werden alle zuvor eingesteuerten Operationen dann wirklich auf dem Display ausgegeben. Ein <code>display.clear();</code> leert die auf dem Display ausgegebenen Werte, damit neuer Text dargestellt werden kann. Wird kein <code>display.display();</code> aufgerufen, so wird immer mehr auf das Display geschrieben. Dies kann soweit führen, dass Text über bestehenden Text geschrieben wird.</p>
<p>Dies kann am Beispiel der WLAN-Initialisierung gut gesehen werden. Das Gehäuse ist dabei wieder von Thingiverse bezogen und via 3D Drucker gedruckt worden (<a href="https://www.thingiverse.com/thing:2176764" target="_blank" rel="noopener">https://www.thingiverse.com/thing:2176764</a>):</p>
<p><img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2018/05/IMAG0778-1.jpg" alt="" width="546" height="418" class="alignnone wp-image-1699" srcset="https://www.smarthomeng.de/wp-content/uploads/2018/05/IMAG0778-1.jpg 730w, https://www.smarthomeng.de/wp-content/uploads/2018/05/IMAG0778-1-300x230.jpg 300w" sizes="(max-width: 546px) 100vw, 546px" /><br />
Nach der Initialisierung wird nun auf dem Display der Abstand angezeigt:</p>
<p><img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2018/05/IMAG0776.jpg" alt="" width="516" height="556" class="alignnone wp-image-1690" srcset="https://www.smarthomeng.de/wp-content/uploads/2018/05/IMAG0776.jpg 3024w, https://www.smarthomeng.de/wp-content/uploads/2018/05/IMAG0776-278x300.jpg 278w, https://www.smarthomeng.de/wp-content/uploads/2018/05/IMAG0776-768x827.jpg 768w, https://www.smarthomeng.de/wp-content/uploads/2018/05/IMAG0776-950x1024.jpg 950w" sizes="(max-width: 516px) 100vw, 516px" /></p>
<p>In Teil 3 folgt nun in Kürze noch ein Update zu meiner tatsächlichen Installation in der Zisterne und der Garage. Die Arbeiten sind bereits vollendet und die Werte werden via Kabel in die Garage auf den ESP32 übertragen. Mehr dazu aber in der nächsten Zeit&#8230;</p>
<p><em>(Die in diesem Artikel verwendeten Screenshots und Fotos wurden selber erstellt. Für den Schaltplan wurde das Tool<span> </span><a href="http://fritzing.org/home/" target="_blank" rel="noopener">Fritzing</a><span> </span>verwendet.)</em></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.smarthomeng.de/entfernungsmessung-mit-esp32-und-smarthomeng-teil-2-anbindung-eines-ssd1306-oled-displays/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Das Traffic Plugin am Beispiel eines Staualarms</title>
		<link>https://www.smarthomeng.de/das-traffic-plugin-am-beispiel-eines-staualarms</link>
					<comments>https://www.smarthomeng.de/das-traffic-plugin-am-beispiel-eines-staualarms#respond</comments>
		
		<dc:creator><![CDATA[Marc René Frieß]]></dc:creator>
		<pubDate>Sat, 21 Apr 2018 16:04:27 +0000</pubDate>
				<category><![CDATA[Plugins]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[Alarm]]></category>
		<category><![CDATA[Fahrzeit]]></category>
		<category><![CDATA[Google Directions]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[Traffic]]></category>
		<category><![CDATA[Traffic Plugin]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=1574</guid>

					<description><![CDATA[Pendeln in deutschen Großstädten ist kein Spaß. Laut einem Artikel von Spiegel Online stehen deutsche Autofahrer im Jahr 475.000 Stunden im Stau. Mit dem Traffic Plugin bietet SmartHomeNG die Möglichkeit, Fahrzeiten über die Google Directions API zu berechnen. So lässt sich auf einfache Art und Weise ein Alarmsystem bauen, dass<a class="moretag" href="https://www.smarthomeng.de/das-traffic-plugin-am-beispiel-eines-staualarms"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<p>Pendeln in deutschen Großstädten ist kein Spaß. Laut einem Artikel von <a href="http://www.spiegel.de/auto/aktuell/adac-autofahrer-stehen-475-000-stunden-im-stau-a-1189334.html" target="_blank" rel="noopener">Spiegel Online</a> stehen deutsche Autofahrer im Jahr 475.000 Stunden im Stau.</p>
<p>Mit dem Traffic Plugin bietet SmartHomeNG die Möglichkeit, Fahrzeiten über die Google Directions API zu berechnen.</p>
<p><span id="more-1574"></span></p>
<p>So lässt sich auf einfache Art und Weise ein Alarmsystem bauen, dass einem im Büro Bescheid gibt, wenn es Zeit wird zu fahren (oder man länger bleiben sollte, damit sich der Stau wieder auflösen kann).</p>
<p>Die Erkennung, wo man sich gerade befindet, wird dabei, wie in <a href="https://www.smarthomeng.de/geozonen-basierte-services-mit-der-egigeozone-app-und-dem-network-plugin" target="_blank" rel="noopener">https://www.smarthomeng.de/geozonen-basierte-services-mit-der-egigeozone-app-und-dem-network-plugin</a> beschrieben, über EgiGeoZone und das Network Plugin umgesetzt.</p>
<h1>Das Traffic Plugin</h1>
<p>Die automatisch generierte Doku zum Traffic Plugin findet sich unter <a href="https://www.smarthomeng.de/user/plugins_doc/config/traffic.html" target="_blank" rel="noopener">https://www.smarthomeng.de/user/plugins_doc/config/traffic.html</a>.</p>
<p>Die Readme liegt unter <a href="https://www.smarthomeng.de/user/plugins/traffic/README.html" target="_blank" rel="noopener">https://www.smarthomeng.de/user/plugins/traffic/README.html</a>, der Quellcode auf Github unter <a href="https://github.com/smarthomeNG/plugins/tree/master/traffic" target="_blank" rel="noopener">https://github.com/smarthomeNG/plugins/tree/master/traffic</a>.</p>
<p>Der Support-Thread im Forum findet sich unter <a href="https://knx-user-forum.de/forum/supportforen/smarthome-py/1048446-traffic-plugin-support-thread" target="_blank" rel="noopener">https://knx-user-forum.de/forum/supportforen/smarthome-py/1048446-traffic-plugin-support-thread</a>.</p>
<p>Das Plugin ist schnell in der <code>etc/plugin.yaml</code> konfiguriert:</p>
<pre><code class=" language-yaml">
traffic:
    class_name: Traffic
    class_path: plugins.traffic
    apikey: your own api key
    language: de (optional)
</code></pre>
<p>Der persönliche API Key für die Directions API von Google kann unter <a href="https://developers.google.com/maps/documentation/directions/intro?hl=de" target="_blank" rel="noopener">https://developers.google.com/maps/documentation/directions/intro?hl=de</a> beantragt werden.</p>
<h1>Die Items</h1>
<p>Wichtig sind dabei folgende drei Items zur Erfassung des aktuellen Orts, an dem man sich aufhält. Die Items wurden bereits in dem oben genanntem Artikel zu EgiGeoZone eingeführt, und werden, wie im Artikel beschrieben, von EgiGeoZone bedatet:</p>
<pre class="language-yaml code-toolbar"><code class=" language-yaml"><span class="token key atrule">location</span><span class="token punctuation">:</span>

        <span class="token key atrule">lat</span><span class="token punctuation">:</span>
            <span class="token key atrule">type</span><span class="token punctuation">:</span> str
            <span class="token key atrule">visu_acl</span><span class="token punctuation">:</span> ro
            <span class="token key atrule">cache</span><span class="token punctuation">:</span> <span class="token string">'yes'</span>

        <span class="token key atrule">lon</span><span class="token punctuation">:</span>
            <span class="token key atrule">type</span><span class="token punctuation">:</span> str
            <span class="token key atrule">visu_acl</span><span class="token punctuation">:</span> ro
            <span class="token key atrule">cache</span><span class="token punctuation">:</span> <span class="token string">'yes'</span>

        <span class="token key atrule">zone</span><span class="token punctuation">:</span>
            <span class="token key atrule">type</span><span class="token punctuation">:</span> str
            <span class="token key atrule">visu_acl</span><span class="token punctuation">:</span> ro
            <span class="token key atrule">cache</span><span class="token punctuation">:</span> <span class="token string">'yes'</span>
</code></pre>
<p>Wichtig dabei ist, dass der Zonenname in EgiGeoZone für die Arbeitsstätte (oder mehrere Arbeitsstätten) den String &#8222;Arbeit&#8220; enthält und der Zonenname für daheim &#8222;Home&#8220;. Alternative Namen gehen auch, müssen dann aber in der Logik weiter unten angepasst werden.</p>
<p>Zusätzlich müssen noch die Home Koordinaten jeweils als Item definiert werden.<br />
<strong>Tipp:</strong> Alternativ können auch die Attribute <code>_lat</code> und <code>_lon</code> direkt auf dem SmartHome Objekt (<code>bin/smarthome.py</code>) genutzt werden.</p>
<pre class="language-yaml code-toolbar"><code class=" language-yaml"><span>location:
</span><span>
</span><span>    home:
</span><span>        lat:
</span><span>            type: </span>str
            <span>visu_acl: </span>ro
            <span>value: </span>48.xxxxxxx
            <span>cache: </span><span>'yes'
</span><span>
</span><span>        </span><span>lon:
</span><span>            type: </span>str
            <span>visu_acl: </span>ro
            <span>value: </span>11.xxxxxxx
            <span>cache: </span><span>'yes'</span></code></pre>
<p>Für die Speicherung der Reisedaten, die vom Traffic Plugin zurückgegeben werden, werden folgende Items benötigt:</p>
<pre class="language-yaml code-toolbar"><code class=" language-yaml">travel_info:

    calculate_way_home:
       type: bool
       cache: 'yes'
    
    calculate_way_work:
        type: bool
        cache: 'yes'

    travel_time:
        type: num
        
        in_traffic:
            type: num

    travel_distance:
        type: num
        
    travel_summary:
        type: str</code></pre>
<h1>Die Logik traffic_info.py</h1>
<p>Als nächstes muss die aktuelle Fahrzeit zyklisch jede Minute über eine Logik vom Plugin abgefragt werden.</p>
<pre><code class="language-yaml">TrafficInfo:
    filename: traffic_info.py
    crontab: '* * * *'</code></pre>
<p>Der Code der Logik sieht wie folgt aus:</p>
<pre><code class="language-yaml">
# Codeblock 1 - Fahrt von der Arbeit nach Hause
if sh.now().hour &lt; 20 and sh.now().hour &gt; 14 and sh.now().weekday() in [0, 1, 2, 3, 4] and ('Arbeit' in sh.location.zone()):
    sh.location.calculate_way_home(1)
    destination = sh.location.home.lat() + "," + sh.location.home.lon()
    origin = sh.location.lat() + "," + sh.location.lon()
else:
    sh.location.calculate_way_home(0)

# Codeblock 2 - Fahrt von zu Hause in die Arbeit
if sh.now().hour &lt; 10 and sh.now().hour &gt; 4 and sh.now().weekday() in [0, 1, 2, 3, 4] and sh.location.zone() == 'Home':
    sh.location.calculate_way_work(1)
    destination = "Musterstraße 5, München"
    origin = sh.location.home.lat() + "," + sh.location.home.lon()
else:
    sh.location.calculate_way_work(0)

# Codeblock 3 - Default: Fahrt nach Hause von "irgendwo".
if not sh.location.calculate_way_work() and sh.location.zone() != 'Home':
    destination = sh.location.home.lat() + "," + sh.location.home.lon()
    origin = sh.location.lat() + "," + sh.location.lon()
    sh.location.calculate_way_home(1)

# Codeblock 4 - Wege- und Zeitbestimmung, ggf. Alarmmeldung oder Reset der Items
if sh.location.calculate_way_work() or sh.location.calculate_way_home():
    route = sh.traffic.get_route_info(origin, destination, False)
    if route is not None:
        summary = route['summary'] + ": %.1f km in %.0f min" % (round(route['distance'] / 1000, 2), round(route['duration_in_traffic'] / 60, 2))
        sh.location.travel_time(route['duration'])
        if 'duration_in_traffic' in route:
            sh.location.travel_time.in_traffic(route['duration_in_traffic'])
        sh.location.travel_distance(route['distance'])
        sh.location.travel_summary(summary)
        if 'Arbeit' in sh.location.zone() and sh.location.travel_time.in_traffic() &gt;= 2500 &gt; sh.location.travel_time.in_traffic.prev_value() and sh.now().hour &lt; 20 and sh.now().hour &gt; 14:
            sh.pushbullet.note("Alarm: Verkehr", "%s Min. Fahrzeit nach Hause!" % round((sh.location.travel_time.in_traffic() / 60), 2))
else:
    sh.location.travel_time('')
    sh.location.travel_time.in_traffic('')
    sh.location.travel_distance('')
    sh.location.travel_summary('-')
</code></pre>
<p>Im ersten Block wird geprüft, ob die aktuelle Uhrzeit zwischen 14:00 und 20:00 liegt (Zeitraum für die Prüfung bzgl. &#8222;Weg von der Arbeit nach Hause&#8220;) und, ob der aktuelle Tag Montag &#8211; Freitag ist. Zusätzlich wird geprüft, ob man sich in einer Zone befindet, deren Name  die Zeichenkette &#8222;Arbeit&#8220; enthält. Ist dies der Fall, so werden das boolsche Item <code>calculate_way_home</code> auf <code>True</code> und als <code>destination</code> die Home-Koordinate gesetzt.</p>
<p>Der zweite Codeblock macht das Gleiche, aber für die (bevorstehende) Anfahrt in die Arbeit von zu Hause aus (4:00-10:00 als Zeitintervall). Die aktuelle Zone enthält den String &#8222;Home&#8220;, als Destination wird die Adresse der Arbeitsstätte gesetzt. <code>calculate_way_work</code> wird auf <code>True</code> gesetzt.</p>
<p>Im dritten Codeblock wird nun geprüft, ob man auf dem Weg zur Arbeit und nicht zu Hause ist. Ist man dies nicht, so wird auf Basis der aktuellen Position (die nicht zwingend die Arbeitsstätte ist) immer die Fahrzeit nach Hause berechnet. Diese kann bspw. in der Visu angezeigt werden. <code>calculate_way_home</code> wird für die nachfolgende Berechnung ebenfalls auf <code>True</code> gesetzt.</p>
<p>Im vierten Codeblock wird nun das Traffic Plugin aufgerufen. Über <code>get_route_info(origin, destination, False)</code> werden die Daten zur Route von der aktuellen Position zum Ziel abgefragt. Das Item <code>location.travel_time</code> wird mit der reinen Fahrzeit <em><strong>ohne</strong> Berücksichtigung der aktuellen Verkehrlage</em>, das Unteritem <code>location.travel_time.in_traffic</code> <em><strong>mit</strong> Berücksichtigung der aktuellen Verkehrslage</em> befüllt.<br />
In das Item <code>location.travel_distance</code> wird die aktuellen Distanz geschrieben.<br />
In <code>location.travel_summary</code> landet ein kurzes Summary als String.<br />
Zuletzt wird eine Alarmmeldung über das <a href="https://www.smarthomeng.de/user/plugins_doc/config/pushbullet.html" target="_blank" rel="noopener">Pushbullet Plugin</a> versendet: <code>sh.pushbullet.note("Alarm: Verkehr", "%s Min. Fahrzeit nach Hause!" % round((sh.location.travel_time.in_traffic() / 60), 2))</code></p>
<p>Das Ergebnis ist hier zu sehen:<br />
<img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2018/04/Screenshot_20180422-072146.png" alt="" class="alignnone wp-image-1629" width="332" height="590" srcset="https://www.smarthomeng.de/wp-content/uploads/2018/04/Screenshot_20180422-072146.png 1440w, https://www.smarthomeng.de/wp-content/uploads/2018/04/Screenshot_20180422-072146-169x300.png 169w, https://www.smarthomeng.de/wp-content/uploads/2018/04/Screenshot_20180422-072146-768x1365.png 768w, https://www.smarthomeng.de/wp-content/uploads/2018/04/Screenshot_20180422-072146-576x1024.png 576w" sizes="(max-width: 332px) 100vw, 332px" /></p>
<p>Neben der in diesem Artikel gezeigten Grundfunktionalität, lassen sich mit dem Plugin bzw. der Directions API auch noch deutlich mehr Informationen, wie bspw. die vollständigen Routing-Informationen zum Zielort, bestimmen.</p>
<p>Ich persönlich kombiniere einige dieser Daten mit der Anzeige meiner Position und der Wegstrecke nach Hause in Google Maps. Hierfür habe ich ein <a href="https://www.smartvisu.de" target="_blank" rel="noopener">smartVISU</a> Widget geschrieben. Dies ist Thema eines zukünftigen Artikels.</p>
<p><em>(Die in diesem Artikel verwendeten Screenshots wurden selber erstellt. Das Titelbild ist unter der Creative Commons Zero (CC0) Lizenz veröffentlicht und wurde von www.pexels.com bezogen.)</em></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.smarthomeng.de/das-traffic-plugin-am-beispiel-eines-staualarms/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
