<?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>smartVISU &#8211; SmartHomeNG | smarthome knx homematic mqtt hue 1wire home automation</title>
	<atom:link href="https://www.smarthomeng.de/tag/smartvisu/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>Sun, 11 Apr 2021 20:48:05 +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>smartVISU &#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>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 fetchpriority="high" 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 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 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>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>Google Maps Widget für SmartVISU 2.9</title>
		<link>https://www.smarthomeng.de/google-maps-widget-fuer-smartvisu-2-9</link>
					<comments>https://www.smarthomeng.de/google-maps-widget-fuer-smartvisu-2-9#respond</comments>
		
		<dc:creator><![CDATA[Marc René Frieß]]></dc:creator>
		<pubDate>Sat, 18 Aug 2018 14:52:28 +0000</pubDate>
				<category><![CDATA[Beispiel-Implementierungen]]></category>
		<category><![CDATA[Plugins]]></category>
		<category><![CDATA[egigeozone]]></category>
		<category><![CDATA[Google Maps]]></category>
		<category><![CDATA[smartVISU]]></category>
		<category><![CDATA[smartVISU 2.9]]></category>
		<category><![CDATA[Traffic Plugin]]></category>
		<category><![CDATA[Widget]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=1995</guid>

					<description><![CDATA[Auch in der Visualisierung kann es von Nutzen sein, seine aktuelle Position und ggf. eine Fahrtroute auf einer Google Maps Karte zu visualisieren. SmartHomeNG bietet eine Reihe an Plugins und Möglichkeiten, um die jeweiligen Geokoordinaten zu erfassen (EgiGeoZone mit Network oder Webservices Plugin) und die Fahrzeit zu berechnen (Traffic Plugin).<a class="moretag" href="https://www.smarthomeng.de/google-maps-widget-fuer-smartvisu-2-9"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<p>Auch in der Visualisierung kann es von Nutzen sein, seine aktuelle Position und ggf. eine Fahrtroute auf einer Google Maps Karte zu visualisieren. SmartHomeNG bietet eine Reihe an Plugins und Möglichkeiten, um die jeweiligen Geokoordinaten zu erfassen (EgiGeoZone mit Network oder Webservices Plugin) und die Fahrzeit zu berechnen (Traffic Plugin). Die Anzeige dieser Daten muss jedoch in der Visualisierung geschehen. <span id="more-1995"></span><br />
Aus dieser Motivation heraus habe ich ein Google Maps Widget für die SmartVISU geschrieben, welches mir meine aktuelle Position, meine Heimkoordinaten und den Weg zur Arbeit bzw. den Weg von der aktuellen Position nach Hause anzeigt.</p>
<p>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> wurde beschrieben, wie man Positionsdaten in SmartHomeNG übertragen kann. In <a href="https://www.smarthomeng.de/das-traffic-plugin-am-beispiel-eines-staualarms" target="_blank" rel="noopener">https://www.smarthomeng.de/das-traffic-plugin-am-beispiel-eines-staualarms</a> wurde beschrieben, wie das Traffic Plugin (Google Directions) in SmartHomeNG eingebunden werden kann. Items aus beiden Artikeln werden für das Plugin benötigt!</p>
<p><strong>Tipp:</strong> Am Ende des Artikels findet sich noch eine einfachere Version, die nur die aktuelle Position benötigt (und anzeigt)!</p>
<h1>Items</h1>
<p>Basis bilden ein Teil bzw. eine Erweiterung der Items aus dem EgiGeoZone und den Traffic Plugin Artikel. Bitte auf diese Artikel referenzieren, wie die Items belegt werden können.</p>
<pre><code class="language-yaml">
%YAML 1.1
---
location:

	home:
		lat:
			type: str
			value: 48.263530
			cache: 'yes'

		lon:
			type: str
			value: 11.443952
			cache: 'yes'
	
	work:

		lat:
			type: str
			value: 48.143158
			cache: 'yes'

		lon:
			type: str
			value: 11.547755
			cache: 'yes'
			
	lat:
		type: str
		cache: 'yes'

	lon:
		type: str
		cache: 'yes'

travel_info:
       
        calculate_way_home:
                type: bool
                cache: 'yes'

        calculate_way_work:
                type: bool
                cache: 'yes'

        travel_summary:
                type: str
 
</code></pre>
<p>Neben den jeweiligen GPS Koordinaten der aktuellen Position (<code>location.lat, location.lon</code>), der Home-Koordinate (<code>location.home.lat, location.home.lon</code>) und der Koordinate der Arbeitsstelle (<code>location.work.lat, location.work.lon</code>), sind hier auch zwei boolsche Items, die angeben, ob jeweils der Weg nach Hause oder in die Arbeit angezeigt werden soll (<code>travel_info.calculate_way_home</code> und <code>travel_info.calculate_way_work</code>) Für die Anzeige darf jeweils nur eines dieser Items <code>True</code> sein. Näheres ist in <a href="https://www.smarthomeng.de/das-traffic-plugin-am-beispiel-eines-staualarms" target="_blank" rel="noopener">https://www.smarthomeng.de/das-traffic-plugin-am-beispiel-eines-staualarms</a> beschrieben.</p>
<p><strong>Tipp:</strong> Man kann natürlich auch die &#8222;aktuelle&#8220; Koordinate <code>location.lat, location.lon</code> fest im Item hinterlegen, ohne dieses via EgiGeoZone zu bedaten. Diese Koordinate ist, so lange keine Route angezeigt wird, das Zentrum der Karte!</p>
<h1>Google Maps Widget</h1>
<p>Für das Widget sind im Ordner <code>dropins/widgets</code> zwei Dateien zu erstellen. Im Javascript File wird dabei die Karte initialisiert und falls angegeben, die Verkehrsanzeige eingeschaltet. Daneben wird ein Marker auf die Home Koordinate und die aktuelle Position gesetzt. Letzterer ist mit einem Foto hinterlegt.</p>
<p>Im Update-Block werden die jeweiligen Positionen aktualisiert und die aktuelle Route gesetzt (falls eine Route aktuell angezeigt werden soll).</p>
<p>Im JS-File muss bedacht werden, dass der im Rahmen des Traffic Plugins eingerichtete API Key für die Google Directions API angegeben werden muss (<code>&lt;apikey&gt</code>)! Zudem kann als Title noch der jeweilige Name <code>&lt;Mein Name&gt;</code> gesetzt werden.</p>
<p><strong><code>dropins/widgets/gmaps.js</code>:</strong></p>
<pre><code class="language-javascript">
// dropins/widgets/gmaps.js
$.widget("sv.gmaps_map", $.sv.widget, {
    initSelector: 'div[data-widget="gmaps_map"]',

    options: {
        'traffic': null,
    },

    _create: function () {
        this._super();
        this._create_map();
    },

    _create_map: function () {
        try {
            this.map = new google.maps.Map(this.element[0], {
                zoom: 11,
                disableDefaultUI: false,
                clickableIcons: false,
                mapTypeControl: false,
                streetViewControl: false
            });
        }
        catch(e) {
            if(e.name == "ReferenceError") { // google maps script not loaded yet
                var that = this;
                // google maps script is already loading in another widget
                if(window.google_maps_loading) { 
                    window.setTimeout(function() { that._create_map() }, 100)
                    return;
                }
                // google maps script is not loading
                window.google_maps_loading = true;
                $.ajax({
                    url: 'https://maps.googleapis.com/maps/api/js?key=&lt;apikey&gt;',
                    dataType: "script",
                    complete: function() { window.google_maps_loading = false; that._create_map() }
                });
                return;
            }
            else  // other exceptions should be trown
                throw e;
        }

        this.directionsService = new google.maps.DirectionsService;
        this.directionsDisplay = new google.maps.DirectionsRenderer();
        this.directionsDisplay.setMap(this.map);

        if (this.options['traffic']) {
            var trafficLayer = new google.maps.TrafficLayer();
            trafficLayer.setMap(this.map);
        }

        var pinColorGreen = "20d24a";
        var pinImageGreen = new google.maps.MarkerImage("https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|" + pinColorGreen,
            new google.maps.Size(21, 34),
            new google.maps.Point(0,0),
            new google.maps.Point(10, 34));
        var pinImageMyself = new google.maps.MarkerImage("/smartVISU/pics/phone/myself.jpg" ,
            null, null, null, new google.maps.Size(40, 40));
        var pinShadow = new google.maps.MarkerImage("https://chart.apis.google.com/chart?chst=d_map_pin_shadow",
            new google.maps.Size(40, 37),
            new google.maps.Point(0, 0),
            new google.maps.Point(12, 35));

        this.marker_home = new google.maps.Marker({
            map: this.map,
            icon: pinImageGreen,
            shadow: pinShadow,
            title:' Home '
        });

        this.marker_myself = new google.maps.Marker({
            map: this.map,
            icon: pinImageMyself,
            title:' &lt;Mein Name&gt;',
            zIndex:99999999
        });
    },

    _update: function(response) {

        if(!this.map) {
            var that = this;
            window.setTimeout(function() { that._update(response) }, 100)
            return;
        }

        this.map.setCenter({lat: response[0], lng: response[1]});
        var pos = new google.maps.LatLng(parseFloat(response[0]),parseFloat(response[1]));
        this.marker_myself.setPosition(pos);

        var pos_home = new google.maps.LatLng(parseFloat(response[2]),parseFloat(response[3]));
        this.marker_home.setPosition(pos_home);
        if (response[6] && response[7] && (response[4] == 1 || response[5] == 1)) {
            if (response[4] == 1) {
                var destination = { lat: parseFloat(response[2]), lng: parseFloat(response[3]) };
            } else if (response[5] == 1) {
                var destination = { lat: parseFloat(response[6]), lng: parseFloat(response[7]) };
            };
            var directionsDisplay = this.directionsDisplay;
            this.directionsDisplay.setMap(this.map);
            this.directionsService.route({
                origin: pos,
                //provideRouteAlternatives: true,
                destination: destination,
                travelMode: google.maps.TravelMode.DRIVING
            }, function(result, status) {
                if (status === google.maps.DirectionsStatus.OK) {
                    directionsDisplay.setDirections(result);
                } else {
                    console.log('Directions request failed due to ' + status);
                }
            });
        } else {
            if(this.directionsDisplay != null) {
                this.directionsDisplay.setMap(null);
            }
        }
    }
})
</code></pre>
<p>&nbsp;</p>
<p>und <strong><code>dropins/widgets/gmaps.html</code>:</strong></p>
<pre><code class="language-twig">
// dropins/widgets/gmaps.html - API Key für Google Directions angeben!
/**
 * Displays a google maps map with current, home and work position, as well as routing
 *
 * @param unique id for this widget
 * @param a gad/item for latitude
 * @param a gad/item for longitude
 * @param a gad/item for home latitude
 * @param a gad/item for home longitude
 * @param a gad/item for bool flag, if route to home shall be calculated
 * @param a gad/item for bool flag, if route to work shall be calculated
 * @param a gad/item for work latitude
 * @param a gad/item for work longitude
 * @param traffic information on (=1) or off (=0)
 */
{% macro map(id, gad_lat, gad_lon, gad_home_lat, gad_home_lon, gad_calculate_way_home, gad_calculate_way_work, gad_work_lat, gad_work_lon, traffic) %}
    &lt;div id="{{ uid(page, id) }}" style="width: 100%; height: 400px;" data-traffic="{{ traffic }}" data-widget="gmaps_map" data-item="{{ gad_lat }}, {{ gad_lon}}, {{ gad_home_lat }}, {{ gad_home_lon }}, {{ gad_calculate_way_home }}, {{ gad_calculate_way_work }}, {{ gad_work_lat }}, {{ gad_work_lon }}"&gt;&lt;/div&gt;
{% endmacro %}
</code></pre>
<p>Weiterhin wird ein Bild, welches unter <code>/smartVISU/pics/phone/myself.jpg</code> abgelegt ist, verwendet! Damit das Widget ordentlich funktioniert, sollte dieses Bild auch dort existieren.</p>
<h1>Einbindung in smartVISU 2.9</h1>
<p>Da die Widgets mit smartVISU 2.9 automatisch geladen werden, muss nun nur noch das Widget auf der entsprechenden Seite eingebunden werden:</p>
<pre><code class="language-twig">
&lt;div class="block" style="width: 100%;"&gt;
  &lt;div class="set-2" data-role="collapsible-set" data-theme="c" data-content-theme="a" data-mini="true"&gt;
    &lt;div data-role="collapsible" data-collapsed="false"&gt;
      &lt;h3&gt;Verkehr:
      {{ basic.symbol('travel_info.calculate_way_home', 'travel_info.calculate_way_home', 'Nach Hause via ', '', '1') }}
      {{ basic.symbol('travel_info.calculate_way_work', 'travel_info.calculate_way_work', 'Zur Arbeit via ', '', '1') }}
      {{ basic.print('travel_info.travel_summary', 'travel_info.travel_summary', 'text') }}
      &lt;/h3&gt;
      {{ gmaps.map('trafficmap', 'location.lat', 'location.lon', 'location.home.lat', 'location.home.lon', 'travel_info.calculate_way_home', 'travel_info.calculate_way_work', 'location.work.lat', 'location.work.lon', '1') }}
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;  
</code></pre>
<p>Das Ergebnis mit aktivem Arbeitsweg, sieht dann wie folgt aus:</p>
<p><img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2018/08/kartenansicht.jpg" alt="" width="830" height="472" class="alignnone size-full wp-image-2016" srcset="https://www.smarthomeng.de/wp-content/uploads/2018/08/kartenansicht.jpg 830w, https://www.smarthomeng.de/wp-content/uploads/2018/08/kartenansicht-300x171.jpg 300w, https://www.smarthomeng.de/wp-content/uploads/2018/08/kartenansicht-768x437.jpg 768w" sizes="(max-width: 830px) 100vw, 830px" /></p>
<h1>Einfachere Version:</h1>
<p>Hier noch eine einfachere Version des Widgets, nur mit Koordinaten der aktuellen Position:</p>
<pre><code class="language-twig">
{{ gmaps.simple_map('trafficmap_simple', 'location.lat', 'location.lon') }}
</code></pre>
<pre><code class="language-twig">
/**
 * Displays a simple google maps map
 *
 * @param unique id for this widget
 * @param a gad/item for latitude
 * @param a gad/item for longitude
 */
{% macro simple_map(id, gad_lat, gad_lon) %}
&lt;div id="{{ uid(page, id) }}" style="width: 100%; height: 400px;" data-widget="gmaps_simplemap" data-item="{{ gad_lat }}, {{ gad_lon}}"&gt;&lt;/div&gt;
{% endmacro %}
</code></pre>
<pre><code class="language-javascript">
$.widget("sv.gmaps_simplemap", $.sv.widget, {
    initSelector: 'div[data-widget="gmaps_simplemap"]',

    _create: function () {
        this._super();
        this._create_map();
    },

    _create_map: function () {
        try {
            this.map = new google.maps.Map(this.element[0], {
                zoom: 11,
                disableDefaultUI: false,
                clickableIcons: false,
                mapTypeControl: false,
                streetViewControl: false
            });
        }
        catch (e) {
            if (e.name == "ReferenceError") { // google maps script not loaded yet
                var that = this;
                // google maps script is already loading in another widget
                if (window.google_maps_loading) {
                    window.setTimeout(function () {
                        that._create_map()
                    }, 100)
                    return;
                }
                // google maps script is not loading
                window.google_maps_loading = true;
                $.ajax({
                    url: 'https://maps.googleapis.com/maps/api/js?key=&lt;apikey&gt;',
                    dataType: "script",
                    complete: function () {
                        window.google_maps_loading = false;
                        that._create_map()
                    }
                });
                return;
            }
            else  // other exceptions should be thrown
                throw e;
        }

        var pinColorGreen = "20d24a";
        var pinImageGreen = new google.maps.MarkerImage("https://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=%E2%80%A2|" + pinColorGreen,
            new google.maps.Size(21, 34),
            new google.maps.Point(0,0),
            new google.maps.Point(10, 34));
        this.marker_myself = new google.maps.Marker({
            map: this.map,
            icon: pinImageGreen,
            title:' &lt;Mein Name&gt;',
            zIndex:99999999
        });
    },

    _update: function(response) {
        if(!this.map) {
            var that = this;
            window.setTimeout(function() { that._update(response) }, 100)
            return;
        }

        this.map.setCenter({lat: response[0], lng: response[1]});
        var pos = new google.maps.LatLng(parseFloat(response[0]),parseFloat(response[1]));
        this.marker_myself.setPosition(pos);
    }
});</code></pre>
]]></content:encoded>
					
					<wfw:commentRss>https://www.smarthomeng.de/google-maps-widget-fuer-smartvisu-2-9/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Vom Winde verweht</title>
		<link>https://www.smarthomeng.de/vom-winde-verweht</link>
					<comments>https://www.smarthomeng.de/vom-winde-verweht#comments</comments>
		
		<dc:creator><![CDATA[Marc René Frieß]]></dc:creator>
		<pubDate>Thu, 19 Apr 2018 17:55:38 +0000</pubDate>
				<category><![CDATA[Beispiel-Implementierungen]]></category>
		<category><![CDATA[Plugins]]></category>
		<category><![CDATA[Beaufort]]></category>
		<category><![CDATA[Logik]]></category>
		<category><![CDATA[smartVISU]]></category>
		<category><![CDATA[Windrichtung]]></category>
		<category><![CDATA[Windstärke]]></category>
		<category><![CDATA[Wundergrund]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=1516</guid>

					<description><![CDATA[Dieser Artikel beschäftigt sich mit dem Thema Wind und was sich daraus alles über Plugins und Logiken am Ende in der smartVISU realisieren lässt. Anmerkung: mittlerweile sind die API Keys für Wundergrund leider nicht mehr kostenlos! Die Anleitung muss also mit einem alternativen Plugin wie Darksky oder OpenWeatherMap durchgeführt werden!<a class="moretag" href="https://www.smarthomeng.de/vom-winde-verweht"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<p>Dieser Artikel beschäftigt sich mit dem Thema Wind und was sich daraus alles über Plugins und Logiken am Ende in der smartVISU realisieren lässt.</p>
<p><strong>Anmerkung:</strong> mittlerweile sind die API Keys für Wundergrund leider nicht mehr kostenlos! Die Anleitung muss also mit einem alternativen Plugin wie <a href="https://github.com/smarthomeNG/plugins/tree/master/darksky" target="_blank" rel="noopener">Darksky</a> oder <a href="https://github.com/smarthomeNG/plugins/tree/develop/openweathermap" target="_blank" rel="noopener">OpenWeatherMap</a> durchgeführt werden!</p>
<p>Basis des Artikels sind Daten zu Windrichtung und Windgeschwindigkeit über das Wundergrund Plugin. Es lassen sich aber bspw. auch Daten der KNX Wetterstation verwenden, sofern vorhanden.</p>
<h1>Das Wundergrund Plugin konfigurieren</h1>
<p>Die automatisch generierte Doku zum Wundergrund Plugin findet sich unter <a href="https://www.smarthomeng.de/user/plugins_doc/config/wunderground.html" target="_blank" rel="noopener">https://www.smarthomeng.de/user/plugins_doc/config/wunderground.html</a>.</p>
<p>Das Plugin liegt auf Github unter <a href="https://github.com/smarthomeNG/plugins/tree/master/wunderground" target="_blank" rel="noopener">https://github.com/smarthomeNG/plugins/tree/master/wunderground</a>.</p>
<p>Als Erstes muss das Plugin in der <code>etc/plugin.yaml</code> eingetragen werden. Der <code>apikey</code> kann kostenlos <span style="color: #ff0000;">(Update: leider sind die API Keys inzwischen nicht mehr kostenlos!)</span> über <a href="https://www.wunderground.com/weather/api/d/pricing.html" target="_blank" rel="noopener">https://www.wunderground.com/weather/api/d/pricing.html</a> beantragt werden. Es ist darauf zu achten, dass das Updateintervall eine bestimmte Zeitdauer nicht überschreitet, speziell, wenn man Wundergrund auch direkt in der smartVISU nutzt. Das Limit sind 500 Calls pro Tag bzw. 10 Calls pro Minute. Das Default-Updateintervall für das Plugin sind 600 Sekunden, also einmal in 10 Minuten. Per <code>cycle</code> Attribut ließe sich dieses in der <code>plugin.yaml</code> anpassen.</p>
<p>Als <code>location</code> setzt man bspw. seinen Ort, es sind hier neben dem Namen aber auch Geokoordinaten möglich.</p>
<pre><code class="language-yaml">
wundergrund_wetter:
    class_name: Wunderground
    class_path: plugins.wunderground
    apikey: 'xxxxyyyyxxxxyyyy'
    language: 'de'
    location: 'Germany/Hamburg'
    item_subtree: weather.wundergrund
    # cycle: 600
</code></pre>
<p><code>item_subtree</code> ist der Ast im Itemtree, unter dem die Wundergrund-relevanten Items liegen. Im Beispiel ist es <code>weather.wundergrund</code>.<br />
Die notwendigen Items sehen wie folgt aus:</p>
<pre><code class="language-yaml">
%YAML 1.1
---
# items/wetter.yaml
weather:

    wundergrund:

        windrichtung:
            type: str
            wug_matchstring: current_observation/wind_dir

        windrichtung_grad:
            type: num
            wug_matchstring: current_observation/wind_degrees

        windgeschwindigkeit:
            type: num
            value: -9999
            wug_matchstring: current_observation/wind_kph
            wug_datatype: positive

            ms:
                type: num
                eval: (sh.weather.wundergrund.windgeschwindigkeit()/3.6)
                eval_trigger: weather.wundergrund.windgeschwindigkeit

            beaufort:
                type: num

            string:
                type: str
               
        windboeen:
            type: num
            value: -9999
            wug_matchstring: current_observation/wind_gust_kph
            wug_datatype: positive
</code></pre>
<p><strong>Tipp:</strong> Neben dem Wind gibt es über Wundergrund noch viele weitere Wetterdaten.</p>
<h1>Anzeige der Windrichtung in der smartVISU</h1>
<p>Die Windrichtung lässt sich nun in der smartVISU 2.9 sehr einfach ausgeben:</p>
<pre><code class="language-twig">
{{ icon.compass('weather.wundergrund.windrichtung_compass', '', 'weather.wundergrund.windrichtung_grad',  '0', '360', '') }}
{{ basic.print('weather.wundergrund.windrichtung', 'weather.wundergrund.windrichtung', 'text') }}
</code></pre>
<p>Das Ergebnis ist eine sehr schöne Darstellung der Windrichtung:</p>
<p><img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2018/04/windrichtung.jpg" alt="" class="alignnone size-full wp-image-1521" width="124" height="66" /></p>
<h1>Windstärke auswerten und in der smartVISU anzeigen</h1>
<p>Als nächstes soll die Windstärke ausgewertet werden. Dafür dient die nach Sir Francis Beaufort benannte Beaufortskala, die Windstärken in 13 Bereichte von 0 (Windstille) bis 12 (Orkan) klassifiziert.</p>
<p>Für diese Skala ist der Wert im Item <code>weather.wundergrund.windgeschwindigkeit.ms</code> notwendig, das via Eval-Ausdruck die Windgeschwindigkeit von Kilometer pro Stunde in Meter pro Sekunde umrechnet (<code>sh.weather.wundergrund.windgeschwindigkeit()/3.6</code>). Die Umrechnung triggert jedes Mal, wenn sich <code>weather.wundergrund.windgeschwindigkeit</code> verändert.</p>
<p>Für die Auswertung der Windstärke muss unter <code>logics/wind.py</code> eine neue Logik erstellt werden, die die Items <code>weather.wundergrund.windgeschwindigkeit.string</code> und <code>weather.wundergrund.windgeschwindigkeit.beaufort</code> befüllt:<br />
Der Eintrag in der <code>etc/logic.yaml</code> sieht wie folgt aus:</p>
<pre><code class="language-yaml">
WindLogic:
    crontab: init
    filename: wind.py
    watch_item: weather.wundergrund.windgeschwindigkeit.ms
</code></pre>
<p>Die Logik löst also jedes Mal aus, wenn sich <code>weather.wundergrund.windgeschwindigkeit.ms</code> ändert.</p>
<p>Der Code der Logik in der Datei <code>logics/wind.py</code> mappt nun die Windgeschwindigkeit in Meter pro Sekunde auf die Beaufortskala:</p>
<pre><code class="language-python">
if sh.weather.wundergrund.windgeschwindigkeit.ms() &lt; 0.3:
    sh.weather.wundergrund.windgeschwindigkeit.string("Windstille")
    sh.weather.wundergrund.windgeschwindigkeit.beaufort(0)
elif 0.3 &lt;= sh.weather.wundergrund.windgeschwindigkeit.ms() &lt; 1.6:
    sh.weather.wundergrund.windgeschwindigkeit.string("leiser Zug")
    sh.weather.wundergrund.windgeschwindigkeit.beaufort(1)
elif 1.6 &lt;= sh.weather.wundergrund.windgeschwindigkeit.ms() &lt; 3.4:
    sh.weather.wundergrund.windgeschwindigkeit.string("leichte Brise")
    sh.weather.wundergrund.windgeschwindigkeit.beaufort(2)
elif 3.4 &lt;= sh.weather.wundergrund.windgeschwindigkeit.ms() &lt; 5.5:
    sh.weather.wundergrund.windgeschwindigkeit.string("schwacher Wind")
    sh.weather.wundergrund.windgeschwindigkeit.beaufort(3)
elif 5.5 &lt;= sh.weather.wundergrund.windgeschwindigkeit.ms() &lt; 8.0:
    sh.weather.wundergrund.windgeschwindigkeit.string("mäßiger Wind")
    sh.weather.wundergrund.windgeschwindigkeit.beaufort(4)
elif 8.0 &lt;= sh.weather.wundergrund.windgeschwindigkeit.ms() &lt; 10.8:
    sh.weather.wundergrund.windgeschwindigkeit.string("frischer Wind")
    sh.weather.wundergrund.windgeschwindigkeit.beaufort(5)
elif 10.8 &lt;= sh.weather.wundergrund.windgeschwindigkeit.ms() &lt; 13.9:
    sh.weather.wundergrund.windgeschwindigkeit.string("starker Wind")
    sh.weather.wundergrund.windgeschwindigkeit.beaufort(6)
elif 13.9 &lt;= sh.weather.wundergrund.windgeschwindigkeit.ms() &lt; 17.2:
    sh.weather.wundergrund.windgeschwindigkeit.string("steifer Wind")
    sh.weather.wundergrund.windgeschwindigkeit.beaufort(7)
elif 17.2 &lt;= sh.weather.wundergrund.windgeschwindigkeit.ms() &lt; 20.8:
    sh.weather.wundergrund.windgeschwindigkeit.string("stürmischer Wind")
    sh.weather.wundergrund.windgeschwindigkeit.beaufort(8)
elif 20.8 &lt;= sh.weather.wundergrund.windgeschwindigkeit.ms() &lt; 24.5:
    sh.weather.wundergrund.windgeschwindigkeit.string("Sturm")
    sh.weather.wundergrund.windgeschwindigkeit.beaufort(9)
elif 24.5 &lt;= sh.weather.wundergrund.windgeschwindigkeit.ms() &lt; 28.5:
    sh.weather.wundergrund.windgeschwindigkeit.string("schwerer Sturm")
    sh.weather.wundergrund.windgeschwindigkeit.beaufort(10)
elif 28.5 &lt;= sh.weather.wundergrund.windgeschwindigkeit.ms() &lt; 32.7:
    sh.weather.wundergrund.windgeschwindigkeit.ms.string("orkanartiger Sturm")
    sh.weather.wundergrund.windgeschwindigkeit.beaufort(11)
else:
    sh.weather.wundergrund.windgeschwindigkeit.string("Orkan")
    sh.weather.wundergrund.windgeschwindigkeit.beaufort(12)
</code></pre>
<p>Damit die Logik effektiv wird, muss SmartHomeNG neu gestartet oder die Logik via Backend-Plugin aktiviert werden.</p>
<p>Sinnvollerweise kann diese Logik auch in einer Funktion gekapselt werden. Dies ist an einem Alternativansatz, der mit einer Lookup-Tabelle arbeitet, im Folgenden dargestellt:</p>
<pre><code class="language-python"><span class="pl-c">#!/usr/bin/env python3</span>
<span class="pl-c"># beaufort3.py</span>

<span class="pl-k">def</span> <span class="pl-en">get_beaufort</span>(<span class="pl-smi">speed</span>):
    <span class="pl-s"><span class="pl-pds">"""</span></span>
<span class="pl-s">    :parameter speed: windspeed in meter per second</span>
<span class="pl-s">    :return: a tuple of a string with the (german) description and an integer with beaufort speed</span>
<span class="pl-s">    <span class="pl-pds">"""</span></span>
    table <span class="pl-k">=</span> [ 
        (  <span class="pl-c1">0.3</span>, <span class="pl-s"><span class="pl-pds">"</span>Windstille<span class="pl-pds">"</span></span>,<span class="pl-c1">0</span>),
        (  <span class="pl-c1">1.6</span>, <span class="pl-s"><span class="pl-pds">"</span>leiser Zug<span class="pl-pds">"</span></span>,<span class="pl-c1">1</span>),
        (  <span class="pl-c1">3.4</span>, <span class="pl-s"><span class="pl-pds">"</span>leichte Brise<span class="pl-pds">"</span></span>,<span class="pl-c1">2</span>),
        (  <span class="pl-c1">5.5</span>, <span class="pl-s"><span class="pl-pds">"</span>schwacher Wind<span class="pl-pds">"</span></span>,<span class="pl-c1">3</span>),
        (  <span class="pl-c1">8.0</span>, <span class="pl-s"><span class="pl-pds">"</span>mäßiger Wind<span class="pl-pds">"</span></span>,<span class="pl-c1">4</span>),
        ( <span class="pl-c1">10.8</span>, <span class="pl-s"><span class="pl-pds">"</span>frischer Wind <span class="pl-pds">"</span></span>,<span class="pl-c1">5</span>),
        ( <span class="pl-c1">13.9</span>, <span class="pl-s"><span class="pl-pds">"</span>starker Wind<span class="pl-pds">"</span></span>,<span class="pl-c1">6</span>),
        ( <span class="pl-c1">17.2</span>, <span class="pl-s"><span class="pl-pds">"</span>steifer Wind<span class="pl-pds">"</span></span>,<span class="pl-c1">7</span>),
        ( <span class="pl-c1">20.8</span>, <span class="pl-s"><span class="pl-pds">"</span>stürmischer Wind<span class="pl-pds">"</span></span>,<span class="pl-c1">8</span>),
        ( <span class="pl-c1">24.5</span>, <span class="pl-s"><span class="pl-pds">"</span>Sturm<span class="pl-pds">"</span></span>,<span class="pl-c1">9</span>),
        ( <span class="pl-c1">28.5</span>, <span class="pl-s"><span class="pl-pds">"</span>schwerer Sturm<span class="pl-pds">"</span></span>,<span class="pl-c1">10</span>),
        ( <span class="pl-c1">32.7</span>, <span class="pl-s"><span class="pl-pds">"</span>orkanartiger Sturm<span class="pl-pds">"</span></span>,<span class="pl-c1">11</span>),
        ( <span class="pl-c1">999</span>,  <span class="pl-s"><span class="pl-pds">"</span>Orkan<span class="pl-pds">"</span></span>,<span class="pl-c1">12</span>) ]
    
    <span class="pl-k">try</span>:
        description <span class="pl-k">=</span> <span class="pl-c1">min</span>(<span class="pl-c1">filter</span>(<span class="pl-k">lambda</span> <span class="pl-smi">x</span>: x[<span class="pl-c1">0</span>] <span class="pl-k">&gt;=</span> speed, table))[<span class="pl-c1">1</span>]
        bft <span class="pl-k">=</span> <span class="pl-c1">min</span>(<span class="pl-c1">filter</span>(<span class="pl-k">lambda</span> <span class="pl-smi">x</span>: x[<span class="pl-c1">0</span>] <span class="pl-k">&gt;=</span> speed, table))[<span class="pl-c1">2</span>]
        <span class="pl-k">return</span> description,bft
    <span class="pl-k">except</span> <span class="pl-c1">ValueError</span>:
        <span class="pl-k">return</span> <span class="pl-c1">None</span>, <span class="pl-c1">None</span>

decription, bft <span class="pl-k">=</span> get_beaufort(sh.weather.wundergrund.windgeschwindigkeit.ms())
sh.weather.wundergrund.windgeschwindigkeit.string(description)
sh.weather.wundergrund.windgeschwindigkeit.beaufort(bft)
</code></pre>
<p>&nbsp;</p>
<p>In der smartVISU können diese Werte nun wie folgt angezeigt werden:</p>
<pre><code class="language-twig">
{{ basic.symbol('', '', '', 'weather_wind_speed_bft') }}                       
Bft: {{ basic.print('wind_weatherstation_bfvalue', 'knx.weather.wind.beaufort') }}, 
{{ basic.print('wind_weatherstation_string', 'knx.weather.wind.string', 'text') }}
</code></pre>
<p>Das Ergebnis:</p>
<p><img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2018/04/beaufort.jpg" alt="" class="alignnone size-full wp-image-1544" width="180" height="55" /></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/vom-winde-verweht/feed</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Berechnung des Wertes für icon.zenith</title>
		<link>https://www.smarthomeng.de/berechnung-des-wertes-fuer-icon-zenith</link>
					<comments>https://www.smarthomeng.de/berechnung-des-wertes-fuer-icon-zenith#respond</comments>
		
		<dc:creator><![CDATA[Marc René Frieß]]></dc:creator>
		<pubDate>Wed, 04 Apr 2018 15:45:39 +0000</pubDate>
				<category><![CDATA[Beispiel-Implementierungen]]></category>
		<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[icon.zenith]]></category>
		<category><![CDATA[smartVISU]]></category>
		<category><![CDATA[Sonnenstand]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=1355</guid>

					<description><![CDATA[Ein besonderes Merkmal der smartVISU sind dynamisch erzeugte SVG Dateien, die über die &#8222;icon&#8220;-Widget-Bibliothek genutzt werden können. Eine häufige Frage dabei ist, wie sich das icon.zenith, dass den aktuellen Sonnenstand darstellt, von SmartHomeNG aus bedaten lässt. Zwar bietet SmartHomeNG unter lib/env/location.yaml eine ganze Reihe Default-Items mit Werten zum Sonnenstand an,<a class="moretag" href="https://www.smarthomeng.de/berechnung-des-wertes-fuer-icon-zenith"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<p>Ein besonderes Merkmal der <a href="http://www.smartvisu.de/" target="_blank" rel="noopener">smartVISU</a> sind dynamisch erzeugte SVG Dateien, die über die &#8222;icon&#8220;-Widget-Bibliothek genutzt werden können.</p>
<p>Eine häufige Frage dabei ist, wie sich das <code>icon.zenith</code>, dass den aktuellen Sonnenstand darstellt, von SmartHomeNG aus bedaten lässt.<br />
Zwar bietet SmartHomeNG unter <code>lib/env/location.yaml</code> eine ganze Reihe Default-Items mit Werten zum Sonnenstand an, jedoch sind diese für das <code>icon.zenith</code> nicht notwendig.</p>
<p>Dieses Kurz-Tutorial zeigt, wie sich der Wert für das Icon mit einer simplen Logik näherungsweise berechnen lässt.</p>
<h1>SmartHomeNG</h1>
<p>Basis ist ein einfaches numerisches Item namens <code>weather.sun.icon</code>:</p>
<pre><code class="language-yaml">weather:

    sun:

        icon:
            type: num
            visu_acl: ro
</code></pre>
<p>&nbsp;</p>
<p>Als nächstes wird unter <code>etc/logic.yaml</code> eine neue Logik eingehängt, die auf den Sonnenstand reagiert:</p>
<pre><code class="language-yaml">SunPositionLogic:
    filename: sun_position.py
    watch_item: env.location.sun_position.azimut.degrees
</code></pre>
<p>Die Logik löst also bei jeder Veränderng des System-Items <code>env.location.sun_position.azimut.degrees</code> aus. Dieses gibt den Sonnenstand in Grad wieder. Neben der untenstehenden Berechnung des Wertes für das &lt;code&gt;icon.zenith&lt;/code&gt; könnte man in der Logik auch noch weitere Sonnenstands-abhängige Aktionen einbinden, etwa das Herunterfahren von Rollläden.</p>
<p>&nbsp;</p>
<p>In der Logik-Datei <code>logics/sun_position.py</code> selber, werden nun sehr einfache Berechnungen vorgenommen:</p>
<pre><code class="language-python">
# Berechnungen für icon.zenith
now = datetime.datetime.utcnow().hour * 60 + datetime.datetime.utcnow().minute
sunrise = sh.sun.rise().hour * 60 + sh.sun.rise().minute
sunset = sh.sun.set().hour * 60 + sh.sun.set().minute
icon = int(round(255 * ((now - sunrise) / (sunset - sunrise)),0))

sh.weather.sun.icon(icon)
</code></pre>
<p>Über das Intervall vom Sonnenaufang bis zum Sonnenuntergang, wird der aktuelle Zeitpunkt auf eine Skala von 0 &#8211; 255 gemappt.</p>
<h1>smartVISU</h1>
<p>Dieser Wert dient nun als Basis für das <code>icon.zenith</code>, welches in der smartVISU wie folgt eingebunden wird:<br />
<code>{{ icon.zenith('weather.sun.icon', '', 'weather.sun.icon') }}</code>.<br />
Neben dem Icon kann man bspw. noch die aktuellen Daten des Sonnenwinkels anzeigen:</p>
<pre><code class="language-twig">
&lt;table&gt;
  &lt;tr&gt;
  &lt;td width="55px;"&gt; 
    {{ icon.zenith('weather.sun.icon', '', 'weather.sun.icon') }}
  &lt;/td&gt;
  &lt;td&gt; 
     H: {{ basic.print('env.location.sun_position.azimut', 'env.location.sun_position.azimut.degrees') }} ° 
  &lt;br/&gt;
     V: {{ basic.print('env.location.sun_position.elevation', 'env.location.sun_position.elevation.degrees') }} °
  &lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;
</code></pre>
<p>&nbsp;</p>
<p>Das fertige Ergebnis sieht nun wie folgt aus:</p>
<p><img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2018/04/icon_zenith.png" alt="" class="alignnone size-full wp-image-1357" width="131" height="64" /></p>
<p>&nbsp;</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/berechnung-des-wertes-fuer-icon-zenith/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Welches Datenbank Plugin sollte ich verwenden?</title>
		<link>https://www.smarthomeng.de/welches-datenbank-plugin-sollte-ich-verwenden</link>
					<comments>https://www.smarthomeng.de/welches-datenbank-plugin-sollte-ich-verwenden#comments</comments>
		
		<dc:creator><![CDATA[Martin Sinn]]></dc:creator>
		<pubDate>Fri, 30 Mar 2018 07:35:26 +0000</pubDate>
				<category><![CDATA[FAQ]]></category>
		<category><![CDATA[Plugins]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[Datenbank]]></category>
		<category><![CDATA[smartVISU]]></category>
		<category><![CDATA[sqlite]]></category>
		<category><![CDATA[sqlite_visu2_8]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=866</guid>

					<description><![CDATA[Datenbank Plugins Es gibt zurzeit drei verschiedene Datenbank Plugins: database sqlite sqlite_visu2_8 Wenn Du neu mit SmartHomeNG beginnst, solltest Du das Plugin database verwenden. Das database Plugin unterstützt sowohl MySQL Datenbanken, als auch SQLite Datenbanken. Welcher Datenbank-Typ verwendet wird, wird in ../etc/plugin.yaml konfiguriert. sqlite und sqlite_visu2_8 Die beiden SQLite Plugins dienen<a class="moretag" href="https://www.smarthomeng.de/welches-datenbank-plugin-sollte-ich-verwenden"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<h3>Datenbank Plugins</h3>
<p>Es gibt zurzeit drei verschiedene Datenbank Plugins:</p>
<ul>
<li>database</li>
<li>sqlite</li>
<li>sqlite_visu2_8</li>
</ul>
<p>Wenn Du neu mit SmartHomeNG beginnst, solltest Du das Plugin <strong>database</strong> verwenden. Das <strong>database</strong> Plugin unterstützt sowohl MySQL Datenbanken, als auch SQLite Datenbanken. Welcher Datenbank-Typ verwendet wird, wird in <code>../etc/plugin.yaml</code> konfiguriert.</p>
<h3>sqlite und sqlite_visu2_8</h3>
<p>Die beiden SQLite Plugins dienen nur der Rückwärts-Kompatibilität für bestehende SmartHomeNG bzw. smarthome.py Umgebungen und werden nicht mehr weiterentwickelt.</p>
<p>Das Plugin <strong>sqlite</strong> unterstützt smartVISU bis zur Version v2.7.</p>
<p>Zur Unterstützung von smartVISU v2.8 und v2.9 muss das Plugin <strong>sqlite_visu2_8</strong> verwendet werden. Das Plugin führt beim ersten Start eine Konvertierung der Datenbank von <strong>sqlite</strong> auf das <strong>sqlite_visu2_8</strong> Format durch. Einen Weg zurück gibt es dann nicht. Es sollte also vorher eine Sicherung der Datenbank Datei <code>../var/db/smarthome.db</code> durchgeführt werden.</p>
<p><strong>Wichtig</strong>: Vor Beginn der Sicherung SmartHomeNG beenden.</p>
<p>&nbsp;</p>
<p>Eine Routine zur Konvertierung der Datenbanken der sqlite Plugins zu einer Datenbank für das database Plugin gibt es (noch) nicht.</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.smarthomeng.de/welches-datenbank-plugin-sollte-ich-verwenden/feed</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Integration von SteelSeries-Canvas in die smartVISU 2.9 (mit Daten des SMA_EM-Plugins)</title>
		<link>https://www.smarthomeng.de/beispiel-integration-von-steelseries-canvas-in-die-smartvisu</link>
					<comments>https://www.smarthomeng.de/beispiel-integration-von-steelseries-canvas-in-die-smartvisu#comments</comments>
		
		<dc:creator><![CDATA[Marc René Frieß]]></dc:creator>
		<pubDate>Thu, 29 Mar 2018 09:30:21 +0000</pubDate>
				<category><![CDATA[Beispiel-Implementierungen]]></category>
		<category><![CDATA[Plugins]]></category>
		<category><![CDATA[dropins]]></category>
		<category><![CDATA[sma_em]]></category>
		<category><![CDATA[smartVISU]]></category>
		<category><![CDATA[smartVISU 2.9]]></category>
		<category><![CDATA[steelseries-canvas]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=738</guid>

					<description><![CDATA[Obwohl mit smartVISU 2.9 die Anzahl der direkt mitgelieferten Widgets deutlich steigt, so können in manchen Situationen die mitgelieferten Widgets nicht ausreichend sein. In diesem Kurz-Tutorial wird beschrieben, wie sich das Widget-Framework SteelSeries-Canvas (Beispiele) in die smartVISU 2.9 integrieren lässt. Dies wird am Beispiel einer &#8222;Bezug/Einspeisungs&#8220;-Anzeige mit Daten aus dem<a class="moretag" href="https://www.smarthomeng.de/beispiel-integration-von-steelseries-canvas-in-die-smartvisu"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<p>Obwohl mit <a href="http://www.smartvisu.de/" target="_blank" rel="noopener">smartVISU 2.9</a> die Anzahl der direkt mitgelieferten Widgets deutlich steigt, so können in manchen Situationen die mitgelieferten Widgets nicht ausreichend sein.</p>
<p>In diesem Kurz-Tutorial wird beschrieben, wie sich das Widget-Framework <a href="https://github.com/HanSolo/SteelSeries-Canvas" target="_blank" rel="noopener">SteelSeries-Canvas</a> (<a href="https://plus.google.com/105784522827877256999/posts/BnLRUttBN5a" target="_blank" rel="noopener">Beispiele</a>) in die <a href="http://www.smartvisu.de/" target="_blank" rel="noopener">smartVISU 2.9</a> integrieren lässt. Dies wird am Beispiel einer &#8222;Bezug/Einspeisungs&#8220;-Anzeige mit Daten aus dem SMA_EM-Plugin durchgeführt. Das Plugin ist aber keine Pflicht: es können aber auch beliebige andere Items mit ähnlichen Daten verwendet werden.</p>
<p>Der Thread zu SteelSeries-Canvas im Forum findet sich mit weiteren Beispielen in <a href="https://knx-user-forum.de/forum/supportforen/smartvisu/39225-steelseries-canvas-in-smartvisu" target="_blank" rel="noopener">https://knx-user-forum.de/forum/supportforen/smartvisu/39225-steelseries-canvas-in-smartvisu</a>.</p>
<h1>SMA_EM-Plugin einrichten</h1>
<p>Das SMA_EM-Plugin (<a href="https://knx-user-forum.de/forum/supportforen/smarthome-py/1030610-sma_em-plugin" target="_blank" rel="noopener">Support-Thread im Forum</a>, <a href="https://www.smarthomeng.de/user/plugins_doc/config/sma_em.html" target="_blank" rel="noopener">generierte Doku</a>, <a href="https://github.com/smarthomeNG/plugins/tree/master/sma_em" target="_blank" rel="noopener">Plugin auf Github</a>) kann man nutzen, wenn man ein EnergyMeter der Firma SMA in der ersten Generation besitzt. Dieses schickt einen Netzwerk-Multicast auf die Adresse <code>239.12.255.254</code>, den das Plugin einfach &#8222;mithört&#8220;.</p>
<p>Das Plugin basiert auf der Implementierung <a href="https://github.com/datenschuft/SMA-EM/" target="_blank" rel="noopener">https://github.com/datenschuft/SMA-EM/</a> von Florian Wenger. Teile des (open-source) Quelltexts wurden mit freundlicher Genehmigung des Entwicklers im Plugin wiederverwendet.</p>
<p>Das Plugin ist relativ schnell eingerichtet. Mit folgendem Eintrag in der <code>plugin.yaml</code> ist es getan:</p>
<pre><code class="language-yaml">
sma_em:
    class_name: SMA_EM
    class_path: plugins.sma_em
    time_sleep: 4
    serial: xxxxxxxxxxx
</code></pre>
<p>Die Serial ist dabei die des <a href="https://www.sma.de/produkte/monitoring-control/sma-energy-meter.html" target="_blank" rel="noopener">SMA Energy Meters</a>. Sie kann über die Weboberfläche einfach ausgelesen werden:</p>
<p><img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2018/03/sma-energy-meter.png" alt="" class="alignnone wp-image-740" width="457" height="325" srcset="https://www.smarthomeng.de/wp-content/uploads/2018/03/sma-energy-meter.png 718w, https://www.smarthomeng.de/wp-content/uploads/2018/03/sma-energy-meter-300x214.png 300w" sizes="(max-width: 457px) 100vw, 457px" /><br />
<code>time_sleep</code> ist die Zeit, die nach jedem Auslesen gewartet werden soll.</p>
<p>Die wichtigsten Items sind:</p>
<pre><code class="language-yaml">
# items/items.yaml
%YAML 1.1
---

smaem:

    psurplus:
        name: Solar Energy Surplus
        sma_em_data_type: psurplus
        type: num

        kw:
            type: num
            eval: sh.smaem.psurplus() / 1000
            eval_trigger: smaem.psurplus

    pregard:
        name: Energy Regard
        sma_em_data_type: pregard
        type: num

        kw:
            type: num
            eval: sh.smaem.pregard() / 1000
            eval_trigger: smaem.pregard
</code></pre>
<p><strong>Anmerkung:</strong> Neben diesen Items können über das SMA_EM-Plugin noch eine Vielzahl weiterer Daten ausgelesen werden.</p>
<p>Nach einem Neustart von SmartHomeNG ist das Plugin aktiv und Daten sollten in die entsprechenden Items fließen.</p>
<h1>Erweiterung der smartVISU 2.9 mit SteelSeries-Canvas</h1>
<p><strong>Anmerkung:</strong> Diese Anleitung basiert bereits auf der Funktionalität der smartVISU 2.9 und verwendet das <code>smartvisu/dropins</code> Verzeichnis (Details zum Dropin-System der SV2.9 siehe <a href="https://github.com/Martin-Gleiss/smartvisu/blob/develop/dropins/README.md" target="_blank" rel="noopener">https://github.com/Martin-Gleiss/smartvisu/blob/develop/dropins/README.md</a>).</p>
<p>Direkt unter <code>smartvisu/dropins</code> werden die Dateien <code>steelseries-min.js</code> und <code>tween-min.js</code> aus dem <a href="https://github.com/HanSolo/SteelSeries-Canvas" target="_blank" rel="noopener">SteelSeries-Canvas Github Repository</a> abgelegt. Diese werden nun automatisch von der smartVISU 2.9 eingebunden, wie im HTML Quelltext verifiziert werden kann:</p>
<p><img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2018/03/steelseries-link.png" alt="" class="alignnone size-full wp-image-741" width="602" height="45" srcset="https://www.smarthomeng.de/wp-content/uploads/2018/03/steelseries-link.png 602w, https://www.smarthomeng.de/wp-content/uploads/2018/03/steelseries-link-300x22.png 300w" sizes="(max-width: 602px) 100vw, 602px" /></p>
<p>Als Nächstes wird unter <code>smartvisu/dropins/widgets</code> eine Datei namens <code>steelseries.html</code> angelegt. In dieser definiert man seine SteelSeries-Widgets, die nun automatisch eingebunden werden:</p>
<pre><code class="language-twig">
/**
  * Displays a steelseries radial for energy balance
  *
  * @param unique id for this widget
  * @param the gad for the surplus
  * @param the gad for the regard
  * @param min value
  * @param max value
  * @param widgetSize size of the widget in pixels. if left empty, 200 is set.
  * @param pointerColor according to steelseries.ColorDef, e.g. RED or GREEN
  * @param title
  * @param unit
  */
{% macro radial_energy(id, gad_surplus, gad_regard, minValue, maxValue, widgetSize, pointerColor, title, unit) %}
  {% if not widgetSize %}{% set widgetSize = 200 %}{% endif %}
  &lt;canvas id="{{ uid(page, id) }}" data-widget="steelseries.radial_energy" data-item="{{ gad_surplus }}, {{ gad_regard}}" width="{{ widgetSize }}" height="{{ widgetSize }}" data-widgetsize="{{ widgetSize }}" data-title="{{ title }}" data-unit="{{ unit }}" data-min-value="{{ minValue }}" data-max-value="{{ maxValue }}" {% if pointerColor %}data-pointercolor="{{ pointerColor }}"{% endif %}&gt;
  &lt;/canvas&gt;
{% endmacro %}
</code></pre>
<p>Weiterhin muss unter <code>smartvisu/dropins/widgets</code> eine Datei namens <code>steelseries.js</code> angelegt werden:</p>
<pre><code class="language-javascript">$.widget("sv.steelseries_radial_energy", $.sv.widget, {

        initSelector: 'canvas[data-widget="steelseries.radial_energy"]',

        options: {
          title: "",
          unit: "",
          widgetsize: 200,
          pointercolor: null,
          'min-value': null,
          'max-value': null,
        },

        _steelseries: null,

        _create: function() {
          this._super();

          var areas = [steelseries.Section(this.options['min-value'], 0, 'rgba(220, 0, 0, 0.3)'),
                    steelseries.Section(0, this.options['max-value'], 'rgba(0, 220, 0, 0.3)')];
          var params = {
              gaugeType: steelseries.GaugeType.TYPE4,
              size: this.options.widgetsize,
              titleString: this.options.title,
              unitString: this.options.unit,
              frameDesign: steelseries.FrameDesign.BLACK_METAL,
              backgroundColor: steelseries.BackgroundColor.TURNED,
              minValue: this.options['min-value'],
              maxValue: this.options['max-value'],
              ledVisible: false,
              lcdVisible: true,
              area: areas,
              lcdDecimals: 1,
              useOdometer: false
          };
          if(this.options.pointercolor)
            params.pointerColor = steelseries.ColorDef[this.options.pointercolor];

          this._steelseries = new steelseries.Radial(this.element[0].id, params);

        },

        _update: function(response) {
          if (response[0] &gt; 0) {
             this._steelseries.setValueAnimated((-1)*parseFloat(response[0]));
          } else {
             this._steelseries.setValueAnimated(parseFloat(response[1]));
          }
        },
    });
</code></pre>
<p>Nachdem man gespeichert hat, kann man das Widget nun in seinen Pages mit folgendem Block nutzen:</p>
<pre><code class="language-twig">
&lt;div class="block"&gt;
    &lt;div class="set-2" data-role="collapsible-set" data-theme="c" data-content-theme="a" data-mini="true"&gt;
        &lt;div data-role="collapsible" data-collapsed="false"&gt;

            {{ steelseries.radial_energy('steel.radial_smaem','smaem.pregard','smaem.psurplus', -8000, 8000, '267', '', 'Energiebilanz', 'Watt') }}

        &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<p>&nbsp;</p>
<h3>Strombezug / Einspeisung &#8211; aktuell</h3>
<p>Im Fall meiner Photovoltaik-Anlage habe ich &#8222;pi mal Daumen&#8220; maximal 8000 Watt Erzeugung, daher die Normierung auf den Bereich -8000 (Bezug) bis +8000 (Einspeisung). Der Wert 267 gibt die Größe (<code>widgetSize</code>) des Widgets an &#8211; wird diese leer gelassen, ist der Default 200 Pixel. Die Farbe des Zeigers würde sich mit dem Wert <code>pointerColor</code> (im Beispiel leer) noch anpassen lassen.</p>
<p>Das fertige Resultat kann nun live bewundert werden:<br />
<img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/2018/03/steelseries.png" alt="" class="alignnone size-full wp-image-739" width="523" height="352" srcset="https://www.smarthomeng.de/wp-content/uploads/2018/03/steelseries.png 523w, https://www.smarthomeng.de/wp-content/uploads/2018/03/steelseries-300x202.png 300w, https://www.smarthomeng.de/wp-content/uploads/2018/03/steelseries-272x182.png 272w" sizes="(max-width: 523px) 100vw, 523px" /></p>
<p>&nbsp;</p>
<p><em>(Die in diesem Artikel verwendeten Screenshots wurden selber erstellt.)</em></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.smarthomeng.de/beispiel-integration-von-steelseries-canvas-in-die-smartvisu/feed</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>smartVISU Autogeneration</title>
		<link>https://www.smarthomeng.de/smartvisu-autogeneration</link>
					<comments>https://www.smarthomeng.de/smartvisu-autogeneration#respond</comments>
		
		<dc:creator><![CDATA[Martin Sinn]]></dc:creator>
		<pubDate>Sun, 26 Nov 2017 09:43:20 +0000</pubDate>
				<category><![CDATA[Plugins]]></category>
		<category><![CDATA[smartVISU]]></category>
		<category><![CDATA[visu_smartvisu]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=395</guid>

					<description><![CDATA[smartVISU Autogeneration Überblick Im Vergleich zum Visu Plugin der vorhergehenden smarthome/smarthomeNG Releases, wurden die Möglichkeiten zur automatischen Generierung von Seiten für die smartVISU stark erweitert. Unterstützt werden das smartVISU Release 2.7 und der nicht releaste Stand zur Version 2.8. Die zusätzlichen Attribute, die in der item.yaml Datei für die Items<a class="moretag" href="https://www.smarthomeng.de/smartvisu-autogeneration"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<h1>smartVISU Autogeneration</h1>
<h2>Überblick</h2>
<p>Im Vergleich zum Visu Plugin der vorhergehenden smarthome/smarthomeNG Releases, wurden die Möglichkeiten zur automatischen Generierung von Seiten für die smartVISU stark erweitert. Unterstützt werden das smartVISU Release 2.7 und der nicht releaste Stand zur Version 2.8.</p>
<p>Die zusätzlichen Attribute, die in der item.yaml Datei für die Items konfiguriert werden können, sind in der <a href="https://www.smarthomeng.de/user/plugins_doc/config/visu_smartvisu.html" title="https://www.smarthomeng.de/user/plugins_doc/config/visu_smartvisu.html" rel="noreferrer">README Datei des Plugins</a> beschrieben.</p>
<p>Diese Seite und die zugehörien Unterseiten sollen einige der Möglichkeiten aufzeigen, die sich durch die Erweiterungen bieten:</p>
<h3>Anzeige von zusätzlichen Informationen in der Navigation</h3>
<p>In der Navigation können eine Reihe zusätzlicher Informationen angezeigt werden.</p>
<h4>Möglichkeiten</h4>
<p>Das folgende Beispiel zeigt die Möglichkeiten zur Anzeige von zusätzlichen Informationen in der Navigation. Es können zwei Zeilen angezeigt werden. Im Beispiel wird in der ersten Zeile die aktuelle Raumtemperatur angezeigt und in der zweiten Zeile werden Icons angezeigt, die den Zustand von Geräten in dem Raum anzeigen.</p>
<p><img decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/beitraege/visu/navigation.jpg" width="350" /><span></span></p>
<p>Das Beispiel zeigt folgendes an:</p>
<ul>
<li>Kaffeemaschine auf Standby in der Küche</li>
<li>TV an im Wohnzimmer</li>
<li>Im Gästezimmer ung im Bad wird geheizt</li>
<li>Im Büro löuft das TV im Audio Mode</li>
<li>Die Waschmaschine läuft</li>
</ul>
<p>Am Beispiel der Küche zeigt die folgende Konfiguration, wie die zusätzlichen Informationen konfiguriert werden:</p>
<pre><code class="language-yaml">wohnung:

    kochen:
        name: Kochen
        sv_page: room
        sv_img: scene_cooking.png
	sv_nav_aside: "{{ basic.float('m_kochen.ist', 'wohnung.kochen.heizung.ist', '°') }}"
        sv_nav_aside2: "{{ basic.symbol('m_kochen_kaffee2', 'wohnung.kochen.kaffeeautomat.status', '', 'icons/ws/scene_coffee_maker_automatic.png', '2') }} 
            {{ basic.symbol('m_kochen_kaffee3', 'wohnung.kochen.kaffeeautomat.status', '', 'icons/or/scene_coffee_maker_automatic.png', '3') }} 
            {{ basic.symbol('m_kochen_heizen', 'wohnung.kochen.heizung.heizen', '', icon1~'sani_heating.png') }}"

</code></pre>
<p>Wie in den bisherigen Releases:</p>
<ul>
<li><code>sv_page</code><span> </span>zeigt an, dass [wohnung.kochen] ein Raum ist und für diesen ein Navigationseintrag und eine Seite generiert werden soll.</li>
<li><code>sv_img</code>gibt an, welches Icon in der Navigation und auf der Seite angezeigt werden soll.</li>
</ul>
<p>Neu:</p>
<ul>
<li><code>sv_nav_aside</code>spezifiziert, was an der Seite in der oberen Zeile angezeigt werden soll. In diesem Fall ist das die aktuelle Raumtemperatur.</li>
<li><code>sv_nav_aside2</code>spezifiziert,was an der Seite in der unteren Zeile angezeigt werden soll. In diesem Fall ist das eine Reihe von Symbolen: &#8212; Kaffeemautomat im Standby &#8212; Kaffeeautomat heizt &#8212; Die Heizung heizt</li>
</ul>
<p>Wenn die Stati nicht aktiv sind, werden die jeweiligen Icons nicht angezeigt. Da der Kaffeeautomat nur entweder im Standby sein kann oder heizt, wird nur eines der Icons angezeigt. Wenn der Kaffeeautomat ausgeschaltet ist, wird kein Icon angezeigt.</p>
<p>&nbsp;</p>
<h3>Generierung einer Konfigurations-Navigation</h3>
<p>Zusätzlich zum Aufbau einer Navigation über die Seiten der Räume, kann eine Navigation über mehrere Konfigurationsseiten aufgebaut werden.</p>
<h4>Möglichkeiten</h4>
<p>Das folgende Beispiel zeigt die Möglichkeiten zum generieren einer Kategorie Navigation. Die Kategorie Navigation wird durch anklicken des Hand-Symbols in der Titelzeile der smartVISU aktiviert.</p>
<p><img decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/beitraege/visu/category_nav.jpg" width="350" /><span></span></p>
<p>Am Beispiel der obigen Konfigurations-Navigation zeigt die nachfolgende Konfig-Datei, wie die Navigation konfiguriert wird:</p>
<pre><code class="language-yaml">config:
    konfiguration:
        name: Konfiguration
        sv_page: category
        sv_img: control_all_on_off.png

    beschattung:
        name: Beschattung
        sv_page: category
        sv_img: fts_shutter_40.png

    beleuchtung:
        name: Beleuchtungsautomatik
        sv_page: category
        sv_img: light_light_dim_00.png

</code></pre>
<p><code>sv_page</code><span> </span>ist zum generieren eines Eintrages für die Konfigurations-Navigation auf den Seitentyp<span> </span><strong><code>category</code></strong><span> </span>einzustellen.</p>
<p>&nbsp;</p>
<h3>Trenner in der Navigation</h3>
<p>Die Navigation kann durch Trenner unterteilt werden, um die Übersichtlichkeit zu erhöhen.</p>
<h4>Möglichkeiten</h4>
<p>Das folgende Beispiel zeigt die Möglichkeiten zur Anzeige von Trennern in der Navigation. Zwischen den Navigationseinträgen können mehrere Trenner angezeigt werden. Das Beispiel zeigt nicht die Raum-Navigation, sondern die Navigation auf der Konfigurationsseite.</p>
<p><img decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/beitraege/visu/divider.jpg" width="350" /><span></span></p>
<p>Das Beispiel zeigt folgende Trenner:</p>
<ul>
<li>Tests</li>
<li>Kategorien</li>
</ul>
<p>Am Beispiel des Trenners<span> </span><strong><code>Tests</code></strong><span> </span>zeigt die folgende Konfiguration, wie Trenner konfiguriert werden:</p>
<pre><code class="language-yaml">config:
    verteilung:
        name: Verteilung
        sv_page: category
        sv_img: measure_current.png

    seperator_test:
        name: Tests
        sv_page: cat_seperator

    fritzboxen:
        name: Fritzboxen
        sv_page: category
        sv_img: it_router.png

</code></pre>
<p><code>sv_page</code><span> </span>ist zum generieren eines Trenners auf einen speziellen Seitentyp einzustellen.</p>
<ul>
<li>Wenn ein Trenner in die normale Raumnavigation eingefügt werden soll, so muss<span> </span><strong><code>sv_page = seperator</code></strong><span> </span>angegeben werden.</li>
<li>Wenn ein Trenner in die Konfigurationsnavigation eingefügt werden soll, so muss<span> </span><strong><code>sv_page = cat_seperator</code></strong><span> </span>angegeben werden.</li>
</ul>
<h3></h3>
<h3>Unterschiedliche Visu-Styles</h3>
<p>Zusätzlich zum von bisherigen Releases unterstützen Standard-Style, wird der Style<span> </span><code>black</code>unterstützt.</p>
<h4>Möglichkeiten</h4>
<p>Das folgende Beispiel zeigt die Möglichkeiten zur Auswahl des Styles der für smartVISU generierten Seiten.</p>
<p>Bisher wurden Blöcke generiert, die so aussahen (Style &#8218;Standard&#8216;):</p>
<p><img decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/beitraege/visu/style_std.jpg" /><span></span></p>
<p>In der aktuellen Version ist es möglich, die Blöcke in folgender Optik generieren zu lassen (Style &#8218;Black&#8216;):</p>
<p><img decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/beitraege/visu/style_blk.jpg" /><span></span></p>
<p>Dieses ist eine Visu-weite Einstellung, die in der Datei /etc/plugin.yaml vorgenommen wird. Dort kann<span> </span><strong><code>visu_style = std</code></strong><span> </span>oder<span> </span><strong><code>visu_style = blk</code></strong><span> </span>eingetragen werden.</p>
<p>Eine vollständige Seite im Style &#8218;Black&#8216; sieht z.B. folgendermaßen aus:</p>
<p><img decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/beitraege/visu/style_blk_visu.jpg" width="600" /></p>
<p>&nbsp;</p>
<h3>Unterschiedliche Blockgrößen</h3>
<p>Die Blöcke in denen Widgets angezeigt werden, hatten in den bisherigen Releases eine fest definierte (Mindest-)Größe. Jetzt stehen drei unterschiedliche Mindestgrößen zur Verfügung.</p>
<h4>Möglichkeiten</h4>
<p>Die smartVISU unterstützt Blöcke mit drei unterschiedlichen Größen. Gemeint ist hierbei die Mindestgröße des Blocks. Wenn in dem Block Widgets platziert werden, die mit dem Platz nicht auskommen, wird der Block automatisch höher. Die Blockhöhen unterscheiden sich in etwa um die Höhe der Heading-Zeile.</p>
<p>In den bisherigen Releases von smarthome/smarthomeNG wurden beim automatischen generieren von smartVISU Seiten immer Blöcke der Größe<span> </span><strong>2</strong><span> </span>(mittel) verwendet.</p>
<p>Im aktuellen Release können auch Blöcke der Größen<span> </span><strong>1</strong><span> </span>(groß) und<span> </span><strong>3</strong><span> </span>(klein) in die Seiten generiert werden.</p>
<p>Dieses kann als Item-Attribut<span> </span><strong><code>sv_blocksize</code></strong><span> </span>festgelegt werden.</p>
<p>Am Beispiel des Trenners<span> </span><strong><code>Tests</code></strong><span> </span>zeigt die folgende Konfiguration, wie Trenner konfiguriert werden:</p>
<pre><code class="language-yaml">wohnung:
    buero:
        verbraucher:
            name: Verbraucher
            sv_blocksize: 1
            sv_widget: "{{ basic.switch('wohnung.buero.tv', 'wohnung.buero.tv', icon0~'control_on_off.png', icon0~'control_standby.png') }} &lt;br&gt; 
                {{ basic.switch('wohnung.buero.computer', 'wohnung.buero.computer', icon0~'control_on_off.png', icon0~'control_standby.png') }} &lt;br&gt; 
                {{ basic.switch('wohnung.buero.schrank', 'wohnung.buero.schrank', icon0~'control_on_off.png', icon0~'control_standby.png') }} &lt;br&gt; 
                {{ basic.switch('wohnung.buero.steckdose_tuer', 'wohnung.buero.steckdose_tuer', icon0~'control_on_off.png', icon0~'control_standby.png') }}"

</code></pre>
<p><code>sv_blocksize</code><span> </span>dient zur Einstellung der (minimalen) Blockhöhe und dasrf die Werte 1, 2 oder 3 annehmen. Wird<span> </span><code>sv_blocksize</code>nicht angegeben, so wird der Default-Wert<span> </span><strong>2</strong><span> </span>benutzt.</p>
<p>&nbsp;</p>
<h3>Unterschiedliche Blocktypen</h3>
<p>Die Blöcke in denen Widgets angezeigt werden, hatten in den bisherigen Releases einen festen Typ. Nun ist ein Typ &#8222;Dual&#8220; hinzugekommen.</p>
<h4>Möglichkeiten</h4>
<p>Die smartVISU unterstützt Blöcke zusätzlich zu den Standard-Blöcken auch Blöcke mit &#8222;2 Seiten&#8220;, die in den bisherigen Releases von smarthome/smarthomeNG nicht unterstützt wurden.</p>
<p>Im aktuellen Release können auch diese Dual-Blöcke in der automatischen Seitengenerierung verwendet werden.</p>
<p>Hier ein Beispiel, wie ein solcher DualBlock aussehen kann:</p>
<p><img decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/beitraege/visu/blocktype_dual_1.jpg" /><span> Erste Seite des Dual-Blocks </span><img decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/beitraege/visu/blocktype_dual_2.jpg" /><span> Zweite Seite des Dual-Blocks</span></p>
<p>Ein solcher Dual-Block hat immer die Größe eines großen Blocks. Damit die Visu-Seite &#8222;aufgeräumt&#8220; aussieht, sollte für den daneben liegenden Block die große Form gewählt werden (<code>sv_blocksize = 1</code>). Diehe dazu auch den Abschnitt <strong><em>Unterschiedliche Blockgrößen</em></strong> weiter oben in diesem Artikel.</p>
<p>Hier ist ein Beispiel auf einer Visu Seite:</p>
<p><img decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/beitraege/visu/blocktype_dual_visu.jpg" width="600" /></p>
<h3></h3>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.smarthomeng.de/smartvisu-autogeneration/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Das Schalten von KNX Aktoren aus der smartVISU funktioniert nicht</title>
		<link>https://www.smarthomeng.de/das-schalten-von-knx-aktoren-aus-der-smartvisu-funktioniert-nicht</link>
					<comments>https://www.smarthomeng.de/das-schalten-von-knx-aktoren-aus-der-smartvisu-funktioniert-nicht#respond</comments>
		
		<dc:creator><![CDATA[Martin Sinn]]></dc:creator>
		<pubDate>Tue, 31 Oct 2017 15:36:04 +0000</pubDate>
				<category><![CDATA[FAQ]]></category>
		<category><![CDATA[KNX]]></category>
		<category><![CDATA[smartVISU]]></category>
		<guid isPermaLink="false">http://test.smarthomeng.de/?p=217</guid>

					<description><![CDATA[Antwort: Da sind drei unterschiedliche Tools involviert, die miteinander reden müssen. Die richtige Konfiguration muss deshalb einzeln nacheinander getestet werden: EIBD oder KNXD: (welchen Deamon genutzt ist dabei nicht erheblich). Die Funktionsfähigkeit des Deamons kann mit dem Kommando GROUPSWRITE getestet werden. Solange das nicht funktioniert, kann auch die Ansteuerung aus<a class="moretag" href="https://www.smarthomeng.de/das-schalten-von-knx-aktoren-aus-der-smartvisu-funktioniert-nicht"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<p><strong>Antwort</strong>: Da sind drei unterschiedliche Tools involviert, die miteinander reden müssen. Die richtige Konfiguration muss deshalb einzeln nacheinander getestet werden:</p>
<ol>
<li><strong>EIBD </strong>oder<strong> KNXD</strong>: (welchen Deamon genutzt ist dabei nicht erheblich). Die Funktionsfähigkeit des Deamons kann mit dem Kommando GROUPSWRITE getestet werden. Solange das nicht funktioniert, kann auch die Ansteuerung aus SmartHomeNG und smartVISU nicht funktionieren.</li>
<li><strong>SmartHomeNG</strong>: Damit SmartHomeNG mit dem KNX Bus reden kann, muss das KNX-Plugin richtig konfiguriert sein. Dieses erfolgt in der Datei /etc/plugin.conf.
<p>Um zu testen, ob SmartHomeNG mit dem KNX Bus redet, kann man Quick-and-Dirty in der Conf Datei bei dem Item das geschaltet werden soll, einen Eintrag value = 1 oder value = 0 ergänzen und SmartHomeNG neu starten. Dann sollte der KNX Aktor ein- bzw. ausschalten.</p>
<p>Erst wenn diese Kommunikation funktioniert, macht es Sinn sich der Visu zuzuwenden.</li>
<li><strong>smartVISU</strong>: Die smartVISU muss richtig konfiguriert sein, damit sie mit SmartHomeNG spricht. Sonst sieht es zwar aus, als würde sie schalten, tut sie aber nicht.
<p>Auf der Konfigurationsseite muss unter I/O-Connection folgendes eingetragen sein:</p>
<ul>
<li>Driver: Smarthome.py</li>
<li>Address:</li>
<li>Port: 2424</li>
<li>Realtime: on</li>
</ul>
<p>Wichtig: Der Eintrag <strong>localhost</strong> als Adresse funktioniert <strong>nicht</strong>!</li>
</ol>
]]></content:encoded>
					
					<wfw:commentRss>https://www.smarthomeng.de/das-schalten-von-knx-aktoren-aus-der-smartvisu-funktioniert-nicht/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>NGINX als ReverseProxy</title>
		<link>https://www.smarthomeng.de/nginx-als-reverseproxy</link>
					<comments>https://www.smarthomeng.de/nginx-als-reverseproxy#comments</comments>
		
		<dc:creator><![CDATA[Marc René Frieß]]></dc:creator>
		<pubDate>Mon, 30 Oct 2017 23:44:14 +0000</pubDate>
				<category><![CDATA[Tipps & Tricks]]></category>
		<category><![CDATA[NGINX]]></category>
		<category><![CDATA[Reverse Proxy]]></category>
		<category><![CDATA[smartVISU]]></category>
		<category><![CDATA[Zusatzsoftware]]></category>
		<guid isPermaLink="false">https://www.smarthomeng.de/?p=349</guid>

					<description><![CDATA[Um einen sicheren Zugriff auf SmartHomeNG und die smartVISU von außen (ohne VPN) zu ermöglichen, empfiehlt es sich, die Software NGINX als ReverseProxy mit Basic Authentication oder Clientzertifikaten zu nutzen. Die Idee hinter einem ReverseProxy ist, dass man einen einzigen sicheren Eintrittspunkt in das Heimnetzwerk hat, ohne ein VPN nutzen<a class="moretag" href="https://www.smarthomeng.de/nginx-als-reverseproxy"> Weiterlesen&#8230;</a>]]></description>
										<content:encoded><![CDATA[<div class="markdown-body">
<p>Um einen sicheren Zugriff auf SmartHomeNG und die smartVISU von außen (ohne VPN) zu ermöglichen, empfiehlt es sich, die Software <a href="https://www.nginx.com/" target="_blank" rel="noopener">NGINX</a> als ReverseProxy mit Basic Authentication oder Clientzertifikaten zu nutzen.</p>
<p>Die Idee hinter einem ReverseProxy ist, dass man einen einzigen sicheren Eintrittspunkt in das Heimnetzwerk hat, ohne ein VPN nutzen zu müssen. Der ReverseProxy hängt direkt hinter dem Router und wird von dort via Portforwarding angesprochen. Üblicherweise wird der HTTPS Port 443 vom Router auf den ReverseProxy umgeleitet. Für die Installation ist temporär auch der HTTP Port 80 notwendig, damit ein SSL Serverzertfikat, bspw. von <a href="https://letsencrypt.org/" target="_blank" rel="noopener">Let&#8217;s Encrypt</a>, für die hinterlegte DynDNS URL installiert werden kann.</p>
<p>Im ReverseProxy kann ein Zugriffsschutz implementiert werden, der via Basic Authentication oder Clientzertifikate realisiert wird. Beides wird in diesem Artikel erklärt. Es wird zudem auf weitere Sicherheitsmaßnahmen, wie das Blockieren von Requests aus nicht vertrauenswürdigen Ländern, eingegangen.</p>
<p>Je nach angesprungenem Kontextpfad (also bspw. <code>/smartVISU</code> oder <code>/alexa</code>) wird dann in Richtung des Hauptservers und des jeweiligen Ports weitergeleitet. Das folgende Bild illustriert das schematisch:<br />
<img loading="lazy" decoding="async" src="https://www.smarthomeng.de/wp-content/uploads/beitraege/Architecture-2.png" alt="" class="alignnone size-full wp-image-507" width="700" height="430" srcset="https://www.smarthomeng.de/wp-content/uploads/beitraege/Architecture-2.png 700w, https://www.smarthomeng.de/wp-content/uploads/beitraege/Architecture-2-300x184.png 300w" sizes="(max-width: 700px) 100vw, 700px" /></p>
<p>Die folgende Dokumentation beschreibt eine Installation von NGINX als ReverseProxy auf eigenständiger Hardware unter Raspbian Stretch Lite. Dieser ReverseProxy ist bspw. auch für das Alexa Plugin oder die Nutzung von SmartHomeNG mit &#8222;EgiGeoZone&#8220; / &#8222;Geofency&#8220; notwendig, damit ein sicherer Zugriff aus dem Internet auf die SmartHomeNG Instanz erfolgen kann.</p>
<h2>Annahmen</h2>
<p>Diese Anleitung beruht auf folgenden Annahmen</p>
<ul>
<li>NGINX wird auf einem frisch aufgesetzten RaspberryPi mit &#8222;Raspbian Stretch Lite&#8220; installiert.</li>
<li>Der RaspberryPi dient ausschliesslich der Funktion als ReverseProxy</li>
<li>Der Standarduser heißt weiterhin &#8222;pi&#8220;</li>
<li>Eine DynDNS (o.ä.) Domain ist vorhanden und leitet auf die aktuelle Internet IP</li>
<li>SmartHomeNG und smartVISU sind auf einem separaten Rechner im gleichen LAN installiert.</li>
</ul>
<h2>Basiskonfiguration</h2>
<ul>
<li>Deutsches Keyboard festlegen: <code>/etc/default/keyboard</code> editieren und in der Zeile <code>XKBLAYOUT="..."</code> ein &#8222;de&#8220; eintragen. Danach <code>sudo reboot now</code> eingeben, um neu zu starten.</li>
<li>Aus Sicherheitsgründen das Standard-Passwort für &#8222;pi&#8220; ändern: Als User &#8222;pi&#8220; mit Standard-Passwort einloggen und mit <code>passwd</code> ein neues Passwort setzen.</li>
</ul>
<h2>NGINX installieren:</h2>
<pre><code class="language-bash">sudo apt-get update
sudo apt-get install nginx-full
</code></pre>
<h2>GeoIP installieren:</h2>
<p>Über GeoIP kann mittels der anfragenden IP herausgefunden werden, aus welchem Land eine Anfrage kommt. Darüber lassen sich bspw. Requests aus Risikoländern blockieren.</p>
<pre><code class="language-bash">sudo apt-get install geoip-database libgeoip1
cd /usr/share/GeoIP/
sudo wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz
sudo gunzip GeoIP.dat.gz
</code></pre>
<h2>Let&#8217;s Encrypt Server-Zertifikate</h2>
<p>(nach <a href="https://goneuland.de/debian-9-stretch-lets-encrypt-zertifikate-mit-certbot-erstellen/" rel="nofollow" title="https://goneuland.de/debian-9-stretch-lets-encrypt-zertifikate-mit-certbot-erstellen/">https://goneuland.de/debian-9-stretch-lets-encrypt-zertifikate-mit-certbot-erstellen/</a>)</p>
<p>Über Let&#8217;s Encrypt lassen sich kostenlos SSL Zertifikate, bspw. für dyndns-Domains, ausstellen.</p>
<p>Certbot installieren:</p>
<pre><code class="language-bash">sudo apt-get install certbot
</code></pre>
<p>Nun die Datei <code>/etc/nginx/snippets/letsencrypt.conf</code> bearbeiten:</p>
<pre><code class="language-bash">sudo nano /etc/nginx/snippets/letsencrypt.conf
</code></pre>
<p>Dort folgenden Inhalt einfügen, damit certbot die Identität überprüfen kann.:</p>
<pre><code class="language-bash">location ^~ /.well-known/acme-challenge/ {
 default_type "text/plain";
 root /var/www/letsencrypt;
}
</code></pre>
<pre><code class="language-bash">sudo mkdir -p /var/www/letsencrypt/.well-known/acme-challenge
</code></pre>
<pre><code class="language-bash">sudo nano /etc/nginx/sites-available/default
</code></pre>
<p>Dort unterhalb von <code>listen [::]:80 default_server;</code> die Zeile <code>include /etc/nginx/snippets/letsencrypt.conf;</code> einhängen:</p>
<pre><code class="language-json">server {
        listen 80 default_server;
        listen [::]:80 default_server;
        include /etc/nginx/snippets/letsencrypt.conf;
[...]
</code></pre>
<pre><code class="language-bash">sudo service nginx restart
</code></pre>
<p>Temporär Port 80 im Router auf den RaspberryPi weiterleiten !</p>
<pre><code class="language-bash">sudo certbot certonly --rsa-key-size 4096 --webroot -w /var/www/letsencrypt -d &lt;mydomain&gt;.&lt;myds&gt;.&lt;me&gt; 
</code></pre>
<p>Nachdem man seine E-Mail eingegeben hat, sollte die Generierung erfolgreich durch laufen und mit</p>
<pre><code class="language-text">Generating key (4096 bits): /etc/letsencrypt/keys/0000_key-certbot.pem
Creating CSR: /etc/letsencrypt/csr/0000_csr-certbot.pem
</code></pre>
<p>enden.</p>
<p>Port 80 im Browser wieder schließen, dafür Port 443 (https) entsprechend auf den ReverseProxy-RaspberryPi weiterleiten!</p>
<h2>NGINX Konfiguration</h2>
<p>/etc/nginx/nginx.conf bearbeiten und direkt im &#8222;http&#8220; Block die GeoIP Einstellungen hinzufügen. Unter der Konfiguration der &#8222;virtual hosts&#8220; noch einen Block als Schutz gegen Denial of Service Angriffe ergänzen:</p>
<pre><code class="language-nginx">http {
    ##
    # GeoIP Settings
    # Nur Länder aus erlaubten IP Bereichen dürfen den ReverseProxy
    # passieren!
    # https://www.howtoforge.de/anleitung/nginx-besucher-mit-dem-geoip-modul-nach-landern-blocken-debianubuntu/
    ##
    geoip_country /usr/share/GeoIP/GeoIP.dat;
    map $geoip_country_code $allowed_country {
        default yes;
        BY no;
        BR no;
        KP no;
        KR no;
        RS no;
        RO no;
        RU no;
        CN no;
        CD no;
        NE no;
        GH no;
        IQ no;
        IR no;
        SY no;
        UA no;
    }
[...]
    ##
    # Virtual Host Configs
    ##

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;

    ##
    # Harden nginx against DDOS
    ##

    client_header_timeout 10;
    client_body_timeout   10;
}
</code></pre>
<p>NGINX mit <code>sudo service nginx restart</code> neu starten.</p>
<h3>/etc/nginx/conf.d/&lt;mydomain&gt;.&lt;myds&gt;.&lt;me&gt;.conf erstellen</h3>
<pre><code class="language-nginx">server {
    server_tokens off;
    
    ## Blocken, wenn Zugriff aus einem nicht erlaubten Land erfolgt ##
    if ($allowed_country = no) {
        return 403;
    }    
    
    # https://www.cyberciti.biz/tips/linux-unix-bsd-nginx-webserver-security.html
    ## Block download agents ##
    if ($http_user_agent ~* LWP::Simple|BBBike|wget) {
        return 403;
    }

    ## Block some robots ##
    if ($http_user_agent ~* msnbot|scrapbot) {
        return 403;
    }

    ## Deny certain Referers ##
    if ( $http_referer ~* (babes|forsale|girl|jewelry|love|nudit|organic|poker|porn|sex|teen) )
    {
        return 403;
    }

    listen 443 ssl default_server;
    server_name &lt;mydomain&gt;.&lt;myds&gt;.&lt;me&gt;;

    ##
    # SSL
    ##
    
    ## Activate SSL, setze SERVER Zertifikat Informationen ## 
    # Generiert via Let's Encrypt! 
    ssl on;
    ssl_certificate /etc/letsencrypt/live/&lt;mydomain&gt;.&lt;myds&gt;.&lt;me&gt;/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/&lt;mydomain&gt;.&lt;myds&gt;.&lt;me&gt;/privkey.pem;
    ssl_session_cache builtin:1000 shared:SSL:10m;
    ssl_prefer_server_ciphers on;
    # unsichere SSL Ciphers deaktivieren!
    ssl_ciphers    HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!RC4;
    
    ##
    # HSTS
    ##

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    ##
    # global
    ##

    root /var/www/&lt;mydomain&gt;.&lt;myds&gt;.&lt;me&gt;;
    index index.php index.htm index.html;
    
    # Weiterleitung zu SmartHomeNG (Websocket Schnittstelle) mit Basic Auth
    # Nur Verbindungen gegen "/" durchlassen! Also weder auf Dateien noch Verzeichnisse (= nur Websocket Connects)
    location = / {
        auth_basic "Restricted Area: smartVISU";
        auth_basic_user_file /etc/nginx/.smartvisu;      
        proxy_pass http://&lt;SmartHomeNG LAN IP&gt;:&lt;Websocket Port&gt;;        
    }

    # Zugriff auf die smartVISU mit Basic Auth
    location /smartVISU {      
        auth_basic "Restricted Area: smartVISU";
        auth_basic_user_file /etc/nginx/.smartvisu;
        proxy_pass http://&lt;smartVISU Server LAN IP&gt;/smartVISU;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    
    # Alexa Plugin Weiterleitung
    location /alexa {
        auth_basic "Restricted Area: Alexa";
        auth_basic_user_file /etc/nginx/.alexa;
        proxy_pass http://&lt;SmartHomeNG LAN IP&gt;:&lt;Alexa Plugin Port&gt;/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # Network Plugin Weiterleitung
    location /shng {
        auth_basic "Restricted Area: SmartHomeNG";
        auth_basic_user_file /etc/nginx/.shng;
        proxy_pass http://&lt;SmartHomeNG LAN IP&gt;:&lt;Network Plugin Port&gt;/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
</code></pre>
<h3>NGINX reloaden:</h3>
<pre><code class="language-bash">/etc/init.d/nginx reload
</code></pre>
<h3>Passwort-Files für unterschiedliche User für smartVISU, Alexa, Network Plugin erstellen</h3>
<pre><code class="language-bash">sudo apt-get install apache2-utils

sudo htpasswd -c /etc/nginx/.smartvisu &lt;username&gt;
sudo htpasswd -c /etc/nginx/.alexa &lt;username&gt;
sudo htpasswd -c /etc/nginx/.shng &lt;username&gt;
</code></pre>
<p>Dann ein Passwort vergeben.</p>
<p>Der Zugriff auf https://../smartVISU sollte nun klappen.</p>
<h3>Nacharbeiten: Port 80 in NGINX deaktivieren</h3>
<p>Da NGINX im LAN aktuell noch auf Port 80 konfiguriert ist, sollte man in der /etc/nginx/sites-available/default noch ein <code>return 403</code> ergänzen und NGINX neu starten:</p>
<pre><code class="language-nginx">server {
        listen 80 default_server;
        listen [::]:80 default_server;

        return 403;

        include /etc/nginx/snippets/letsencrypt.conf;
</code></pre>
<pre><code class="language-bash">/etc/init.d/nginx reload
</code></pre>
<h2>Client Zertifikate erstellen (optional)</h2>
<h3>openssl.cnf editieren</h3>
<pre><code class="language-bash">sudo nano /etc/ssl/openssl.cnf
</code></pre>
<p>Folgende Zeilen anpassen:</p>
<pre><code class="language-ini">dir = /etc/ssl/ca                       # Directory where everything is kept
[...]
new_certs_dir = $dir/certs               # default place for new certs.
[...]
certificate = $dir/ca.crt               # The CA certificate
[...]
crl = $dir/crl.pem                      # The current CRL
private_key = $dir/private/ca.key       # The private key
[...]
default_md = sha1 # use public key default MD
</code></pre>
<p>Drei neue Verzeichnisse und drei Dateien anlegen:</p>
<pre><code class="language-bash">sudo mkdir -p /etc/ssl/ca/certs/users
sudo mkdir -p /etc/ssl/ca/crl
sudo mkdir -p /etc/ssl/ca/private

sudo touch /etc/ssl/ca/index.txt
sudo touch /etc/ssl/ca/index.txt.attr
</code></pre>
<p>In der Datei crlnumber den Wert &#8222;01&#8220; eintragen und speichern.</p>
<pre><code class="language-bash">sudo nano /etc/ssl/ca/crlnumber
</code></pre>
<p>Zertifikat für Certification Authority (CA) erstellen, Passwort für die CA wählen und eigene Daten eingeben:</p>
<pre><code class="language-bash">sudo openssl genrsa -des3 -out /etc/ssl/ca/private/ca.key 4096
sudo openssl req -new -x509 -days 1095 -key /etc/ssl/ca/private/ca.key -out /etc/ssl/ca/certs/ca.crt
sudo openssl ca -name CA_default -gencrl -keyfile /etc/ssl/ca/private/ca.key -cert /etc/ssl/ca/certs/ca.crt -out /etc/ssl/ca/private/ca.crl -crldays 1095
</code></pre>
<p>Client Zertifikat für einen User erstellen und ein Passwort für das Client Zertifikat vergeben:</p>
<pre><code class="language-bash">sudo openssl genrsa -des3 -out /etc/ssl/ca/certs/users/&lt;USERNAME&gt;.key 1024
sudo openssl req -new -key /etc/ssl/ca/certs/users/&lt;USERNAME&gt;.key -out /etc/ssl/ca/certs/users/&lt;USERNAME&gt;.csr
</code></pre>
<p>Bei folgendem Schritt das Passwort für die CA eingeben:</p>
<pre><code class="language-bash">sudo openssl x509 -req -days 1095 -in /etc/ssl/ca/certs/users/&lt;USERNAME&gt;.csr -CA /etc/ssl/ca/certs/ca.crt -CAkey /etc/ssl/ca/private/ca.key -CAserial /etc/ssl/ca/serial -CAcreateserial -out /etc/ssl/ca/certs/users/&lt;USERNAME&gt;.crt
</code></pre>
<p>Bei folgendem Schritt mit dem Passwort für das Client Zertifikat bestätigen und ein Export Passwort wählen:</p>
<pre><code class="language-bash">sudo openssl pkcs12 -export -clcerts -in /etc/ssl/ca/certs/users/&lt;USERNAME&gt;.crt -inkey /etc/ssl/ca/certs/users/&lt;USERNAME&gt;.key -out /etc/ssl/ca/certs/users/&lt;USERNAME&gt;.p12 
</code></pre>
<p>&lt;USERNAME&gt;.p12 File herunterladen:</p>
<pre><code class="language-bash">sudo cp /etc/ssl/ca/certs/users/&lt;USERNAME&gt;.p12 /home/pi
cd /home/pi/
sudo chown pi &lt;USERNAME&gt;.p12
</code></pre>
<p>Bspw. nun via SFTP ziehen und aufs Datei aufs Android Handy übertragen und ausführen oder im Browser unter Zertifikate&#8220; importieren. Dabei muss es mit Export Passwort bestätigt werden.</p>
<h2>Client Zertifikate in NGINX nutzen (optional)</h2>
<p>Anleitung nach <a href="https://arcweb.co/securing-websites-nginx-and-client-side-certificate-authentication-linux/" rel="nofollow" title="https://arcweb.co/securing-websites-nginx-and-client-side-certificate-authentication-linux/">https://arcweb.co/securing-websites-nginx-and-client-side-certificate-authentication-linux/</a></p>
<p>/etc/nginx/conf.d/&lt;mydomain&gt;.&lt;myds&gt;.&lt;me&gt;.conf bearbeiten und die Zeilen im SSL Block ergänzen (&#8222;ab Client Zertifikat spezifisch&#8220;)</p>
<pre><code class="language-nginx">    ##
    # SSL
    ##

    ## Activate SSL, setze SERVER Zertifikat Informationen ##
    # Generiert via Let's Encrypt!    
    ssl on;
    ssl_certificate /etc/letsencrypt/live/&lt;mydomain&gt;.&lt;myds&gt;.&lt;me&gt;/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/&lt;mydomain&gt;.&lt;myds&gt;.&lt;me&gt;/privkey.pem;
    ssl_session_cache builtin:1000 shared:SSL:10m;
    ssl_prefer_server_ciphers on;
    # unsichere SSL Ciphers deaktivieren!
    ssl_ciphers    HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!RC4;

    # Client Zertifikat spezifisch
    ssl_client_certificate /etc/ssl/ca/certs/ca.crt;
    ssl_crl /etc/ssl/ca/private/ca.crl;
    ssl_verify_client optional;
    ssl_session_timeout 5m;
</code></pre>
<p>Die smartVISU relevanten Teile könnten jetzt folgendermaßen über Clientzertifikate geschützt werden:</p>
<pre><code class="language-json">    # Weiterleitung zu SmartHomeNG (Websocket Schnittstelle) mit Clientzertifikat
    location = / {
        # Clientzertifikat gültig?
        if ($ssl_client_verify != SUCCESS) {
                return 403;
        }
        proxy_pass http://&lt;SmartHomeNG LAN IP&gt;:&lt;Websocket Port&gt;;      
    }

    # Zugriff auf die smartVISU mit Clientzertifikat
    location /smartVISU {  
        # Clientzertifikat gültig?    
        if ($ssl_client_verify != SUCCESS) {
                return 403;
        }
        proxy_pass http://&lt;smartVISU Server LAN IP&gt;/smartVISU;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
</code></pre>
<p>Wer es doppelt sicher haben möchte, kann die Basic Auth in den jew. Blöcken auch beibehalten.</p>
<p>Testbar ist das Ganze, wenn es im Browser ohne Zertifikat einen 403er Fehler gibt und mit Zertifikat die smartVISU aufbaut.</p>
<h2>Erweiterung: Stärkere Diffie-Hellman-Parameter</h2>
<p>Damit die Sicherheit &#8222;perfekt&#8220; wird, sollten stärkere Diffie-Hellman-Schlüssel verwendet werden. Dazu muss ein neues .pem File generiert werden. Es empfiehlt sich, die Erzeugung dieses Files nicht direkt auf den Raspi, sondern auf einem PC mit stärkerer CPU durchzuführen. Ein Test auf einem Raspi3 dauerte 24 Stunden (!). Ein Intel 4790k brauchte hingegen nur 30 Minuten.</p>
<p>Folgendes ist zu tun:</p>
<pre><code class="language-bash">cd /etc/ssl/certs
sudo openssl dhparam -out dhparam.pem 4096
</code></pre>
<p>Alternativ kann die Datei auch einfach in <code>/etc/ssl/certs</code> kopiert werden.</p>
<p>Danach ist in der SSL Konfiguration von NGINX folgende Zeile zu ergänzen und NGINX neu zu starten:</p>
<pre><code class="language-bash"># Konfiguration editieren
sudo nano /etc/nginx/conf.d/\&lt;mydomain\&gt;.\&lt;myds\&gt;.\&lt;me\&gt;.conf 
</code></pre>
<pre><code class="language-bash">## Dort folgende Zeile im Block SSL einfügen:

##
# SSL
##
[...]
ssl_dhparam /etc/ssl/certs/dhparam.pem;
[...]
</code></pre>
<pre><code class="language-bash">## NGINX neu starten
sudo service nginx restart
</code></pre>
<p>Die Sicherheit der eigenen https-Domain kann nun unter <a href="https://www.ssllabs.com/ssltest/" rel="nofollow" title="https://www.ssllabs.com/ssltest/">https://www.ssllabs.com/ssltest/</a> getestet werden. Mit den oben genannten Maßnahmen sollte ein A+ erreicht werden.</p>
<p>Der versiertere Nutzer kann sich unter <a href="https://mozilla.github.io/server-side-tls/ssl-config-generator/" rel="nofollow" title="https://mozilla.github.io/server-side-tls/ssl-config-generator/">https://mozilla.github.io/server-side-tls/ssl-config-generator/</a> auch gleich eine eigene Konfiguration generieren lassen.</p>
</div>
<h2>Wartung: Zertifikat nach 3 Monaten erneuern</h2>
<p>Nach 3 Monaten muss das Let&#8217;s Encrypt Serverzertifikat erneuert werden. Damit das Erneuerungs-Skript funktioniert, muss Port 80 im <span class="highlighted">NGINX</span> freigegeben, bzw. über einen separaten <code>server</code> Block auf HTTPS umgeleitet werden:</p>
<pre><code class="language-bash">
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 301 https://$host$request_uri;
}
</code></pre>
<p>Die Erneuerung geht dann wie folgendermaßen:<br />
<code>sudo certbot certonly --rsa-key-size 4096 --webroot -w /var/www/letsencrypt -d &lt;mydomain&gt;.&lt;myds&gt;.&lt;me&gt;</code></p>
<p>Im nun folgenden Dialog Option 2 (2: Renew &amp; replace the cert (limit ~5 per 7 days)) auswählen. Danach <span class="highlighted">NGINX</span> neu starten:<br />
<code>sudo service nginx restart</code><code></code></p>
<p>Der Test über <a href="https://www.ssllabs.com/ssltest/">https://www.ssllabs.com/ssltest/</a> oder der Aufruf im Browser gibt nun Aufschluß über die Laufzeit des verlängerten Zertifikats.</p>
<p><strong>Tipp: </strong>Endet die Erneuerung mit einem Timeout, kann dies ggf. an einer fälschlicherweise an den DNS Server propagierten IPV6 Addresse liegen. In diesem Fall testweise bei den DynDNS Einstellungen diese deaktivieren.</p>
<p><em>(Die in diesem Artikel verwendeten Screenshots und Grafiken wurden selber erstellt. Verwendete Symbole und Icons stammen von https://openclipart.org. 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/nginx-als-reverseproxy/feed</wfw:commentRss>
			<slash:comments>23</slash:comments>
		
		
			</item>
	</channel>
</rss>
