Werte von Arduino mit Python in Postgres schreiben

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
linuxubuntu
User
Beiträge: 9
Registriert: Freitag 28. Dezember 2018, 11:48

Hallo Zusammen

Ich versuche mit folgendem Python Script Daten in meine Postgres Datenbank zu schreiben. Ich weiss der Code kann noch verbessert werden und daran arbeite ich auch noch.

Code: Alles auswählen

from datetime import datetime

import psycopg2
import serial

db_connect = psycopg2.connect(user="xxxxx", password="xxxxxxx", host="1xxxxx", port="xxxxx",
                              database="mydb")

read_arduino = serial.Serial('/dev/ttyACM3', 9600)
db_curser = db_connect.cursor()

while True:
    data_arduino = read_arduino.readline()
    data_arduino_dec = data_arduino.decode("UTF8")
    data_arduino_dec_split = data_arduino_dec.split(",")
    returns_temp_name = data_arduino_dec_split[0]
    returns_temp_value = data_arduino_dec_split[1]
    leader_temp_value = data_arduino_dec_split[3]
    living_temp_value = data_arduino_dec_split[5]
    time_s = datetime.now().timestamp()
# Insert Value temperatur leader and returns in Database
    db_curser.execute(f"INSERT INTO my_smart_home(sensor_name, sensor_value, time_s)"
                      f"VALUES({str(returns_temp_name)}," f"{float(returns_temp_value)}, {time_s})")
    db_connect.commit()
Zur erklährung returns_temp_name ist der name des Sensors returns_temp_value ist der Wert vom Sensor.

Nun ist das Problem, dass ich vom Python folgende Fehlermeldung erhalte:

", line 22, in <module>
db_curser.execute(f"INSERT INTO my_smart_home(sensor_name, sensor_value, time_s)"
psycopg2.ProgrammingError: column "returns_temp" does not exist
LINE 1: ...art_home(sensor_name, sensor_value, time_s)VALUES(returns_te..."

Die Column "returns_temp" ist keine column sondern der name des Sensors und dieser soll in die Column sensor_name geschrieben werden.
Kann mir jemand helfen und sagen was ich falsch mache?

Besten Dank und Gruss


^
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Dann führe ein insert so durch, wie es die Doku sagt und bau dir den String nicht irgendwie zusammen (Stichwort: SQl-Injection):

http://initd.org/psycopg/docs/usage.htm ... dule-usage

Code: Alles auswählen

cur.execute("INSERT INTO test (num, data) VALUES (%s, %s)",  (100, "abc'def"))
%s als Platzhalter, die Variablen in einem tuple als 2. Parameter an execute.
linuxubuntu
User
Beiträge: 9
Registriert: Freitag 28. Dezember 2018, 11:48

Danke für die rasche Rückmeldung. Habe es nun hinbekommen:

Code: Alles auswählen

# Insert Value temperatur leader and returns in Database
    db_curser.execute("INSERT INTO my_smart_home (sensor_name, sensor_value, time_s) VALUES (%s, %s, %s)",
                      (str(returns_temp_name), float(returns_temp_value), float(time_s)))
    db_connect.commit()
Hättest du dies auch so gelöst?
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Man braucht nicht jedes Zwischenergebnis an eine Variable binden, insbesondere, wenn die Namen immer kryptischer werden.
Statt temp_value sollte es temperature heißen, dass es sich um einen Wert handelt, ist bei einer Variable nicht wirklich erhellend.
Serial-Objekte sind iterierbar, statt der while-Schleife würde sich also eine for-Schleife anbieten.
Statt die aktuelle Zeit selbst zu übergeben, würde ich das der Datenbank überlassen, oder gleich als default für das Feld nehmen: TIMESTAMP WITH TIMEZONE DEFAULT NOW().
Werte formatiert man nicht in SQL-Statements hinein. Bei den Datenbankfeldern, was soll das `s` bei `time_s`. Der Name my_smart_home ist für eine Tabelle, die Sensordaten sammelt auch seltsam, ich würde sie 'temperature' nennen, falls das nur Temperatursensordaten sind.

Code: Alles auswählen

for line in read_arduino:
    returns_name, returns_temperature, _, leader_temperature, _, living_temperature = line.decode('UTF8').split(",")
    db_curser = db_connect.cursor()
    db_curser.execute("INSERT INTO my_smart_home (sensor_name, sensor_value, time_s) VALUES (%s, %s, NOW())",
        (returns_name, float(returns_temperature)))
    db_connect.commit()
Antworten