| |
| |
| Inhalt: |
| |
| Motivation bzw. Hintergrund |
| Einstieg in die Scriptsprache |
| Sensordaten einsammeln und in eine Datenbank schreiben |
| Lego Roboter mit PyBricks |
| |
| |
| Für mich hat Python inzwischen den Stellenwert angenommen, den zuvor Perl als Scriptsprache inne hatte. Ich verwende die Scriptsprache |
| nzwischen für nahezu jegliche Automatismen, CGI und fü alles, was sich sonst im Rahmen vorhandener "Alltagsprobleme" ergibt, |
| für die ich eine programmatische Lösung brauche. |
| |
| Ein dickes Plus ist auch hier die Möglichkeit den Code plattformübergreifend (gut es gibt da Codefragmente, die angepasst werden müssen) |
| einsetzen zu können. |
| |
| |
| Wie schon beschrieben, seid Ihr als Python Einsteiger auf meinen Seiten sicher falsch, wenngleich der beschriebene Code sicher nicht |
| sonderlich kompliziert ist. Da es gerade als Anfänger manchmal nicht einfach ist die richtige Einführung in eine Sprache zu finden möchte |
| ich Euch an dieser Stelle nicht ganz im "Regen" stehen lassen. Da ich eher ein "old style" Lernender bin, setze ich bei Themen, die ich |
| mir aneignen möchte zunächst mal auf Bücher. Im Falle von Python finde ich das Buch "Python 3 - Das umfassende Handbuch" von |
| Johannes Ernesti und Peter Kaiser, inzwischen in der 7. Auflage im Rheinwerk Verlag erschienen, super. Gut finde ich bei dem Verlag auch, |
| daß man die dort erhältlichen Bücher im "Bundle" d. h. als Druck- und Ebookausgabe kaufen kann und sich so die digitale Ausgabe |
| dann eben z. B. auch auf sein Tablet laden kann, um das Buch immer dabei zu haben. Wenn Ihr Euch hingegen neue Themen lieber über |
| Videos aneignen möchtet kann ich Euch "The Morpheus Tutorials" empfehlen. In seinem YouTube Channel erklärt der Autor aus |
| meiner Sicht sehr gut alle möglichen Themen rund ums große Themenfeld Informatik, das Pythontutorial finde ich im Kanal ebenfalls sehr |
| gut gelungen! Mir gefällt vor allem, daß die Kapitel sehr kurz gehalten wurden, so daß man die Geschwindigkeit des "Voranschreitens" |
| selbst bestimmen kann. |
| |
| Nach diesen einführenden Informationen möchte ich auch hier kurz zeigen, wie das übliche "Hallo Welt" in Python funktioniert. Unter |
| Windows nutzt Ihr als Einsteiger am besten die sogenannte Python Shell.Den Interpreter bekommt Ihr auf den Downloadseiten des Projekts |
| Python.org. Wenn Ihr diese Shell startet und folgende Zeile eingebt, wird "Hallo Welt!" ausgegeben: |
|
| |
 |
| |
| Da ich gerade solche Skriptsprachen wie Python selten unter Windows, sondern eher auf unseren Linuxservern zur Erledigung |
| verschiedener Aufgaben einsetze, möchte ich Euch auch kurz zeigen, wie dieses "Hallo Welt" auf einem Linux System (nachfolgender |
| Screenshot stammt von einem CentOS 8 System) aussieht. Für diejenigen unter Euch, die vielleicht keine oder kaum Erfahrung mit |
| Linux/UNIX haben, werden auch die Berechtigungen (unter Linux muss die Datei auch ausführbar sein und Sie muss auch in der ersten |
| Zeile des Codes den Interpreter angegeben haben) und der Code mit Kommentaren angegeben. |
| |
 |
| |
| Soviel zu einem kleinen Einstieg und als Erläuterung, wie ich Python auf unseren Systemen einsetze. |
| |
| |
| Problemstellung: |
| |
| Für unsere Familie habe ich den Raspberry und insbeondere auch den Raspberry Zero als kleines Stück Hardware dafür entdeckt, daß |
| man an diesen Einplatinenrechner relativ einfach Sensoren anschließen kann, die man dann mittels wenig Code einfach auslesen und etwa |
| auf einer Webseite wieder ausgeben kann. Verfügbar sind aber auch das sogenannte Enviro Phat, ein Zusatzmodul, welches man auf den |
| Rasberry aufsteckt, und über das mehrere Sensoren kombiniert werden können. Zur Darstellung der Daten kommt ein "Miniwebserver" |
| (das sogenannte Framework Flask) zum Einsatz. Bei mir sieht das dann erst einmal wie folgt aus: |
| |
 |
| |
| Ziel war es diese Informationen einzusammeln und in unsere zentrale Datenbank (bei uns ist das ein MySQL Datenbanksystem zu schreiben.
|
| |
| Umsetzung: |
| |
| Das Skript, welches dieses leistet sieht wie folgt aus: |
| |
| #!/usr/bin/python |
| |
| # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| # + + |
| # + Python Script for catching weather data from our balcony sensor and store it + |
| # + at our internal MySQL Database (db: wetter_db, table: log_balkon) + |
| # + + |
| # + Author : Stefan Feeser + |
| # + Date : 11.07.2019 + |
| # + Version : 0.1 + |
| # + Copyright : Family Feeser, 2019 + |
| # + Changes : 11.07.2019 Creation of the script + |
| # + + |
| # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| |
| import sys |
| import time |
| import urllib2 |
| import re |
| import MySQLdb |
| |
| # |
| # ++++++++++++++++++++++++++++++++ D E K L A R A T I O N E N +++++++++++++++++++++++++++++++ |
| # |
| |
| flt_temp = 0.0 |
| flt_pressure = 0.0 |
| int_countrows = 0 |
| str_datum = "" |
| str_indat = "" |
| str_inzeit = "" |
| str_url = "http://192.168.0.168:2600/" |
| str_lines = "" |
| str_error = "" |
| str_element = "" |
| str_help = "" |
| str_logfile = "/data/logs/get-weatherdata-balcony.log" |
| str_server = '' |
| str_port = 'Port' |
| str_username = '' |
| str_password = '' |
| str_db = 'wetter_db' |
| str_sql = "select count(log_balkon_id) from log_balkon;" |
| str_line = "" |
| obj_response = "" |
| obj_loghandle = "" |
| |
| # |
| # ++++++++++++++++++++++++++++++++ H a u p t p r o g r a m m +++++++++++++++++++++++++++++++ |
| # |
| |
| # Start Logging Informations |
| |
| obj_loghandle = open(str_logfile,"a") |
| str_datum = time.strftime("%d.%m.%Y - %H:%M:%S") |
| obj_loghandle.write(str_datum + " : Start fetching weatherdata from our balcony sensor.\n") |
| |
| # Fetching weatherinformations from our sensor |
| |
| try: |
| obj_response = urllib2.urlopen(str_url, timeout = 5) |
| for str_lines in obj_response: |
| if re.search("\ | Temperatur",str_lines): |
| str_lines = re.sub("\ | Temperatur:\ | \","",str_lines) |
| str_lines = re.sub("\ | ","",str_lines)
| str_lines = re.sub("^\s*","",str_lines) |
| str_lines = re.sub("\s*$","",str_lines) |
| str_lines = re.sub("\n","",str_lines) |
| flt_temp = float(str_lines) |
| elif re.search("\ | Luftdruck",str_lines): |
| str_lines = re.sub("\ | Luftdruck:\ | \","",str_lines) |
| str_lines = re.sub("\ | ","",str_lines)
| str_lines = re.sub("^\s*","",str_lines) |
| str_lines = re.sub("\s*$","",str_lines) |
| str_lines = re.sub("\n","",str_lines) |
| flt_pressure = float(str_lines) |
| else: |
| continue |
| except (urllib2.HTTPError, urllib2.URLError) as str_error: |
| str_datum = time.strftime("%d.%m.%Y - %H:%M:%S") |
| obj_loghandle.write(str_datum + " : An error occured while trying to connect to URL (Errorcode: " + str(str_error) + "\n") |
| obj_loghandle.close() |
| sys.exit(1) |
| str_datum = time.strftime("%d.%m.%Y - %H:%M:%S") |
| obj_loghandle.write(str_datum + " : Received URL Information (Sensordata from balcony)\n") |
| #print("Temperatur: " + str(flt_temp) + ", Luftdruck: " + str(flt_pressure) + "\n") |
| str_datum = time.strftime("%d.%m.%Y - %H:%M:%S") |
| obj_loghandle.write(str_datum + " : Script identified Temperature (" + str(flt_temp) + ") and Pressure (" + str(flt_pressure) + ").\n") |
| |
| # Opening database connection to our Weatherdatabase and check about the amount of data |
| |
| str_datum = time.strftime("%d.%m.%Y - %H:%M:%S") |
| obj_loghandle.write(str_datum + " : Initializing Database connection and checking entries.\n") |
| obj_db = MySQLdb.connect(host=str_server, |
| user=str_username, |
| passwd=str_password, |
| db=str_db) |
| obj_cursor = obj_db.cursor() |
| obj_cursor.execute(str_sql) |
| for str_row in obj_cursor.fetchall(): |
| int_countrows = str_row[0] |
| int_lauf = int(int_countrows) + 1 |
| str_datum = time.strftime("%d.%m.%Y - %H:%M:%S") |
| obj_loghandle.write(str_datum + " : Script identified " + str(int_countrows) + " Rows at the database, will continue with ID " |
| + str(int_lauf) + ".\n") |
| obj_db.close() |
| str_datum = time.strftime("%d.%m.%Y - %H:%M:%S") |
| obj_loghandle.write(str_datum + " : Databaseconnection got closed.\n") |
| |
| # Preparing insert statement based on the fetched values |
| |
| str_datum = time.strftime("%d.%m.%Y - %H:%M:%S") |
| obj_loghandle.write(str_datum + " : Preparing insert statement.\n") |
| str_indat = time.strftime("%Y-%m-%d") |
| str_inzeit = time.strftime("%H:%M:%S") |
| str_sql = "insert into log_balkon values(" + str(int_lauf) + ",'" + str_indat + "','" + str_inzeit + |
| "'," + str(round(flt_temp,6)) + "," + str(round(flt_pressure,6)) + ",NULL);" |
| str_datum = time.strftime("%d.%m.%Y - %H:%M:%S") |
| obj_loghandle.write(str_datum + " : Insert statement created: " + str_sql + "\n") |
| |
| # Create a database object |
| |
| str_datum = time.strftime("%d.%m.%Y - %H:%M:%S") |
| obj_loghandle.write(str_datum + " : Creating Database connection.\n") |
| obj_db = MySQLdb.connect(host=str_server, |
| user=str_username, |
| passwd=str_password, |
| db=str_db) |
| # Create a cursor object to execute queries |
| |
| str_datum = time.strftime("%d.%m.%Y - %H:%M:%S") |
| obj_loghandle.write(str_datum + " : Creating cursor.\n") |
| obj_cursor = obj_db.cursor() |
| |
| # Send the insert statement |
| |
| try: |
| obj_cursor.execute(str_sql) |
| obj_db.commit() |
| str_datum = time.strftime("%d.%m.%Y - %H:%M:%S") |
| obj_loghandle.write(str_datum + " : Insert successful.\n") |
| except: |
| obj_db.rollback() |
| str_datum = time.strftime("%d.%m.%Y - %H:%M:%S") |
| obj_loghandle.write(str_datum + " : Rollback happened.\n") |
| |
| # Close connection |
| |
| obj_db.close() |
| str_datum = time.strftime("%d.%m.%Y - %H:%M:%S") |
| obj_loghandle.write(str_datum + " : Databaseconnection got closed.\n") |
| |
| # Finalizing Script (Closing Logfile and take care on a save exit) |
| |
| str_datum = time.strftime("%d.%m.%Y - %H:%M:%S") |
| obj_loghandle.write(str_datum + " : Script will end. Closing Logfile.\n") |
| obj_loghandle.close() |
| sys.exit(0) |
| |
| Es sei angemerkt, dass sich insbesondere das Datenbankmodul und das Modul für Webabfragen geändert haben, da der Code in der |
| vorliegenden Form schon etwas in die Jahre gekommen ist. Ich werde das gelegentlich anpassen. |
| |
| Was anhand des Codes aber hoffentlich ersichtlich ist, das zunächst ein Logfile initialisiert und über dieses alle Aufgaben |
| protokolliert werden. Im Anschluss werden die Webinformationen (Sensordaten) über eine Art Curl für Python geholt und aufbereitet. |
| Danach werden diese Daten dann in die Datenbank geschrieben, was gefordert wurde. |
| |
| Um das Holen der Sensordaten und das Schreiben in die Datenbank zu festgelegten Zeiten zu erreichen, habe ich einen Crontabeintrag erstellt:
|
| |
 |
| |
| Auch an dieser Stelle sei angemerkt, dass wir inzwischen andere Server nutzen und die Crontabeinträge inzwischen auch deutlich |
| umfangreicher geworden sind. Nachfolgend ein Screenshot unserer Weboberfläche. |
| |
 |
| |
| |
| Wie schon auf unseren C/C++ Seiten erwähnt, haben wir PyBricks für uns entdeckt. Die Webseite (funktioniert nur mit den Browsern |
| Chrome oder Edge) fungiert dabei als sogenannte IDE (Integrated Develop Environment), Dokumentationsseite, sowie Interface zu |
| verschiedenen Lego Microcontroller Systemen in einem. Erste Erfahrungen haben wir mit dem Lego Basic Powered Up Hub und dem |
| Lego Boost Hub gemacht. An den Powered Up Hub, der nachfolgend auch abgebildet ist, haben wir eine externe LED angeschlossen |
| und den nach dem Bild angegebenen Code in den Editor des Browsers kopiert. Drückt man hier den Playbutton, wird das Programm |
| via Bluetooth an den Hub übertragen und in unserem Fall leuchten die LEDs fünfmal kurz auf und gehen danach auch wieder aus. |
| |
 |
| |
 |
| |
| ↑ zurück zum Beginn der Seite |
| |