Ein Bekannter hatte neulich das Problem dass sein (Windows) Computer sich manchmal komplett aufhängt. Die einzige Möglichkeit ihn wieder zum Leben zu erwecken ist ihn hart auszuschalten. Das passiert meistens über Nacht und ist besonders ärgerlich wenn er den Computer übers Wochenende per Remote nutzen will da er dann nicht zu erreichen ist. Die Lösung? Eine Steckdose welche über WLAN verbunden ist und den Strom zum Computer einfach kurz unterbricht. Hart aber effektiv!
(Damit der Computer danach wieder hochfährt kann man entweder im BIOS einstellen dass er bei Power Failure restartet oder aber man weckt ihn per Wake-On-LAN auf)
Sowas selber zu bauen ist natürlich einfach, aber -da 220 Volt- eventuell keine gute Idee. Eine fertige Steckdose die man leicht umbauen kann wäre einfacher und man könnte sich sicher sein die gesetzlichen Bestimmungen einzuhalten.
Kurze Recherche führte einen Artikel der ct 02/2018 zu Tage der genau das beschreibt: Eine Steckdose mit dem Namen „Sonoff S20“ mit einem integrierten ESP8266 Wifi-Chip den man problemlos mit eigener Software versorgen kann. Der ESP8266 ist bekanntlich der Bastler-Chip für Wlan schlechthin, denn bei nur ein paar Euro Kosten hat man einen fertigen Mikrocontroller mit Wlan on Board.
Details zur Steckdose findet man im Wiki des Herstellers ITEAD. Dieser ist sich wohl durchaus der Tatsache bewusst dass seine Steckdosen oft mit eigener Software ausgestattet werden und scheint sich daran nicht zu stören. Hier gehts zum Wiki: „ITEAD S20 Smart Socket„.
Dort fndet sich auch ein Schaltplan, sowie CE, ROHS und FCC Zertifikat!
Der Hersteller des ESP8266 (Espressif Systems) hilft der Maker-Community auch und mittlerweile kann man den Chip mit der Arduino IDE nutzen. Oder aber man kann verschiedene andere Sachen auf ihm installieren, z.B. Javascript (Espruino) oder Python (Micropython).
(es gibt hier auch fertige Heimautomationssysteme, aber die waren mir dann doch zu viel!)
Da ich ein Fan von Python bin sollte es auf meiner Steckdose Python sein. Hier kam mir natürlich sehr gelegen dass man die Steckdosen relativ günstig (~ 15 €) sogar direkt in Deutschland bekommt. Mit CE und ROHS Zertifikat! Zu diesem Preis selber bauen? Unmöglich!
Kurzum, erstmal die Steckdose aufgemacht und einen Header an die schon vorbereiteten Pins dran gelötet. Wenn man die Steckdose oben hat so sind die Pins:
– GND
– TX
– RX
– VCC (3.3 V)
Hier merkt man schon die erste Schwierigkeit: Der ESP8266 möchte mit 3.3 Volt versorgt werden. Mein USB-to-seriell Kabel hat zwar 3.3V Signalpegel, gibt aber USB 5V raus. Hier musste also ein Labornetzteil herhalten.
(Theoretisch kann man sich das sparen wenn man die Steckdose einfach programmiert während sie eingesteckt ist. Galvanisch getrennt von den 220V erzeugt sie ihre eigenen 3.3V. Ratsam ist das aber natürlich nicht und es soll hier nicht empfohlen werden!)
Nachdem die Steckdose verbunden ist kann man mit folgenden Kommandos ein frisch runtergeladenes Micropython für den ESP8266 installieren:
apt-get install python3-pip pip install esptool esptool.py --port /dev/ttyUSB0 erase_flash esptool.py --port /dev/ttyUSB0 write_flash -fs 1MB -fm dout 0x0 /home/xxx/esp8266-20171101-v1.9.3.bin
ACHTUNG: Der Parameter ‚-fm dout‘ war bei mir nötig. Sonst klappte zwar das flashen von Micropython aber die serielle Verbindung zeigte nichts sinnvolles an weil der Programmcode nicht richtig geflasht war!
Zum bequemen übertragen von Dateien (Programme die micropython automatisch beim boot startet müssen ‚main.py‘ heißen) installieren wir ‚rshell‘:
# rshell installieren pip3 install rshell # rshell starten rshell --buffer-size=30 -p /dev/ttyUSB0 # main.py übertragen cp main.py /pyboard # Die Kommandokonsole (REPL) von Micropython auf dem Chip aufrufen repl (Beenden mit Strg+X)
So, und das einzige was nun noch fehlt ist der -wirklich einfache- Programmcode meines Webservers. Leider gibt es in Micropython vom ESP8266 keinen Watchdog um sicherzugehen dass bei einem hängenden Programmcode die Steckdose resettet wird, deshalb ein großer Try-Block der quasi jede Exception fängt und einen Reset auslöst. Bis auf den Keyboard-Reset. Wenn man den abfängt kommt man nicht mehr auf die Micropython-REPL und auch rshell geht nicht mehr!
Wenn übrigens Strom an der Steckdose durchgegeben wird und der ESP8266 resettet bleibt das Relais trotzdem weiterhin ausgelöst und die Steckdose unterbricht den Strom zum Verbraucher nicht!
Die Steckdose hat das Relais zum Strom einschalten an Pin 12 angebunden (Active HIGH) und eine grüne LED an Pin 13 (Active LOW). Die blaue LED ist fest verdrahtet und leuchtet immer wenn der Strom eingeschalten ist.
Simepl mit dem Browser auf die IP-Adresse die man im Programmcode vergeben hat verbinden und der Rest ist selbsterklärend!
# Button is: PIN 0 -> INPUT, Active LOW # Relais is: PIN 12 -> OUTPUT, Active High # Green LED is: PIN 13 -> OUTPUT, Active LOW # Blue LED is automaticly active when Relais ist active import gc import os import time import usocket import ustruct import network import machine # Reset-IRQ-Handler (called on btnpin) def resetme(pin): print('Button reset!') machine.reset() # Make sure the REPL is available via UART (for debugging purposes!) # Already done in boot.py! #uart = machine.UART(0, 115200) #os.dupterm(uart) try: print('Startup!') # Configuration Wifi_SSID = "xxx" Wifi_Pass = "yyy" myip = "192.168.123.456" mysubnet = "255.255.255.0" myrouter = "192.168.123.1" mydns = "192.168.123.1" # Set Pins, acivate Relais (value = 1 => active) btnpin = machine.Pin(0, machine.Pin.IN) relaispin = machine.Pin(12, machine.Pin.OUT, value = 1) # Relais on greenledpin = machine.Pin(13, machine.Pin.OUT, value = 1) # green LED off print('Try to connect to WiFi: ' + Wifi_SSID) # Prepare reset on btnpin btnpin.irq(trigger=machine.Pin.IRQ_FALLING, handler=resetme) # Connect to WiFi wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.ifconfig((myip, mysubnet, myrouter, mydns)) wlan.connect(Wifi_SSID, Wifi_Pass) while not wlan.isconnected(): pass print('WiFi connected:') print('IP-Address: ' + str(wlan.ifconfig()[0])) print('Subnet Mask: ' + str(wlan.ifconfig()[1])) print('Gateway: ' + str(wlan.ifconfig()[2])) print('DNS: ' + str(wlan.ifconfig()[3])) print() # Start Webserver s = usocket.socket() ai = usocket.getaddrinfo("0.0.0.0", 80) print("Bind address info:", ai) addr = ai[0][-1] s.setsockopt(usocket.SOL_SOCKET, usocket.SO_REUSEADDR, 1) s.bind(addr) s.listen(5) print("Webserver ready.") # Endless-Loop for Webserver hosting Website outputheader = 'HTTP/1.0 200 OK\r\n\r\n' while True: res = s.accept() client_sock = res[0] client_addr = res[1] client_port = client_addr[2:4] client_ip = client_addr[4:] print("Client IP:", str(client_addr)) print("Client Port:", str(client_port)) print() client_stream = client_sock print("Request:") req = client_stream.readline() print(req) output = '<html><head><title>Network-Outlet</title></head><body>' if req[:7] == b'GET /on': print('--> Switching Relais ON') relaispin.value(1) greenledpin.value(1) output += '<p>Switched Relais ON</p><hr>' elif req[:8] == b'GET /off': print('--> Switching Relais OFF') relaispin.value(0) greenledpin.value(0) output += '<p>Switched Relais OFF</p><hr>' elif req[:10] == b'GET /cycle': print('--> Switching Relais OFF') relaispin.value(0) greenledpin.value(0) output += '<p>Switched Relais OFF</p>' print('--> Switching Relais OFF') time.sleep(2) relaispin.value(1) greenledpin.value(1) output += '<p>Switched Relais ON</p><hr>' elif req[:11] == b'GET /status': relaisstatus = 'undefined' ledstatus = 'undefined' buttonstatus = 'undefined' # RELAIS if relaispin.value() == 0: relaisstatus = 'OFF' if relaispin.value() == 1: relaisstatus = 'ON' # LED if greenledpin.value() == 0: ledstatus = 'ON' if greenledpin.value() == 1: ledstatus = 'OFF' # BUTTON if btnpin.value() == 0: buttonstatus = 'PRESSED' if btnpin.value() == 1: buttonstatus = 'NOT PRESSED' print('-> relaispin: ' + str(relaispin.value())) print('-> greenledpin: ' + str(greenledpin.value())) print('-> btnpin: ' + str(btnpin.value())) print('--> Relais Status is: ' + relaisstatus) print('--> Green LED Status is: ' + ledstatus) print('--> Button Status is: ' + buttonstatus) print('--> Free Mem is: ' + str(gc.mem_free())) print('--> Uptime in ms: ' + str(time.ticks_ms())) output += '<p>Relais Status is: ' + relaisstatus + '</p>' output += '<p>Green LED Status is: ' + ledstatus + '</p>' output += '<p>Button Status is: ' + buttonstatus + '</p>' output += '<p>Free Mem is: ' + str(gc.mem_free()) + '</p>' output += '<p>Uptime in ms: ' + str(time.ticks_ms()) + '</p><hr>' output += '<p>Usage:</p><p>Switch on: <a href="/on">/on</a></p><p>Switch off: <a href="/off">/off</a></p><p>Power cycle: <a href="/cycle">/cycle</a></p><p>Status: <a href="/status">/status</a></p></body></html>' while True: h = client_stream.readline() if h == b"" or h == b"\r\n": break print(h) print('Answering: ') print('**************************************') print(outputheader + output) print('**************************************') client_stream.write(outputheader + output) client_stream.close() gc.collect() print('Free mem: ' + str(gc.mem_free())) print() except KeyboardInterrupt: print('Keyboard Interrupt!') except: print('Exception happend! Rebooting!') machine.reset()
PS: Der Uptime Zähler (in ms) sollte nach ca. 49 Tagen überlaufen und wieder bei 0 anfangen da es ein unsigned int32 ist. So meine Berechnungen jedenfalls, da die Steckdose noch nicht so lange läuft kann ichs noch nicht bestätigen 🙂
Schreibe einen Kommentar