MagicMirror mit MQTT-Anbindung + PowerSave

26. August 2018 at 12:34
Print Friendly, PDF & Email

Ein Magic Mirror sieht edel aus und stand schon länger auf meiner Wunschliste.
Für OpenHAB hatte ich seit einem Jahr ein Tablet im Eingangsbereich, mit dem meine Familie nicht wirklich glücklich war.
– Der Bildschirm war mit 7 Zoll zu klein
– Das Design der Oberfläche mit HABPanel war nicht schön genug
– Das Wechsel von einem Panel zum nächsten war zu lang (das Table hatte nicht genug Rechenleistung)
– Die Steuerung war zu träge

Der Spiegel sieht in echt besser aus. Es halt doof einen Spiegel zu fotografieren, wenn man selber nicht auf dem Bild sein möchte.

Was man braucht:

 

Installation

Die Anzeige gefällt mir nun richtig gut. Bei der Installation gab es jedoch einige Probleme.

Grundsätzlich basiert das Sytem auf node-Modulen und einem Web-Browser. Dafür sollte eigentlich ein Pi-Zero ausreichen. Leider unterstützt MagicMirror in der neuesten Version dies nicht mehr. Also habe ich einen Pi3 eingesetzt.

Das Installations-Script verwendet leider nicht n und installiert alte Versionen. Danach lassen sich andere MM-Module nicht installieren. Also vorher n installieren und Versionen prüfen

curl -L https://git.io/n-install | bash
node --version
npm --version

 

Anschliessend MM installieren … und der Bildschirm war schwarz. Das Installations-Script hatte einfach die fonts nicht installiert.

cd ~/MagicMirror/vendor
npm install

Zum Thema fonts: Wenn man besondere fonts braucht, lassen die sich auch vom Windows-PC kopieren. Die liegen dort unter C:\Windows\Fonts

cd
mkdir .fonts
# copy font files from windows PC

 

Neben der Standard-Installation habe ich mir noch einen handler in Python geschrieben, um die Taster und den Bewegungssensor auszuwerten. Mein MM besitzt keine Touch-Oberfläche. Das wäre auch nicht schön, da bei ausgeschaltetem Monitor die Spiegelfläche voll Fingerabdrücke wäre. Nach der Erfahrung mit ObenHAB wollte ich auch wieder einfache Taster. Weiterhin habe ich diverse Module im Haus über MQTT  vernetzt. Dies hat zwei entscheidende Vorteile. Man kann alle anderen System leicht ankoppeln und man kann über entsprechende Tools in Echtzeit sehen, ob Nachrichten auch wirklich gesendet werden.

Funktionen

Folgende Module werden angezeigt

  • Uhrzeit
  • 2 google Kalender
  • Wetter
  • fritz!Box Anrufe
  • Temperaturen von Sensoren via MQTT
  • IPCam via RTSP

Funktionen im Hintergrund

  • Monitor an/aus basierend auf Bewegungssensor / PIR
  • Türklingel triggert die Anzeige der IPCam
    Klingel über MQTT angebunden
  • Garagentor öffnen/schliessen
    Ein 433 MHz Sender ist über MQTT angebunden

Live-Stream der IP-CAM:

 

Feedback, wenn die Taste für die Garage gedrückt wurde:

Aufbau

Der Rahmem ist von Ikea – kostet 13,-EUR

Mit schwarzem Karton habe ich ein Pass-Partout aufgelegt, damit das Hintergrundlicht nicht den Effekt des Spiegels verhindert.

In der Mitte sieht man das Panel und die Elektronik des 17” Monitors.
Die 5V für den raspberry habe ich vom Netzteil abgegriffen.

In der Mitte unten, sieht man den PIR / Bwegeungssensor.
Unten links das Touch-Panel. Das wird aber noch durch konventionelle Schalter ersetzt.
Im ersten Praxis-Test hat sich gezeigt, dass man zu leicht zwei Tasten gleichzeitig auslöst.

Die Tiefe des Ikea-Rahmens reicht nicht aus. Daher habe ich Leisten eingefügt, in dem der Spiegel auch aufgehängt wird. Die Elektronik ist auch mit den Leisten verschraubt.

Zwei Leisten unterhalb des TFT-Panels verhindern das dieser nach unten rutscht und gleichzeitig kann man dort isoliert den Raspberry montieren.

Für den stabilen Betrieb werden die Leitungen für den PIR-Sensor durch ein Ferrit-Kern geführt.

 

Energieverbrauch senken

Der gelbe Blitz tauchte auf und zeigt ein Problem mit der Stromversorgung an. Nun kann man zwar einfach ein dickes Netzteil dranhängen (natürlich mit einem guten Kabel /AGW24) oder man senkt den Energiebedarf.

Powertop

Hierüber kann man sehen wie das System ausgelastet ist und wer den Verbrauch nach oben treibt.

sudo apt-get install powertop
sudo powertop

 

USB-Schnittstelle abschalten

USB wird bei mir gar nicht benötigt, also kann man dies beim PI3 abschalten, ohne die WLAN Verbindung zu kappen.

Vorher

USB Schnittstelle abschalten

echo '1-1' | sudo tee /sys/bus/usb/drivers/usb/unbind

Nachher

CPU-Usage Electron senken

Vorher

GL-Treiber aktivieren

sudo nano /boot/config.txt
 dtoverlay=vc4-fkms-v3d

Nacher

Handler als Service

Der Handler kann nicht über crontab gestartet werden, da MQTT dies verhindert.
Also installiert man einen Dienst.

Service Datei anlegen: /lib/systemd/system/mm-handler.service

[Unit]
Description=Magic Mirror handler for buttons on PIR
After=network.target
 
[Service]
Type=simple
ExecStart=/usr/bin/python /home/pi/mm_handler.py -name mmhandler
Restart=always
 
[Install]
WantedBy=multi-user.target

 

Mit folgenden Befehlen steuert man den Dienst:

Register for next boot

systemctl enable mm-handler

Start manually

systemctl start mm-handler

Stop manually

systemctl stopmm-handler

Status

systemctl status mm-handler

MM Handler mit MQTT Anbindung

 

 

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# file mm_handler.py
# to be installed as servive
#
import RPi.GPIO as GPIO
import time
import subprocess
import paho.mqtt.client as mqtt
import urllib3
import sys
import atexit
 
# 1st MQTT Broker
MQTT_SERVER_20 = '192.168.1.xxx'
MQTT_PORT_20 = '1883'
MQTT_USER_20 = 'mqttuser1'
MQTT_PW_20 = 'mqttpw1'
MQTT_TOPIC_20 = '1stlvl/remote/xxx/cmnd'
 
# 2nd MQTT Broker
MQTT_SERVER_75 = '192.168.1.yyy'
MQTT_PORT_75 = '1883'
MQTT_USER_75 = 'mqttuser2'
MQTT_PW_75 = 'mqttpw2'
MQTT_TOPIC_75 = '1stlvl/tuer1/switchDoor/on'
 
url_up = 'http://192.168.1.xxx:8080/remote?action=NOTIFICATION&notification=SHOW_ALERT&payload=%7b%22title%22:%22Garage%22,%22message%22:%22TOR%20GEHT%20AUF%22%7d'
url_down = 'http://192.168.1.xxx:8080/remote?action=NOTIFICATION&notification=SHOW_ALERT&payload=%7b%22title%22:%22Garage%22,%22message%22:%22TOR%20GEHT%20ZU%22%7d'
url_door = 'http://192.168.1.xxx:8080/remote?action=NOTIFICATION&notification=SHOW_ALERT&payload=%7b%22title%22:%22Eingang%22,%22message%22:%22ES%20KLINGELT%22%7d'
url_hideA ='http://192.168.1.xxx:8080/remote?action=NOTIFICATION&notification=HIDE_ALERT'
 
url_show = 'http://192.168.1.xxx:8080/remote?action=SHOW&module=module_15_MMM-RTSPStream'
url_hide = 'http://192.168.1.xxx:8080/remote?action=HIDE&module=module_15_MMM-RTSPStream'
SLEEP_TIME = 45
 
GPIO.setmode(GPIO.BCM) # use the pin number as on the raspi board
Button_1_DOWN 	= 10 # 1 - PIN 19
Button_2_IPCAM 	= 22 # 2 - PIN 15
Button_3_DOOR 	= 27 # 3 - PIN 13
Button_4_UP 	= 17 # 4 - PIN 11
Button_5_PIR = 4        # Pin 7 on the board
 
GPIO.setup(Button_1_DOWN	, GPIO.IN)
GPIO.setup(Button_2_IPCAM	, GPIO.IN)
GPIO.setup(Button_3_DOOR	, GPIO.IN)
GPIO.setup(Button_4_UP		, GPIO.IN) 
GPIO.setup(Button_5_PIR		, GPIO.IN)
 
time_stamp = time.time()
 
SHUTOFF_DELAY = 120  # seconds
turned_off = False
last_motion_time = time.time()
 
UPTIME_DELAY = 60 # seconds
start_uptime_time = time.time()
last_uptime_time = time.time()
 
#GPIO.setup  (LED_GPIOPin   , GPIO.OUT) # set pin 7 as output
#GPIO.output (LED_GPIOPin   , False    )# set pin 7 Low
 
Counter1 = Counter2 = Counter3 = Counter4 = Counter5 = 0
CounterPrior1 = CounterPrior2 = CounterPrior3 = CounterPrior4 = CounterPrior5 = 0
 
# ----------------------------------------------------------
def clean_exit():
	# open("/tmp/counter", "w").write("%d" % _count)
	client20.publish("house/magicmirror/online","false")#publish
	client20.publish("house/magicmirror/uptime","0")#publish
	print "mm_handler.py> exit program"
 
atexit.register(clean_exit)	
 
# ----------------------------------------------------------
def Button_1_Interrupt(channel):
	global time_stamp       # put in to debounce
	time_now = time.time()
	global Counter1
	Counter1 = Counter1 + 1
	print "---------------------------------------- Button interrupt -> Counter :" + str(Counter1)
	return
# ----------------------------------------------------------
def Button_2_Interrupt(channel):
	global time_stamp       # put in to debounce
	time_now = time.time()
	global Counter2
	Counter2 = Counter2 + 1
	print "---------------------------------------- Button interrupt -> Counter :" + str(Counter2)
	return
 
# ----------------------------------------------------------
def Button_3_Interrupt(channel):
	global time_stamp       # put in to debounce
	time_now = time.time()
	global Counter3
	Counter3 = Counter3 + 1
	print "---------------------------------------- Button interrupt -> Counter :" + str(Counter3)
	return
 
# ----------------------------------------------------------
def Button_4_Interrupt(channel):
	global time_stamp       # put in to debounce
	time_now = time.time()
	global Counter4
	Counter4 = Counter4 + 1
	print "---------------------------------------- Button interrupt -> Counter :" + str(Counter4)
	return	
 
# ----------------------------------------------------------
def Button_PIR_Interrupt(channel):
	global time_stamp       # put in to debounce
	time_now = time.time()
	global Counter5
	Counter5 = Counter5 + 1
	print "---------------------------------------- Button interrupt -> Counter :" + str(Counter4)
	return	
 
# ----------------------------------------------------------
def on_connect_75(client, userdata, flags, rc):
    print("mm_handler.py> Connected to 75 with result code " + str(rc))
    # Subscribing in on_connect() means that if we lose the connection and reconnect then subscriptions will be renewed.
    client.subscribe(MQTT_TOPIC_75)
 
# The callback for when the client receives a CONNACK response from the server.
def on_connect_20(client, userdata, flags, rc):
    print("mm_handler.py> Connected to 20 with result code " + str(rc))
    client.subscribe(MQTT_TOPIC_20)
 
# The callback for when a PUBLISH message is received from the server.
def on_message_75(client, userdata, msg):
    print("Topic: ", msg.topic + "\nMessage: " + str(msg.payload))
    if msg.payload == 'true' or msg.payload == 'TRUE':
        print("mm_handler.py> doorbell on")
        http = urllib3.PoolManager()
        response = http.request('GET', url_door)
        time.sleep(2) # in seconds
        # "identifier":"module_15_MMM-RTSPStream"
        response = http.request('GET', url_hideA)
        print("mm_handler.py> "+ url_show )
        http = urllib3.PoolManager()
        response = http.request('GET', url_show)
        time.sleep(SLEEP_TIME) # in seconds
        print("mm_handler.py> "+ url_hide )
        http = urllib3.PoolManager()
        response = http.request('GET', url_hide)
        print "mm_handler.py> done"
    if msg.payload == 'false' or msg.payload == 'FALSE':
        print("mm_handler.py> doorbell off")
 
client20 = mqtt.Client()
client75 = mqtt.Client()
#---------------------------------------------------------
# main function
def main():
 
	global Counter1, Counter2, Counter3, Counter4, Counter5
	global CounterPrior1, CounterPrior2, CounterPrior3, CounterPrior4, CounterPrior5
	global turned_off, last_motion_time, last_uptime_time, start_uptime_time
	global client20, client75
 
	print "mm_handler.py> -----------------------  register events"
	GPIO.add_event_detect(Button_1_DOWN, 	GPIO.RISING, callback = Button_1_Interrupt, bouncetime = 200)
	GPIO.add_event_detect(Button_2_IPCAM, 	GPIO.RISING, callback = Button_2_Interrupt, bouncetime = 200)
	GPIO.add_event_detect(Button_3_DOOR, 	GPIO.RISING, callback = Button_3_Interrupt, bouncetime = 200)
	GPIO.add_event_detect(Button_4_UP, 		GPIO.RISING, callback = Button_4_Interrupt, bouncetime = 200)
	GPIO.add_event_detect(Button_5_PIR,		GPIO.RISING, callback = Button_PIR_Interrupt, bouncetime = 200)
 
	print "mm_handler.py> -----------------------  connect to MQTT server 20"
	client20.on_connect = on_connect_20
	client20.username_pw_set(MQTT_USER_20, MQTT_PW_20)
	print("mm_handler.py> Now trying to connect: " + MQTT_SERVER_20 +" ...")
	client20.connect(MQTT_SERVER_20)
	client20.loop_start()
 
	print "mm_handler.py> -----------------------  connect to MQTT server 75"
	client75.on_connect = on_connect_75
	client75.on_message = on_message_75
	client75.username_pw_set(MQTT_USER_75, MQTT_PW_75)
	print("mm_handler.py> Now trying to connect: " + MQTT_SERVER_75 +" ...")
	client75.connect(MQTT_SERVER_75)
	client75.loop_start()
 
	print "mm_handler.py> wait until PIR is ready ..."
	while GPIO.input(Button_5_PIR) != 0: # Schleife, bis PIR == 0 ist
		time.sleep(0.1)
	print "mm_handler.py> PIR ready..."
	client20.publish("house/magicmirror/online",'true')#publish
	client20.publish("house/magicmirror/uptime",'0')#publish
 
	print "mm_handler.py> -----------------------  polling on events started ..."
	while True:
		# increment value if button is pressed
		if Counter1 > CounterPrior1:
			print "mm_handler.py> button DOWN pressed > Counter1 > 0 :" + str(Counter1)
			#subprocess.call('/home/pi/mqttpub_20.sh -t house/433/ardu1/cmnd \'{"code":"10110","device":"10000","state":"0","count":"3"}\'', shell=True)
			http = urllib3.PoolManager()
			response = http.request('GET', url_down)
			#client.connect(MQTT_SERVER)
			client20.publish("1stlvl/433/cmnd",'{"code":"10111","device":"10000","state":"1","count":"3"}')#publish
			#client20.disconnect() #disconnect
			CounterPrior1 = Counter1 = 0
			time.sleep(5.5) # wait 500ms
			response = http.request('GET', url_hideA)
			print "mm_handler.py> ------------------- wait for next push....."
 
		if Counter4 > CounterPrior4:
			print "mm_handler.py> button UP pressed > Counter4 > 0 :" + str(Counter4)
			# subprocess.call('/home/pi/mqttpub_20.sh -t house/433/ardu1/cmnd \'{"code":"10110","device":"10000","state":"1","count":"3"}\'', shell=True)
			http = urllib3.PoolManager()
			response = http.request('GET', url_up)
			#client20.connect(MQTT_SERVER_20)
			client20.publish("1stlvl/433/cmnd",'{"code":"10111","device":"10000","state":"0","count":"3"}')#publish
			#client20.disconnect() #disconnect
			CounterPrior4 = Counter4 = 0
			time.sleep(5.5) # wait 500ms
			response = http.request('GET', url_hideA)
			print "mm_handler.py> ------------------- wait for next push....."
 
		if Counter2 > CounterPrior2:
			print "mm_handler.py> button IPCam pressed> Counter2 > 1 :" + str(Counter2)
			# subprocess.call('/home/pi/mm_show.sh', shell=True)
			CounterPrior2 = Counter2 = 0
			print "mm_handler.py> ------------------- wait for next push....."
 
		if Counter3 > CounterPrior3:
			print "mm_handler.py> button DOOR pressed> Counter3 > 1 :" + str(Counter3)
			# subprocess.call('/home/pi/doorbell_sim.sh', shell=True)
			CounterPrior3 = Counter3 = 0
			print "mm_handler.py> ------------------- wait for next push....."
 
		if Counter5 > CounterPrior5:
			print "mm_handler.py> PIR move> Counter5 > 1 :" + str(Counter5)
			last_motion_time = time.time()
			if turned_off:
				turned_off = False
				client20.publish("1stlvl/magicmirror/status",'Monitor.ON')#publish
				subprocess.call("vcgencmd display_power 1", shell=True)
			CounterPrior5 = Counter5 = 0
			print "mm_handler.py> ------------------- wait for next move....."
 
		if not turned_off and time.time() > (last_motion_time + SHUTOFF_DELAY):
			turned_off = True
			client20.publish("1stlvl/magicmirror/status",'Monitor.OFF')#publish
			subprocess.call("vcgencmd display_power 0", shell=True)
 
		if time.time() > (last_uptime_time + UPTIME_DELAY):
			uptime_units = round((last_uptime_time - start_uptime_time),0)/60 # convert sec in min
			client20.publish("1stlvl/magicmirror/online","true")#publish
			client20.publish("1stlvl/magicmirror/uptime",uptime_units)#publish
			last_uptime_time = time.time()
 
		time.sleep(0.5) # wait 500ms
 
		# 
	return 0
 
if __name__ == '__main__':
 
	 # call main function
	 main()

 

Konfiguration config.js

Download: config_public

/* Magic Mirror Config Sample
 *
 * By Michael Teeuw http://michaelteeuw.nl
 * MIT Licensed.
 *
 * For more information how you can configurate this file
 * See https://github.com/MichMich/MagicMirror#configuration
 *
 * check errors in this file with http://jshint.com/
 *
 */
 
var config = {
	address: "localhost", // Address to listen on, can be:
	                      // - "localhost", "127.0.0.1", "::1" to listen on loopback interface
	                      // - another specific IPv4/6 to listen on a specific interface
	                      // - "", "0.0.0.0", "::" to listen on any interface
	                      // Default, when address config is left out, is "localhost"
	port: 8080,
	ipWhitelist: ["127.0.0.1", "192.168.1.xxx", "::ffff:127.0.0.1", "::1"], // Set [] to allow all IP addresses
	                                                       // or add a specific IPv4 of 192.168.1.5 :
	                                                       // ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.1.5"],
	                                                       // or IPv4 range of 192.168.3.0 --> 192.168.3.15 use CIDR format :
	                                                       // ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.3.0/28"],
 
	language: 'de', //'de', 'en',
	timeFormat: 24,
	units: "metric",
 
	modules: [
		{   // ------------------------------------------------------------------------ module
			module: "alert"
		}, // end of module
 
		{   // ------------------------------------------------------------------------ module
			module: "updatenotification",
			position: "top_bar"
		}, // end of module
 
		{   // ------------------------------------------------------------------------ module
			module: "clock",
			position: "top_left"
		},
 
		{   // ------------------------------------------------------------------------ module
			module: 'MMM-ModuleScheduler'
		}, // end of module
 
		{   // ------------------------------------------------------------------------ module
			module: 'MMM-Remote-Control'
			// uncomment the following line to show the URL of the remote control on the mirror
			// , position: 'bottom_left'
			// you can hide this module afterwards from the remote control itself
		}, // end of module
 
		{   // ------------------------------------------------------------------------ module
			module: "calendar",
			header: "google Kalender",
			position: "top_left",
			maximumEntries: "8",
			config: {
				calendars: [
					{
						symbol: "calendar-check-o ",
						url: "https://calendar.google.com/calendar/ical/yyyyyyyyyyyyyyyyyyyy%40group.calendar.google.com/private-xxxxxxxxxxxxxxxxxxxxxxxx/basic.ics",
						auth_old: {
							user: 'googleuser',
							pass: 'googlepw',
							method: 'basic'
						}						
				}
				]
			}
		}, // end of module
		{   // ------------------------------------------------------------------------ module
			module: 'MMM-FRITZ-Box-Callmonitor', // https://github.com/paviro/MMM-FRITZ-Box-Callmonitor
			position: 'top_left',	// This can be any of the regions. Best results in left or right regions.
			header: "Recent calls", // This is optional
			config: {
			// See 'Configuration options' for more information.
			// fritzIP: "192.168.178.1"
			username: "fritzuser",
			password: "fritzpw",
			showContactsStatus: "true",
			maximumCallDistance: "1440", // 24h=60*24=1440 in minutes
			maximumCalls: "5",
			vCard: "/home/pi/MagicMirror/modules/MMM-FRITZ-Box-Callmonitor/vCardExport.vcf"
			}
		}, // end of module
 
		{   // ------------------------------------------------------------------------ module
			module: 'MMM-germanwordclock',
			position: 'bottom_left',
		}, // end of module
 
/*		
		// instagramm
		{   // ------------------------------------------------------------------------ module
			module: 'MMM-Instagram',  // https://github.com/kapsolas/MMM-Instagram
			position: 'top_left', 
			config: { 
				// 1) https://www.instagram.com/developer/clients/manage/
				// 2) token is granted here… http://instagram.pixelunion.net/
				// check: https://api.instagram.com/v1/users/self/media/recent?access_token=8355856665.1677ed0.4a012f79b68049ef99e5f0c6ec580054
				access_token: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 
				count: 200, 
				min_timestamp: 0, 
				animationSpeed: 2500, 
				updateInterval: 24000 
			}
		}, // end of module		
*/		
		/*
		{   // ------------------------------------------------------------------------ module
			module: "compliments",
			position: "lower_third"
		}, // end of module
		*/
 
		{   // ------------------------------------------------------------------------ module
			module: "currentweather",
			position: "top_right",
			config: {
				location: "Wiehl",
				locationID: "2809517",  //ID from http://www.openweathermap.org/help/city_list.txt
				appid: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
				updateInterval: '3600000'
			}
		}, // end of module
 
		{   // ------------------------------------------------------------------------ module
			module: "weatherforecast",
			position: "top_right",
			header: "Weather Forecast",
			config: {
				location: "Wiehl",
				locationID: "2809517",  //ID from http://www.openweathermap.org/help/city_list.txt
				appid_old: "YOUR_OPENWEATHER_API_KEY",
				appid: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
			}
		}, // end of module
 
		{   // ------------------------------------------------------------------------ module
			module: 'ping',
			position: 'top_right',
			config: {
				showAlways: true
			}		
		}, // end of module
 
		{   // ------------------------------------------------------------------------ module
			module: 'MMM-iFrame-Ping', // https://github.com/AgP42/MMM-iFrame-Ping
				position: 'top_left',	// This can be any of the regions.
				config: {
					// See 'Configuration options' for more information.
					url: "http://192.168.1.xxx/wordclock/wc.html", //url to display
					/* height:"350px", // "100%", "200px"  370px-370px
					width:"350px", */
					height:"400px", // "100%", "200px" 
					width:"400px", 
					autoRefresh: true, //set to false for video
					updateInterval: 1, //in min. Only if autoRefresh: true
					displayLastUpdate:  false,
					scrolling: "no" 
				}
		}, // end of module
 
 
		{   // ------------------------------------------------------------------------ module
			module: "newsfeed",
			position: "bottom_bar",
			config: {
				feeds: [
					{
						title: "Tagesschau",
						url: "http://www.tagesschau.de/xml/rss2"
					}
				],
				showSourceTitle: true,
				showPublishDate: true
			}
		}, // end of module
 
		{   // ------------------------------------------------------------------------ module
			module: 'MMM-MQTT', // https://github.com/ottopaulsen/MMM-MQTT
			position: 'bottom_right',
			header: 'MQTT 1-Wire',
			config: {
				mqttServer: '192.168.1.xxx',	// OpenHAB
				mqttUser: 'mqttuser1',         	// Leave out for no user
				mqttPassword: 'mqttpw1', 		// Leave out for no password
				subscriptions: [
					/* {
					topic: 'heim/xxxx/uptime', // online, uptime, cmnd
					label: 'uptime:'
					}, */
					{
					topic: 'heim/xxxx/28D51D88040000FA/temperature/current',
					label: 'Terasse',
					decimals: 1,
					suffix: '°C'
					},
					{
					topic: 'heim/xxxx/280C71E705000039/temperature/current',
					label: 'Wintergarten',
					decimals: 1,
					suffix: '°C'
					}
				] // end of subscriptions
			} // end of config
		}, // end of module
 
		{   // ------------------------------------------------------------------------ module
		    // module: 'MMM-MQTT',	// https://github.com/javiergayala/MMM-mqtt incl. send
			module: 'MMM-MQTT', // https://github.com/ottopaulsen/MMM-MQTT incl. JSON
			position: 'bottom_right',
			header: 'MQTT 433',
			config: {
				mqttServer: '192.168.1.yyy', 	// Pandora
				mqttUser: 'mqttuser2',         	// Leave out for no user
				mqttPassword: 'mqttpw2', 	// Leave out for no password
				subscriptions: [
					{
					topic: 'heim/xxxx/cmnd', // online, uptime, cmnd
					label: 'cmnd'
					},
					{
					topic: 'heim/xxxx/cmnd', // online, uptime, cmnd
					label: 'code',
					jsonpointer: '/code'
					},
					{
					topic: 'heim/xxxx/cmnd', // online, uptime, cmnd
					label: 'device',
					jsonpointer: '/device'
					},
					{
					topic: 'heim/xxxx/cmnd', // online, uptime, cmnd
					label: 'up/down',
					jsonpointer: '/state'
					},
					{
					topic: 'heim/xxxx/state', // online, uptime, cmnd
					label: 'success'
					}
				] // end of subscriptions
			} // end of config
		}, // end of module		
 
 
		{   // ------------------------------------------------------------------------ module
			module: "MMM-RTSPStream", // https://github.com/shbatm/MMM-RTSPStream
			position: "middle_center", // http://192.168.1.xxx:9999/config.html
			config: {
				autoStart: true,
				rotateStreams: false,
				rotateStreamTimeout: 10,
				moduleWidth: 354, // 354  708
				moduleHeight: 240, // 240  480
				localPlayer: 'omxplayer',
				remotePlayer: 'none',
				showSnapWhenPaused: true, 
				remoteSnaps: true,
				stream1: {
					name: 'Haustür',
					url: 'rtsp://camuser:campw@192.168.1.xxx:554/videoSub',
					url_bunny: 'rtsp://184.72.239.149/vod/mp4:BigBuckBunny_175k.mov',
					frameRate: 'undefined',
					hdUrl: '',
					snapshotUrl: 'http://192.168.1.xxx:88/cgi-bin/CGIProxy.fcgi?cmd=snapPicture2&usr=camuser&pwd=campw',
					snapshotType: 'url',
					snapshotRefresh: 3,
					width: undefined,
					height: undefined,
				}, // end of stream
			} // end of config		
		}, // end of module	
 
	] // end of modules
 
}; // end of config
 
/*************** DO NOT EDIT THE LINE BELOW ***************/
if (typeof module !== "undefined") {module.exports = config;}