Forum: PC-Programmierung Langzeitspeicherung der Daten in Datenbank


von okey (Gast)


Lesenswert?

Hallo zusammen,

ich möchte eine Tabelle bei Mysql Workbench erstellen und da meine Daten 
vom MQTT speichern.

Momentan übertrage ich die Daten von einem ESP auf meinem Laptop per 
MQTT in Pycharm und hole mir den Litervebrauchi-mpulse meines 
Wasserzählers..
das klappt bis jetzt leider nicht..
CODE:
1
import datetime
2
import mysql.connector
3
import paho.mqtt.client as mqtt_client
4
5
def connect_mqtt():
6
    def on_connect(client, userdata, flags, rc):
7
        if rc == 0:
8
            print("Connected to MQTT Broker!")
9
            print('client')
10
        else:
11
            print("Failed to connect, return code %d\n", rc)
12
    def on_disconnect(client, userdata, rc):
13
        print("Client got disconnected")
14
        if rc!= 0:
15
            print('Unexpected MQTT disconnection, will auto-reconnect')
16
        else:
17
            print('rc value:' + str(rc))
18
        try:
19
            print("Trying to Reconnect")
20
            client.connect('10.28.1.119', 1883)
21
            client.subscribe("testclient")
22
            print('tried to subscribe')
23
        except:
24
            print("Error in Retrying to Connect with Broker")
25
26
    client = mqtt_client.Client('user')
27
    client.on_connect = on_connect
28
    client.on_disconnect = on_disconnect
29
    client.connect('10.28.1.119', 1883)
30
    return client
31
32
def subscribe(client: mqtt_client):
33
    def on_message(client, userdata, msg):
34
        print(datetime.datetime.now(), msg.topic, msg.payload.decode())
35
        value = msg.payload.decode()
36
        valueint = int(value)
37
38
        db = mysql.connector.connect(
39
            host="localhost",
40
            user="root",
41
            password="xxxxxx",
42
            port='3306',
43
            database="clienttest"
44
        )
45
        mycursor = db.cursor()
46
        mycursor.execute('INSERT into clienttest(Sensor,LiterVerbrauch, Date und Time) VALUES (%s, %s, %s)')
47
        print(valueint)
48
        db.commit()
49
        #if msg.topic == config.mqtt_topic:
50
            #alldata = msg.payload.decode()
51
            #jsondata = json.loads(alldata)
52
            #if insertAllOPCDataInDB(jsondata, config.MYSQL_tablename):
53
                #print(datetime.datetime.now(), 'all energydata for %s written do db.' % config.machine)
54
    client.subscribe('testclient')
55
    print("Subscribing to testclient", "testclient")
56
    client.on_message = on_message
57
58
client = connect_mqtt()
59
subscribe(client)
60
client.loop_forever()

: Verschoben durch Admin
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

okey schrieb:
> das klappt bis jetzt leider nicht..
Was klappt bis jetzt leider nicht?
Bis wohin funktioniert deine Idee und wo gehts schief?

von Thomas W. (Gast)


Lesenswert?

okey schrieb:
>         mycursor.execute('INSERT into clienttest(Sensor,LiterVerbrauch,
> Date und Time) VALUES (%s, %s, %s)')

Naja, dieses SQL ist bestimmt nicht so gedacht ('Date und Time'). Aber 
eine Fehlermeldung waere schon mal nicht schlecht...

Th.

von okey (Gast)


Angehängte Dateien:

Lesenswert?

solche Fehlermeldungen bekomme ich

von okey (Gast)


Angehängte Dateien:

Lesenswert?

:)

von Thomas W. (Gast)


Lesenswert?

Selten bloede Idee Fehlermeldungen als Graphik zu veroeffentlichen. Der 
nonSupportedError waere erstmal mein erster Gedanke (Copy and Paste geht 
ja nicht)

Viel Glueck

Th.

von okey (Gast)


Lesenswert?

habe auch noch keine Erfahrungen mit MySql.. hab aber mysql.connector 
installiert und alles bei MySql Workbench vorbereitet.. aber der Code 
scheint nicht zu funktionieren

von Ein T. (ein_typ)


Lesenswert?

okey schrieb:
>
1
> mycursor.execute('INSERT into [...] Date und Time)

"Date und Time"? Das ist kein valider Spaltenname.

von okey (Gast)


Lesenswert?

also ich habe nun so versucht, zwar keine Fehlermeldungen aber auch 
keine Datenspeicherung..
1
import datetime
2
import mysql.connector
3
import paho.mqtt.client as mqtt_client
4
5
i = datetime.datetime.now()
6
7
def connect_mqtt():
8
    def on_connect(client, userdata, flags, rc):
9
        if rc == 0:
10
            print("Connected to MQTT Broker!")
11
        else:
12
            print("Failed to connect, return code %d\n", rc)
13
    client = mqtt_client.Client('user')
14
    client.on_connect = on_connect
15
    client.connect('10.28.1.119', 1883)
16
    return client
17
18
19
def subscribe(client: mqtt_client):
20
    def on_message(client, userdata, msg):
21
        print(datetime.datetime.now(), msg.topic, msg.payload.decode())
22
        value = msg.payload.decode()
23
        valueint = int(value)
24
        db = mysql.connector.connect(
25
            host="localhost",
26
            user="root",
27
            password="winter2023",
28
            port='3306',
29
            database="clienttest"
30
        )
31
        year = str(i.year)
32
        month = str(i.month)
33
        day = str(i.day)
34
        date = day + "-" + month + "-" + year
35
36
        hour = str(i.hour)
37
        minute = str(i.minute)
38
        second = str(i.second)
39
        timestr = hour + ":" + minute + ":" + second
40
41
        mycursor = db.cursor()
42
        try:
43
            mycursor.execute("INSERT into clienttest" "(valueint,time,date)" "VALUES (%s,%s,%s)",(valueint,timestr,date))
44
            db.commit()
45
        except:
46
            db.rollback()
47
        #if msg.topic == config.mqtt_topic:
48
            #alldata = msg.payload.decode()
49
            #jsondata = json.loads(alldata)
50
            #if insertAllOPCDataInDB(jsondata, config.MYSQL_tablename)
51
         #print(datetime.datetime.now(), 'all energydata for %s written do db.' % config.machine)
52
    client.subscribe('testclient')
53
    client.on_message = on_message
54
55
56
client = connect_mqtt()
57
subscribe(client)
58
client.loop_forever()

von Ein T. (ein_typ)


Lesenswert?

okey schrieb:
>
1
>         try:
2
>             mycursor.execute("INSERT into clienttest" 
3
> "(valueint,time,date)" "VALUES (%s,%s,%s)",(valueint,timestr,date))
4
>             db.commit()
5
>         except:
6
>             db.rollback()

Das macht bei einem Fehler nur einen Rollback, gibt aber keinen Fehler 
aus und nichts. Vielleicht die Exception abfangen und ausgeben, 
vielleicht mit warnings.warn() oder traceback.print_exc()?

von Thomas W. (Gast)


Lesenswert?

Ein T. schrieb:
> okey schrieb:
>>
1
>>         try:
2
>>             mycursor.execute("INSERT into clienttest"
3
>> "(valueint,time,date)" "VALUES (%s,%s,%s)",(valueint,timestr,date))
4
>>             db.commit()
5
>>         except:
6
>>             db.rollback()
>
> Das macht bei einem Fehler nur einen Rollback, gibt aber keinen Fehler
> aus und nichts. Vielleicht die Exception abfangen und ausgeben,
> vielleicht mit warnings.warn() oder traceback.print_exc()?

Insbesondere wenn start transaction nicht existiert (oder wird das 
implizit irgendwo gestartet)?

Gruesse

Th.

von Schlaumaier (Gast)


Lesenswert?

okey schrieb:
>         mycursor.execute('INSERT into clienttest(Sensor,LiterVerbrauch,
> Date und Time) VALUES (%s, %s, %s)')

Die Anzahl der Spalten (erste Klammer) und die der Werte(2 Klammer) 
müssen gleich sein.

Es gibt KEINE Programmiersprache wo er Variblen_name mit leerzeichen 
gibt.

Und da felder auch eine Art Variable ist, gilt für sie das selbe.

Also gewöhne dir Leerzeichen in Feldern leerzeichen ab. Wenn du sie 
unbedingt willst, musst du das SQL mitteilen.

Richtig wäre also :

mycursor.execute('INSERT into clienttest(Sensor,LiterVerbrauch,
'Date und Time') VALUES (%s, %s, %s)')

Man beachte das HOCHkomme bei Date und Time.

Besser wäre es so.

mycursor.execute('INSERT into clienttest(Sensor,LiterVerbrauch,
Date_und_Time) VALUES (%s, %s, %s)')

Unterstrich beachten.

Da ich dein Code nicht kenne, besteht sogar die Möglichkeit das das 
Problem auftritt weil eine Tabelle ein Leerzeichen hat.

Merke: Leerzeichen sind in JEDER Programmiersprache böse und sollten NIE 
im Code bei Variblen , beschreibungen etc eingesetzt werden. Einzige 
Ausnahme : Deklarierter Text und dann in " " eingeschlossen.

von (prx) A. K. (prx)


Lesenswert?

Schlaumaier schrieb:
> Es gibt KEINE Programmiersprache wo er Variblen_name mit leerzeichen
> gibt.

Doch. In Fortran sind Leerzeichen optional überall erlaubt und nirgends 
nötig.

von Schlaumaier (Gast)


Lesenswert?

Nachtrag:

Der Begriff "valueint"  gefällt mir nicht.

Mache folgendes.

Lege die mySQL Datenbank mit einen Feld names ID an. Auto-Vergabe + 
Erhöhung, mit einmalig-Parameter.

Dann brauchst du dein Valueint nicht.

Du schreibst die werte einfach mit Insert da rein + gut ist.

Wenn du abfragen für änderungen machen willst, liest du ID mit aus, und 
schreibst du änderung mit "where ID = ausgelesenen_id"

von Schlaumaier (Gast)


Lesenswert?

(prx) A. K. schrieb:
> Doch. In Fortran sind Leerzeichen optional überall erlaubt und nirgends
> nötig.

Tote Kinder sollte man ruhen lassen ;)

von Ein T. (ein_typ)


Lesenswert?

okey schrieb:
> also ich habe nun so versucht, zwar keine Fehlermeldungen aber auch
> keine Datenspeicherung..
>
>
1
> i = datetime.datetime.now()

Ungeschickter Variablenname... zudem:

>         year = str(i.year)
>         month = str(i.month)
>         day = str(i.day)
>         date = day + "-" + month + "-" + year[/code]

Warum? datetime.datetime.now().date().isoformat() würde funktionieren 
und hätte vor allem auch den Vorteil, ein standardkonformes und damit 
weiter verarbeitbares ISO-Format in die Datenbank zu speichern. Nebenbei 
möchte ich anmerken, daß das ISO-Format nicht etwa Tag-Monat-Jahr ist, 
sondern exakt umgekehrt Jahr-Monat-Tag. Mit dem, was Du da erzeugst, 
kann keine Datenbank umgehen -- und wenn doch, dann ist sie kaputt 
(SQLite?).

Außerdem können Datenbankmodule, die kompatibel zu Pythons DBAPI2 
(PEP249) [1] sind, für Spalten mit Datums- und/oder Zeittypen natürlich 
Parameter der Typen datetime.date, datetime.datetime und datetime.time 
verwenden. Kompatible DB-Module liefern diese Datentypen für Datums- und 
Zeitspalten sogar automatisch zurück, wenn man sie abfragt.

Nebenbei bemerkt verstehe ich nicht ganz, warum Du Datum und Zeit in 
zwei unterschiedlichen Spalten speichern willst. Hat MySQL keine 
Spaltentypen wie DATETIME und / oder TIMESTAMP, die das in einer Spalte 
speichern?

Noch besser wäre es allerdings, die Funktionalität der Datenbank zu 
nutzen, bei MySQL IIRC die Funktion "NOW()" -- die kann man entweder als 
DEFAULT-Wert für die Spalte setzen, oder explizit im INSERT verwenden.

Zuletzt sei noch angemerkt, daß MQTT-Broker ihre Daten in der Regel 
nicht speichern, einige kann man allerdings anweisen, das zu tun. Wenn 
Dein Broker die Daten nicht speichert und es treffen neue Daten ein, 
während Dein Python-Skript nicht läuft oder es womöglich anderweitig 
beschäftigt ist, dann sind diese Daten unwiederbringlich verloren. Wenn 
das nicht passieren darf, ist eine Message-Queue vielleicht die bessere 
Lösung. In der Sparte dürfte Apache Kafka der Platzhirsch sein, aber 
auch RabbitMQ, ZeroMQ, NSQ und Redis Streams haben ihre Freunde und 
Anwendungsfälle.


[1] https://peps.python.org/pep-0249/

von Ein T. (ein_typ)


Lesenswert?

Thomas W. schrieb:
> Insbesondere wenn start transaction nicht existiert (oder wird das
> implizit irgendwo gestartet)?

Wenn der Client etwas in der Datenbank verändert, muß er nach DBAPI2 auf 
die Methode commit() des Connection-Handle aufrufen. Das ist insofern 
auch korrekt, als der ANSI/ISO-Standard einen impliziten Start der 
Transaktion mit einem expliziten Commit vorsieht. Python hält sich an 
den SQL-Standard, auch wenn die Datenbank das (Autocommit) nicht tun 
sollte.

von Alter Sack (Gast)


Lesenswert?

Ja nun, lies halt die Fehlermeldung, da stehts drin. Irgendein Plugin 
fehlt.

von Daniel A. (daniel-a)


Lesenswert?

Nimm mal nur den Teil deines programs:
1
import mysql.connector
2
db = mysql.connector.connect(
3
  host="localhost",
4
  user="root",
5
  password="xxxxxx",
6
  port='3306',
7
  database="clienttest"
8
)

Und schaue, das du den zum laufen kriegst. Solange die Verbindung schon 
nicht geht, kannst du vergessen irgend was in der DB zu machen.

von Jens G. (jensig)


Lesenswert?

Schlaumaier schrieb:
> Merke: Leerzeichen sind in JEDER Programmiersprache böse und sollten NIE
> im Code bei Variblen , beschreibungen etc eingesetzt werden. Einzige
> Ausnahme : Deklarierter Text und dann in " " eingeschlossen.

Merke: SQL ist keine Programmiersprache. Und SQL kennt sich mit 
Leerzeichen in Spaltennamen aus, wenn man diese in Hochkommas setzt (so, 
wie der TO es getan hat). Klar, empfohlen isses sicherlich nicht 
unbedingt, aber sollte in diesem Fall keinen Fehler bringen.
Viel schlimmer könnte es sein, daß er im korrigierten Code nun plötzlich 
date und time einzeln als Spaltennamen benutzt, denn das sind eigentlich 
Schlüsselwörter (ist aber je nach DB-System wiederrum evtl. auch kein 
Problem).

von Schlaumaier (Gast)


Lesenswert?

Jens G. schrieb:
> Merke: SQL ist keine Programmiersprache. Und SQL kennt sich mit
> Leerzeichen in Spaltennamen aus, wenn man diese in Hochkommas setzt (so,
> wie der TO es getan hat).

SQL ist eine Datenbanksprache. Das ist jedenfalls nah dran an einer 
Programmiersprache.

Und in den von mir kopierten Befehl waren KEINE Hochkommas sonst hätte 
ich es nicht angesprochen.

Der TO sollte aber sich von vorne rein angewöhnen DEUTSCHE + EINDEUTIGE 
Begriffe für Werte und Variablen_namen zu nutzen. Damit schließt er zu 
100 % aus, das er eine Konstante als Variablen_namen nutzt und sich 
unnötigen Stress einfängt.

Ich füge im Zweifelsfall immer ein m_ davor. Dann ist das Risiko auch 
bei 0.

von arbeitsloser Intendant (Gast)


Lesenswert?

Kann man für die IoT Pfuscher nicht mal ne eigene Kategorie machen wo 
sie ihre Problemchen mit Nodered, Python, ESP, ... und dem anderen 
Kidnergartenbastelschrott posten können? Oder besser gleich konsequent 
löschen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.