|
|
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 |
|