Manchmal hat man da, wo der Pi seinen Dienst als Webcam oder als Home Automation Server versieht, keinen Festnetzanschluß. Die Lösung ist ein Router, an den man einen UMTS Internetstick anschließt oder ein fertiger UMTS (LTE ist natürlich noch besser) Router.
Leider verhält es sich so, dass diese Konfiguration immer mal wieder menschlicher Interaktion bedarf: Unter Umständen ist das Mobilfunknetz so stark überlastet, dass der Router, bzw. der Internet Stick daran sich einfach nicht verbinden will. Nach zu vielen Fehlversuchen streikt der Router dann – zumindest der von mir verwendete TP-Link Mobilfunk Router TL-MR3420. Dann hilft nur ein physikalischer Reset des Routers. Blöd, wenn man dann nicht vor Ort ist, sondern hunderte Kilometer entfernt.
Man könnte den Router ganz einfach mit einer Zeitschaltuhr irgendwann (nachts) aus- und wieder einschalten. Im schlimmsten Fall wäre der Pi dann 24 Stunden offline.
Viel eleganter ist die Lösung mittels Fernschalt-Steckdosen und einem 433MHz Sender am Pi.
Wie man 433MHz Schaltsteckdosen mit dem Pi ansteuert, ist hier beschrieben.
Dann kommt der von mir "entwickelte" Python Code zum Überwachen und Steuern des Routers. Ich bin leider kein Python Experte, weshalb der Code für Experten wahrscheinlich etwas schlampig aussieht. Für Anregungen wäre ich sehr dankbar!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
#!/usr/bin/python #coding=UTF-8 #----------------- # This program tries to establish a connection to a given Internet site. # In case, a connection cannot established after several retries, # a command is sent to a 433MHz switch, to turn off the router and start it after # a minute or so. This program should be called at regular intervals (ca. 15 minutes) # by use of a crontab statement #----------------- import urllib2 import time from elropi import RemoteSwitch import logging def internet_on(): try: response=urllib2.urlopen('http://www.google.it',timeout=urltimeout) return True except urllib2.URLError as err: pass return False # setting constants # change device number according to your requirements deviceno=1 # Change the key[] variable below according to the dipswitches on your Elro receivers. default_key = [1,1,0,1,1] # change the GPIO pin according to your wiring default_pin =7 # set parameters for class elropi.py device = RemoteSwitch(device=deviceno,key=default_key,pin=default_pin) # set timeout for URL check [s] urltimeout=15 # set wait inbetween retries [s] retrywait=15 # set wait after shutdown [s] shutdownwait=60 # set number of retries retries=3 # Logging logging.basicConfig(filename='/var/log/checkinet.log',level=logging.WARNING,format='%(asctime)s %(message)s') # Check whether Internet is available inetstatus=internet_on() attempt=0 while not inetstatus: attempt=attempt + 1 errmsg="Attempt number " + str(attempt) + ": connect failed, retrying" logging.warning(errmsg) if attempt >= retries: device.switchOff() logging.warning("router seems offline, going through power cycle") time.sleep(shutdownwait) device.switchOn() logging.warning("router is booting") break #wait for some seconds before next try and return to top of while loop time.sleep(retrywait) inetstatus=internet_on() if inetstatus: logging.debug("router online") #End of Connectivity check |
Den oben abgebildeten Code in den Editor pasten und als checkinet.py
im Verzeichnis /home/pi/433mhz
abspeichern.
Was passiert da?
Zuerst einmal werden die benötigten Libraries inklusive der Klasse "RemoteSwitch" aus dem in diesem Beitrag besorgten Programm elropi.py
geladen.
Die Funktion internet_on
funkt eine frei wählbare Internet Adresse an. Sinnvollerweise eine, welche eine schnelle Response zeigt. Den Timeoutwert in Sekunden kann man frei wählen. Ist er zu kurz, wird der Router bei schlechten Empfangsbedingungen entsprechend öfter zurückgesetzt.
Dann werden alle Konstanten gesetzt, inklusive der Konstanten für RemoteSwitch
. Die im 433MHz Beitrag vorgenommene Einstellung des GPIO Pins und der Systemadresse der Funkschaltdose in elropi.py
keinen Einfluss auf die Einstellungen, die du hier in checkinet.py
vornimmst. Deshalb müssen diese Parameter hier noch einmal eingegeben werden.
Zusätzlich wird noch die Python Logging Komponente angesprochen, die es dir erlaubt, die Funktionsweise und ggf. stattgefundene Resets zu überprüfen. Print
Statements kannst du natürlich auch einbauen, aber die sind nur sichtbar, wenn man das Programm direkt aufruft. Wir werden das Programm ja automatisch und im Hintergrund laufen lassen. Wer mag, kann anstatt level=logging.WARNING
auch level=logging.DEBUG
schreiben; dann wird jedesmal, wenn das Programm läuft eine Zeile "router online" ins Protokoll geschrieben.
Die angegebene Internet Adresse wird angefunkt. Ist alles okay, wird das Programm beendet. Falls nicht, wird die While
Schleife x-mal bis zu einem einstellbaren Maximalwert durchlaufen, zwischen den Versuchen wird immer ein bisschen gewartet. Nach dem x-ten Fehlversuch wird der Schaltdose ein Abschalt-Kommando geschickt. Nach einer einstellbaren Wartezeit wird die Dose wieder eingeschaltet und der Router bootet – natürlich nur, wenn er auch tatsächlich an der Schaltdose hängt 🙂 . Wenn alles klappt, hat sich der Router nach ein paar Minuten mit dem Internet verbunden. Falls nicht, geht beim nächsten Start das Spiel wieder von vorne los.
Regelmäßiger Check? In die Crontab damit!
So, das wars fast schon. Damit die Internetverbindung regelmäßig getestet wird gehen wir wie folgt vor:
1 |
sudo crontab -e |
Die Crontab wird geladen. Ans untere Ende sollten wir folgenden Befehl schreiben:
2,12,22,32,42,52 * * * * python /home/pi/433mhz/checkinet.py
Das bewirkt, dass das Programm alle 10 Minuten zur 2., 12., 22., 32., 42 und 52. Minute ausgeführt wird. Das mache ich deshalb, weil meine Webcam zu jeder vollen und halben Stunde ein Foto macht und dann etwas Zeit braucht, die Bilder in meinen Webspace hochzuladen. Während dieser Zeit ist der Kanal dicht und es könnte zu einem ungewollten Timeout und Reset kommen – meine Bandbreite ist manchmal echt jämmerlich.
Es ginge natürlich auch
*/10 * * * * python /home/pi/433mhz/checkinet.py
dann würde der Check alle 10 Minuten zur vollen zehnten Minute stattfinden.
Wie oft ihr das Programm laufen lasst, bleibt euch überlassen. Allerdings sollte zwischen den Aufrufen genügend Zeit bleiben, dass sich der Router bzw. Internet Stick wieder mit dem Internet verbindet. Sonst gibt's eine Endlosschleife.
Stellt man die Crontab mit sudo crontab
ein, wird sie immer als Superuser ausgeführt, ihr braucht deshalb den Prefix sudo
nicht. python
bräuchte man eigentlich auch nicht, wenn man das in diesem Beitrag Beschriebene beachtet. Der Einfachheit halber und wohl eher aus Gewohnheit lasse ich das trotzdem meist drin, da ich anfänglich Schwierigkeiten mit dem impliziten Aufruf des Pythoninterpreters hatte.
Zusätzliche Absicherung und Mail Benachrichtigung
Warum auch immer, manchmal will sich das Edimax USB Dongle (ansonsten wirklich hervorragend) nicht mehr mit dem frisch gestarteten Router verbinden. Das führt dann auch zu einer Endlosschleife, da checkinet.py nix checkt bzw. keine Verbindung zum Router zustande kommt. Was tun? Ganz einfach: den Raspberry Pi nach erfolgten Reset und ein paar Gedenkminuten durchstarten.
Dazu braucht es noch die os
Library und den Befehl os.system("sudo reboot")
an geeigneter Stelle.
Hier mein ganzes Programm, was als zusätzliches Komfortfeature noch ein Email an mich schickt, wenn der Router resetted wurde. Die Mailfunktion habe ich von Trevor Appleton's Website.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
#!/usr/bin/python #coding=UTF-8 #----------------- # German documentation can be found at www.rustimation.eu # This program tries to establish a connection to a given Internet site. # In case, a connection cannot be established after several retries, # a command is sent to a 433MHz switch to turn off the router and start it after # a minute or so. This program should be called at regular intervals (ca. 15 minutes) # by use of a crontab statement. # For additional security, the Pi reboots after resetting the router (it has happened # that the WiFi connection between the Pi an the router crashed, resulting in an endless # loop of resetting and restarting the router without any effect). # A previous reset is detected and an email is sent. # Due to GPIO functionality this program must be run as root (sudo) #----------------- import urllib2 import time from elropi import RemoteSwitch import logging import os import smtplib def internet_on(): try: response=urllib2.urlopen('http://www.google.it',timeout=urltimeout) return True except urllib2.URLError as err: pass return False # Logging - logfile must be present logging.basicConfig(filename='/var/log/checkinet.log',level=logging.WARNING,format='%(asctime)s %(message)s') #### setting constants workdir="/home/pi/433mhz/" # change device number according to your requirements deviceno=1 # Change the key[] variable below according to the dipswitches on your Elro receivers. default_key = [1,0,1,0,1] # change the GPIO pin according to your wiring default_pin =7 # set parameters for class elropi.py device = RemoteSwitch(device=deviceno,key=default_key,pin=default_pin) # set timeout for URL check [s] urltimeout=15 # set wait inbetween retries [s] retrywait=30 # set wait after shutdown [s] shutdownwait=5 # set number of retries retries=5 # get local time as string lt = time.localtime() jahr, monat, tag, stunde, minute, sekunde = lt[0:6] acttime="%04i%02i%02i%02i%02i%02i" % (jahr, monat, tag, stunde, minute, sekunde) # mail params - # see also:http://trevorappleton.blogspot.co.uk/2014/11/sending-email-using-python.html SMTP_SERVER = 'smtp.gmail.com' SMTP_PORT = 587 GMAIL_USERNAME = 'yourGmailAddress@gmail.com' #for these purposes, I suggest a special account instead of your regular one. GMAIL_PASSWORD = 'PaSsWoRD' #CAUTION: This is stored in plain text! recipient = 'ReceiversAddress@anywhere.com' subject = 'Router Reboot' headers = ["From: " + GMAIL_USERNAME, "Subject: " + subject, "To: " + recipient, "MIME-Version: 1.0", "Content-Type: text/html"] headers = "rn".join(headers) # check for previous reset - if yes, send mail inetstatus=internet_on() # necessary since sending mail will only work, if inernet is available if inetstatus: try: checkfile=open(workdir+"reset.txt", "r") # if file (=reset) exists then go on resettime=checkfile.read() checkfile.close os.remove(workdir+"reset.txt") logging.warning("previous reset detected") emailText = 'A router reset occurred at ' + resettime emailText = "" + emailText + "" session = smtplib.SMTP(SMTP_SERVER, SMTP_PORT) session.ehlo() session.starttls() session.ehlo session.login(GMAIL_USERNAME, GMAIL_PASSWORD) session.sendmail(GMAIL_USERNAME, recipient, headers + "rnrn" + emailText) session.quit() except IOError: logging.debug("no previous reset") # Check whether Internet is available attempt=0 while not inetstatus: attempt=attempt + 1 errmsg="Attempt number " + str(attempt) + ": connect failed, retrying" logging.warning(errmsg) if attempt >= retries: device.switchOff() logging.warning("router seems offline, rebooting router") time.sleep(shutdownwait) device.switchOn() logging.warning("router is booting") checkfile=open(workdir+"reset.txt","w") checkfile.write(acttime) checkfile.close() time.sleep(60) # long enough for router to bring up WiFi os.system("sudo reboot") # reboot to add security break #wait for some seconds before next try and return to top of while loop time.sleep(retrywait) inetstatus=internet_on() if inetstatus: logging.debug("router online") #End of Connectivity check |