@kiaralle: Python hat da Listen und Wörterbücher wo PHP (assoziative) Arrays und für beides benutzt.
Das ist alles etwas wirr in dem Code. Der sollte mal aufgeräumt werden was die Namen und die Werte und Typen angeht.
Bei `growatt_registers` ist das erste Element der Listen immer eine ganze Zahl, ausser beim letzten, da ist es eine Zeichenkette mit der Darstellung einer ganzen Zahl. Das sollte wohl auch eine Zahl sein.
Wenn die Position eines Elements die Bedeutung des Elements festlegt, also nicht alle Elemente die gleiche Bedeutung haben, dann verwendet man eher Tupel als Listen.
Wie viele Elemente enthält `growatt_registers` denn? Wenn das 91 sind, und das erste Element lückelos aufsteigend einfach nur durchnummeriert ist, dann macht das keinen Sinn, denn dann ist dieser Wert ja immer gleich dem Index. Den hat man schon wenn man per Index darauf zugreift, und den kann man sich mit `enumerate()` einfach erzeugen wenn man direkt über die Elemente der Liste iteriert.
`register_name`, `register_id` und `register_factor` haben Namen die auf *einen* Wert schliessen lassen, stehen aber für Liste mit *vielen* Werten.
`register_factor` wird zwar befüllt, aber nirgends verwendet.
Man muss nicht jedes kleine Zwischnergebnis an einen Namen binden. Schon gar nicht wenn dann Werte unterschiedlichen Typs an einen Namen gebunden werden. Das ist verwirrend.
`data` wird an eine leere Zeichenkette gebunden die nie irgendwo verwendet wird, und später wird der Name dann an ein Tupel gebunden.
Namen sollten erst an Werte gebunden werden wenn man sie braucht. Und beispielsweise nicht zwischen dem binden an leere Listen und dem befüllen in einer Schleife noch andere Sachen machen.
``for i in range(len(sequence)):`` nur um dann `i` für den Zugriff in die Sequenz zu verwenden ist in Python ein „anti pattern“. Man kann direkt über die Elemente von Sequenzen iterieren, ohne den unnötigen Umweg über einen Laufindex.
Und auch feste ”magische” Indexwerte sind nicht gut, weil die nicht zum Verständnis der Bedeutung der Werte beitragen. Man kann die Werte an Namen binden.
Das zusammenstückeln von Zeichenketten und Werten mittels ``+`` und `str()` ist eher BASIC als Python. Dafür gibt es die `format()`-Methode auf Zeichenketten und f-Zeichenkettenliterale.
Das zweite Argument von `execute()` muss kein Tupel sein, eine Liste geht da auch.
Der Code würde dann so aussehen:
Code: Alles auswählen
from contextlib import closing
def some_function(connection):
growatt_registers = [
(0, "Status", 1),
(1, "Vpv1", 0.1),
# ....
(88, "Eop_dischrTotal_L", 1),
(89, "leer89", 0),
(90, "ParaChgCurr", 0.1),
]
register_ids = []
column_names = []
for register_id, name, _factor in growatt_registers:
register_ids.append(f"register[{register_id}]")
column_names.append(name.lower())
with closing(connection.cursor()) as cursor:
cursor.execute(
"INSERT INTO master ({}) VALUES ({})".format(
", ".join(column_names), ", ".join(["%s"] * len(column_names))
),
register_ids,
)
connection.commit()
Das Problem sollte eigentlich offensichtlich sein. Du generierst da komische ”register IDs” die wie Pythoncode aussehen als Zeichenketten und versuchst diese Zeichenketten dann als Werte für die Datenbankspalten zu übergeben. Was soll die Datenbank denn machen wenn sie "register[0]" als *Wert* bekommt?
Und so ``..., register[89], register[90])`` kann das Tupel bei der Ausgabe nicht aussehen. Das muss ja *Werte* enthalten. ``register[90]`` ist aber kein Wert sondern ein *Ausdruck*. Das ist in PHP auch nicht anders, da geht das auch nicht ein Array mit Ausdrücken zu erstellen.
Die Lösung ist supersimpel wenn man verstanden hat was Code ist, was Zeichenketten sind, was Werte sind, und die Trennung von Python und SQL/Datenbank. Man kann der SQL-Datenbank keine Python-Ausdrücke als Zeichenketten übergeben und erwarten, dass die damit etwas anfangen kann oder auch nur Zugriff auf die Daten im Python-Prozess hat.
Letztlich solltest Du *dieses* Problem aber gar nicht lösen, sondern die Tabelle so strukturieren das die nur vier Spalten hat: id, timestamp, register_number, value. Sofern die Werte alle den gleichen Typ haben.
Der Code sähe dann ungefähr so aus:
Code: Alles auswählen
from contextlib import closing
from datetime import datetime as DateTime
def some_function(connection, register_values):
growatt_registers = [
(0, "Status", 1),
(1, "Vpv1", 0.1),
# ....
(88, "Eop_dischrTotal_L", 1),
(89, "leer89", 0),
(90, "ParaChgCurr", 0.1),
]
with closing(connection.cursor()) as cursor:
now = DateTime.now()
cursor.executemany(
"INSERT INTO master (`timestamp`, register_id, value) VALUES (%s, %s, %s)",
(
(now, register_id, register_values[register_id])
for register_id, _, _ in growatt_registers
),
)
connection.commit()