Ueberschalter: Unterschied zwischen den Versionen

Aus C3MAWiki
(→‎Skript: Updated with more debug code and inserted "Werkstatt mode")
 
(9 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
{{aktives Projekt|Kontakt=Ollo}}
{{aktives Projekt|Kontakt=Ollo}}
[[Datei:SchaltschrankUeberschalterV2.jpg|400px|right|Schaltschrank Ueberschalter V2.0]]


= Publikationen =
= Publikationen =
* [[Datei:2014-02-28_Praesi_Raumbeleuchtung.pdf]]
 
Projekt auf '''Github''' [https://github.com/C3MA/uberschalter Projekt auf Github]
 
Präsentation beim C3MA: [[Datei:2014-02-28_Praesi_Raumbeleuchtung.pdf]]


= Server =
= Server =
== Hardware ==
== Hardware ==
* Raspberry Pi [http://www.gtkdb.de/index_36_2451.html seriell stumm geschalten]
* Ethernet
* ioBoard [https://github.com/C3MA/uberschalter Projekt auf Github]
* RS485 USB-Dongle


Das ioBoard wird über das UART des Raspberry Pis angesprochen.
Die Kommunikation zum Raspberry erfolgt über Ethernet, es werden keine weiteren Schnittstellen benötigt.
Die Kommunikation zum Raspberry erfolgt über Ethernet, es werden keine weiteren Schnittstellen benötigt.


== Software ==
== Software ==
* raspbian (wheezy)
* raspbian (wheezy)
** ser2net
** python
** lighttpd (optional für Webclient)
** lighttpd (optional für Webclient)
*** Webserver-Projekt [https://github.com/C3MA/uberschalter Unterordner web]
*** Webserver-Projekt [https://github.com/C3MA/uberschalter Unterordner web]
== Konfiguration ==
In der Konfigurationsdatei /etc/ser2net.conf von '''ser2net''' aktiviert man folgende Konfiguration. Alle weiteren können auskommentiert werden:
2001:raw:120:/dev/ttyAMA0:9600 NONE 1STOPBIT 8DATABITS -XONXOFF -LOCAL -RTSCTS


== Webserver konfigurieren ==
== Webserver konfigurieren ==
Zeile 81: Zeile 79:
* https://github.com/C3MA/and-MqttLight
* https://github.com/C3MA/and-MqttLight
** [[Datei:MqttLight.zip]]
** [[Datei:MqttLight.zip]]
== Web ==
Auf dem RaspberryPi läuft auch Webserver um die Lampen zu steuern:
(Zu erreichen im Raum-Netzwerk unter ''lampi'' oder ''10.23.42.140''.)
<gallery>
Datei:LampPiWeb.png|Lamp Webinterface
</gallery>


= Lampenpositionen =
= Lampenpositionen =
Zeile 93: Zeile 84:
Datei:LampenPlan.jpg|Lampenpositionen mit deren Identifikationsnummer
Datei:LampenPlan.jpg|Lampenpositionen mit deren Identifikationsnummer
</gallery>
</gallery>
Update der Lampenpositionen notwendig (wenn alle Lampen einzeln angesprochen werden können)


= Mqtt =
= Mqtt =
Zeile 113: Zeile 105:
</pre>
</pre>
Linux Befehl:
Linux Befehl:
  $ mosquitto_sub -v -h 10.23.42.31 -t "/room/light/#"
  $ mosquitto_sub -v -h 10.23.42.10 -t "/room/light/#"


Eine Lampe kann mit folgenden Schema geschalten werden: '''/room/light/<id>/command (on|off)'''.
Eine Lampe kann mit folgenden Schema geschalten werden: '''/room/light/<id>/command (on|off)'''.
Zeile 119: Zeile 111:
Unter Linux wurde das wie folgt getestet:
Unter Linux wurde das wie folgt getestet:
<pre>
<pre>
$ mosquitto_pub -h 10.23.42.31 -t "/room/light/3/command" -m "off"
$ mosquitto_pub -h 10.23.42.10 -t "/room/light/3/command" -m "off"
$ mosquitto_pub -h 10.23.42.31 -t "/room/light/3/command" -m "on"
$ mosquitto_pub -h 10.23.42.10 -t "/room/light/3/command" -m "on"
</pre>
 
== Skript ==
<pre>
#!/usr/bin/python
import mosquitto, os, socket, time
from threading import Thread
from time import gmtime, strftime
 
#File: /usr/local/sbin/light2mqtt.py
 
TCP_IP = '127.0.0.1'
TCP_PORT = 2001
BUFFER_SIZE = 1024
 
# Prometheus
#mqttBroker="10.23.42.31"
# BigBrother
mqttBroker="10.23.42.10"
 
mypid = os.getpid()
 
 
client = mosquitto.Mosquitto("RoomLights"+str(mypid))
 
# Zeit in Sekunden, in der die Lamen nicht geschaltet werden koennen (Schutz der Lampen und relais)
LAMPSLEEPTIME=5
 
pollerState = True
oldStates = {}
t = None
lampSleepProtection = {}
 
def processState(ls):
lightnr=1
global oldStates
global lampSleepProtection
 
werkstattState = "off"
for light in ls:
lightState = "on" if int(light) == 1 else "off"
if str(lightnr) in oldStates and lightState != oldStates[str(lightnr)]:
client.publish("/room/light/%s/state" % lightnr, lightState, 0, True)
print("%s Updated %s to %s" % (strftime("%Y-%m-%d %H:%M:%S", gmtime()), lightnr, lightState) )
# Zeit festlegen, solange die Lampe nicht mehr geschalten werden darf
lampSleepProtection[light] = int(time.time()) + LAMPSLEEPTIME
 
# Mindestens eine Lampe in der Werkstatt muss an sein
if lightnr == 5 or lightnr == 6:
werkstattState = "on" if lightState == "on" else werkstattState
lightnr+=1
 
# Aenderungen in der Werkstatt kommunizieren:
if 'w' in oldStates and werkstattState != oldStates['w']:
client.publish("/room/light/w/state", werkstattState, 0, True)
print("%s Updated Werkstatt state to %s" % (strftime("%Y-%m-%d %H:%M:%S", gmtime()), werkstattState) )
 
# Light ist das licht 1-6
# State ist h oder l
 
def switchLight(lights, state):
global lampSleepProtection
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
for l in lights:
if (l in lampSleepProtection and int(time.time()) < int(lampSleepProtection[l])):
print("%s Mqtt Command blocked for Lamp %s for %s seconds" % (strftime("%Y-%m-%d %H:%M:%S", gmtime()), l, str(lampSleepProtection[l] - int(time.time()) ) ))
else:
# Zeit festlegen, solange die Lampe nicht mehr geschalten werden darf
lampSleepProtection[l] = int(time.time()) + LAMPSLEEPTIME
s.send("ollpew%s%s" % (l, state))
time.sleep(0.2)
 
data = s.recv(BUFFER_SIZE)
s.close()
 
data = data.replace("\r", "").split("\n")
if len(data) > 3:
lightState = data[3].split(" ")[1]
print("%s Proccess via Mqtt for Lamp%s to %s" % (strftime("%Y-%m-%d %H:%M:%S", gmtime()), str(lights), state) )
processState(lightState)
else:
print("%s No answer from uC for Lamp%s to %s; only %s" % (strftime("%Y-%m-%d %H:%M:%S", gmtime()), str(lights), state, str(data)) )
 
 
def getStates():
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((TCP_IP, TCP_PORT))
 
        s.send("ollpera")
 
        time.sleep(0.2)
 
        data = s.recv(BUFFER_SIZE)
        s.close()
       
data = data.replace("\r", "").split("\n")
if len(data) > 2:
lightState = data[2].split(" ")[1]
print("%s Process by background thread" % strftime("%Y-%m-%d %H:%M:%S", gmtime()))
processState(lightState)
else:
print("%s No answer from uC getting its status; only %s" % (strftime("%Y-%m-%d %H:%M:%S", gmtime()), str(data)) )
 
def on_connect(rc):
    #print("Connected with result code "+str(rc))
    client.subscribe("/room/light/+/command")
    client.subscribe("/room/light/+/state")
    pollerState = True
 
def on_message(userdata, msg):
global oldStates
topic = msg.topic.strip("/").split("/")
 
lightNr = str(topic[2])
message = str(msg.payload)
 
if (topic[3] == "command"):
if (lightNr == "w" or int(lightNr) >= 1 and int(lightNr) <= 6) and message in ["on", "off"]:
lightState = "l" if message == "off" else "h"
# Lichter in Array gruppieren fuer die Werkstatt
if (lightNr == "w"):
lights = [5, 6]
else: # Sonst array mit einem Licht erstellen
lights = [ int(lightNr) ]
switchLight(lights, lightState)
elif (topic[3] == "state"):
# Nicht die Werkstatt aktualieren, das passiwert in getStates()
try:
if (lightNr == "w" or int(lightNr) >= 1 and int(lightNr) <= 6):
oldStates[lightNr] = message
except ValueError:
pass
 
def on_disconnect(userdata):
pollerState = False
#print "Disconnect"
 
def statePoller():
while True:
if pollerState:
getStates()
# Update the button only all half minutes
time.sleep(30)
       
 
 
client.on_connect = on_connect
client.on_message = on_message
client.on_disconnect = on_disconnect
 
client.will_set('/room/light/daemon/state', 'offline', 0, True)
 
t = Thread(target=statePoller)
t.start()
 
while True:
# print "Connect..."
client.connect(mqttBroker, 1883, 60, True)
client.publish('/room/light/daemon/state', 'online', 0, True)
while client.loop() == 0:
pass
# print "Reconnecting..."
time.sleep(60)
 
 
</pre>
</pre>


Autostart im Raspberry:
Und hier das Sammel-Topic für die Werkstatt:
Folgende Zeile in '''/etc/rc.local''' einfügen: (vor dem ''exit 0'' wenn vorhanden)
<pre>
<pre>
# Start the monster deamon to rule the world
$ mosquitto_pub -h 10.23.42.10 -t "/room/light/w/command" -m "off"
/usr/bin/python /usr/local/sbin/light2mqtt.py &
$ mosquitto_pub -h 10.23.42.10 -t "/room/light/w/command" -m "on"
</pre>
</pre>

Aktuelle Version vom 27. Januar 2019, 20:20 Uhr

Dies ist ein Projekt, an dem momentan aktiv gearbeitet wird. Wenn du Fragen hast oder mitarbeiten möchtest, wende dich an Ollo.


Schaltschrank Ueberschalter V2.0
Schaltschrank Ueberschalter V2.0

Publikationen

Projekt auf Github Projekt auf Github

Präsentation beim C3MA: Datei:2014-02-28 Praesi Raumbeleuchtung.pdf

Server

Hardware

  • Ethernet
  • RS485 USB-Dongle

Die Kommunikation zum Raspberry erfolgt über Ethernet, es werden keine weiteren Schnittstellen benötigt.

Software

  • raspbian (wheezy)
    • python
    • lighttpd (optional für Webclient)

Webserver konfigurieren

$ cd /var/
$ sudo chown pi:pi www/
$ cd cd /var/www/
$ git clone https://github.com/C3MA/uberschalter
$ cd uberschalter/web/
$ make

Aktualiseren der lighttpd Konfiguration zu folgender (Muss ggf. erst installiert werden):

server.modules = (
	"mod_cgi",
	"mod_access",
	"mod_alias",
	"mod_compress",
 	"mod_redirect",
#       "mod_rewrite",
)

#server.document-root        = "/var/www"
server.document-root        = "/var/www/uberschalter/web/www"
server.upload-dirs          = ( "/var/cache/lighttpd/uploads" )
server.errorlog             = "/var/log/lighttpd/error.log"
server.pid-file             = "/var/run/lighttpd.pid"
server.username             = "www-data"
server.groupname            = "www-data"
server.port                 = 80


index-file.names            = ( "index.php", "index.html", "index.lighttpd.html" )
url.access-deny             = ( "~", ".inc" )
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )

compress.cache-dir          = "/var/cache/lighttpd/compress/"
compress.filetype           = ( "application/javascript", "text/css", "text/html", "text/plain" )

# default listening port for IPv6 falls back to the IPv4 port
include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
include_shell "/usr/share/lighttpd/create-mime.assign.pl"
include_shell "/usr/share/lighttpd/include-conf-enabled.pl"

$HTTP["url"] =~ "/cgi-bin/" {
        cgi.assign = ( "" => "" )
}

cgi.assign      = (
        ".cgi"  => ""
)

Client

Android

Lampenpositionen

Update der Lampenpositionen notwendig (wenn alle Lampen einzeln angesprochen werden können)

Mqtt

Doku

Folgende Stati werden in MQTT geschickt:

/room/light/3/command off
/room/light/1/state on
/room/light/2/state on
/room/light/3/state off
/room/light/4/state on
/room/light/5/state on
/room/light/6/state on
/room/light/7/state on
/room/light/8/state on
/room/light/3/command off
/room/light/3/command off
/room/light/3/command on
/room/light/3/state on

Linux Befehl:

$ mosquitto_sub -v -h 10.23.42.10 -t "/room/light/#"

Eine Lampe kann mit folgenden Schema geschalten werden: /room/light/<id>/command (on|off).

Unter Linux wurde das wie folgt getestet:

$ mosquitto_pub -h 10.23.42.10 -t "/room/light/3/command" -m "off"
$ mosquitto_pub -h 10.23.42.10 -t "/room/light/3/command" -m "on"

Und hier das Sammel-Topic für die Werkstatt:

$ mosquitto_pub -h 10.23.42.10 -t "/room/light/w/command" -m "off"
$ mosquitto_pub -h 10.23.42.10 -t "/room/light/w/command" -m "on"