In diesem Tutorial zeige ich dir, wie du mit einem RaspberryPi (oder auch jedem anderen Linux Rechner) einen SDM630 Modbus Zähler auslesen kannst. Das Tutorial soll eher eine Grundlage für ein eigenes Projekt sein. Fertige Software gibt es genug, wie zum Beispiel Smartmeter.
Hardware
- SDM630 Stromzähler (z.B. diesen hier)
- Modbus USB Adapter (z.B. diesen hier)
- Kabel
- 2x 150 Ohm Widerstand
An der oberen Klappe des Zählers gibt es u.A. die Anschlüsse A+ und B-. Diese werden mit den Klemmen A und B am Adapter verbunden. Ein Abschlusswiderstand von 150 Ohm kommt an die Endes des Bus bzw. an das letzte und erste Gerät. Da ich nur 2 Geräte habe, ist das der Zähler und der USB Adapter.
Am Bus können theoretisch mehrere Zähler parallel angeschlossen werden.
Software
Einstellungen am Zähler
Am Zähler müssen für den Modbus verschiedene Einstellungen vorgenommen werden. Das geht bei meinem Zähler so:
- Lange die Taste E drücken
- Passwort eingeben (Standard: 1000)
- Lange die Taste E drücken
- Es erscheint „Set Addr“
- Durch langes Drücken der Taste E die Einstellung wählen und mit den Pfeilen die Adresse ändern. Durch langes Drücken der Taste E die Einstellung Verlassen
- Mit den Pfeilen die Einstellungen „Set baud“, „Set Pari“ und „Set Stop“ wählen und ebenfalls einstellen
Die Adresse ist dazu das, das Gerät im Bus zu identifizieren. Wenn du nur ein Gerät hast, kannst du die Adresse bei 1 lassen, wenn du mehrere hast, den Geräten entsprechend unterschiedliche Adressen geben.
Die Baudrate ist einfach gesagt die Übertragungsgeschwindigkeit. Bei höherer Baudrate ist aber nur eine kürzere Kabellänge möglich.
Parität benutze ich keine, also „none“
Der Stop-Bit kann auf 1 gelassen werden
Mit Skript Werte auslesen
Neben den Einstellungen die du vorher vorgenommen hast, brauchst du noch einen weiteren Wert: Den USB Port. Durch ausprobieren ist man hier ziemlich erfolgreich. Mit ls /dev/ttyUSB*
kannst du dir alle Ports anzeigen lassen. In meinem Fall gab es nur einen einzigen.
Mein Code sieht folgendermaßen aus:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
import minimalmodbus instrument = minimalmodbus.Instrument('/dev/ttyUSB0', 1) # port name, slave address (in decimal) input_register = { "Spannung_L1": { "port": 0, "digits": 2, "Unit": "V", "use": True}, "Spannung_L2": { "port": 2, "digits": 2, "Unit": "V", "use": True}, "Spannung_L3": { "port": 4, "digits": 2, "Unit": "V", "use": True}, "Strom_L1": { "port": 6, "digits": 2, "Unit": "A", "use": True}, "Strom_L2": { "port": 8, "digits": 2, "Unit": "A", "use": True}, "Strom_L3": { "port": 10, "digits": 2, "Unit": "A", "use": True}, "Wirkleistung_L1": { "port": 12, "digits": 2, "Unit": "W", "use": True}, "Wirkleistung_L2": { "port": 14, "digits": 2, "Unit": "W", "use": True}, "Wirkleistung_L3": { "port": 16, "digits": 2, "Unit": "W", "use": True}, "Scheinleistung_L1": { "port": 18, "digits": 2, "Unit": "VA", "use": True}, "Scheinleistung_L2": { "port": 20, "digits": 2, "Unit": "VA", "use": True}, "Scheinleistung_L3": { "port": 22, "digits": 2, "Unit": "VA", "use": True}, "Blindleistung_L1": { "port": 24, "digits": 2, "Unit": "VAr", "use": True}, "Blindleistung_L2": { "port": 26, "digits": 2, "Unit": "VAr", "use": True}, "Blindleistung_L3": { "port": 28, "digits": 2, "Unit": "VAr", "use": True}, "Leistungsfaktor_L1": { "port": 30, "digits": 2, "Unit": "", "use": True}, "Leistungsfaktor_L2": { "port": 32, "digits": 2, "Unit": "", "use": True}, "Leistungsfaktor_L3": { "port": 34, "digits": 2, "Unit": "", "use": True}, "Phasenwinkel_L1": { "port": 36, "digits": 2, "Unit": "Grad", "use": True}, "Phasenwinkel_L2": { "port": 38, "digits": 2, "Unit": "Grad", "use": True}, "Phasenwinkel_L3": { "port": 40, "digits": 2, "Unit": "Grad", "use": True}, "Durchschnittliche_Spannung_zu_N": { "port": 42, "digits": 2, "Unit": "V", "use": True}, "Durchschnittlicher_Strom_zu_N": { "port": 46, "digits": 2, "Unit": "A", "use": True}, "aktueller_Gesamtstrom": { "port": 48, "digits": 2, "Unit": "A", "use": True}, "aktuelle_Gesamtwirkleistung": { "port": 52, "digits": 2, "Unit": "W", "use": True}, "aktuelle_Gesamtscheinleistung": { "port": 56, "digits": 2, "Unit": "VA", "use": True}, "aktuelle_Gesamtblindleistung": { "port": 60, "digits": 2, "Unit": "VAr", "use": True}, "aktueller_Gesamtleistungsfaktor": { "port": 62, "digits": 2, "Unit": "", "use": True}, "aktueller_Gesamtphasenwinkel": { "port": 66, "digits": 2, "Unit": "A", "use": True}, "Frequenz": { "port": 70, "digits": 2, "Unit": "Hz", "use": True}, "Import_Wh_seit_reset": { "port": 72, "digits": 2, "Unit": "kWh", "use": True}, "Export_Wh_seit_reset": { "port": 74, "digits": 2, "Unit": "kWH", "use": True}, "Import_VArh_seit_reset": { "port": 76, "digits": 2, "Unit": "kVArh", "use": True}, "Export_VArh_seit_reset": { "port": 78, "digits": 2, "Unit": "kVArh", "use": True}, "VAh_seit_reset": { "port": 80, "digits": 2, "Unit": "kVAh", "use": True}, "Ah_seit_reset": { "port": 82, "digits": 2, "Unit": "Ah", "use": True}, "Gesamtwirkleistung": { "port": 84, "digits": 2, "Unit": "W", "use": True}, "Max_Gesamtwirkleistung": { "port": 86, "digits": 2, "Unit": "W", "use": True}, "Gesamtscheinleistung": { "port": 100, "digits": 2, "Unit": "VA", "use": True}, "Max_Gesamtscheinleistung": { "port": 102, "digits": 2, "Unit": "VA", "use": True}, "Gesamtstrom_Neutralleiter": { "port": 104, "digits": 2, "Unit": "A", "use": True}, "Max_Strom_Neutralleiter": { "port": 106, "digits": 2, "Unit": "A", "use": True}, "Spannung_L1_L2": { "port": 200, "digits": 2, "Unit": "V", "use": True}, "Spannung_L2_L3": { "port": 202, "digits": 2, "Unit": "V", "use": True}, "Spannung_L3_L1": { "port": 204, "digits": 2, "Unit": "V", "use": True}, "Durchschnittsspannung_L_L": { "port": 206, "digits": 2, "Unit": "V", "use": True}, "Strom_Neutralleiter": { "port": 224, "digits": 2, "Unit": "A", "use": True}, "THD_Spannung_L1": { "port": 234, "digits": 2, "Unit": "%", "use": True}, "THD_Spannung_L2": { "port": 236, "digits": 2, "Unit": "%", "use": True}, "THD_Spannung_L3": { "port": 238, "digits": 2, "Unit": "%", "use": True}, "THD_Strom_L1": { "port": 240, "digits": 2, "Unit": "%", "use": True}, "THD_Strom_L2": { "port": 242, "digits": 2, "Unit": "%", "use": True}, "THD_Strom_L3": { "port": 244, "digits": 2, "Unit": "%", "use": True}, "THD_Durchschnittliche_Spannung_zu_N": { "port": 248, "digits": 2, "Unit": "%", "use": True}, "THD_Durchschnittlicher_Strom_zu_N": { "port": 250, "digits": 2, "Unit": "%", "use": True}, "Strom_L1_demand": { "port": 258, "digits": 2, "Unit": "A", "use": True}, "Strom_L2_demand": { "port": 260, "digits": 2, "Unit": "A", "use": True}, "Strom_L3_demand": { "port": 262, "digits": 2, "Unit": "A", "use": True}, "Max_Strom_L1_demand": { "port": 264, "digits": 2, "Unit": "A", "use": True}, "Max_Strom_L2_demand": { "port": 266, "digits": 2, "Unit": "A", "use": True}, "Max_Strom_L3_demand": { "port": 268, "digits": 2, "Unit": "A", "use": True}, "THD_Spannung_L1_L2": { "port": 334, "digits": 2, "Unit": "%", "use": True}, "THD_Spannung_L2_L3": { "port": 336, "digits": 2, "Unit": "%", "use": True}, "THD_Spannung_L3_L1": { "port": 338, "digits": 2, "Unit": "%", "use": True}, "THD_Durchschnittliche_Spannung_zu_L_L": { "port": 340, "digits": 2, "Unit": "%", "use": True}, "Total_kwh": { "port": 342, "digits": 2, "Unit": "kwh", "use": True}, "Total_kvarh": { "port": 344, "digits": 2, "Unit": "kvarh", "use": True}, "Import_L1_kwh": { "port": 346, "digits": 2, "Unit": "kwh", "use": True}, "Import_L2_kwh": { "port": 348, "digits": 2, "Unit": "kwh", "use": True}, "Import_L3_kwh": { "port": 350, "digits": 2, "Unit": "kwh", "use": True}, "Export_L1_kwh": { "port": 352, "digits": 2, "Unit": "kwh", "use": True}, "Export_L2_kwh": { "port": 354, "digits": 2, "Unit": "kwh", "use": True}, "Export_L3_kwh": { "port": 356, "digits": 2, "Unit": "kwh", "use": True}, "Gesamtstrom_L1_kwh": { "port": 358, "digits": 2, "Unit": "kwh", "use": True}, "Gesamtstrom_L2_kwh": { "port": 360, "digits": 2, "Unit": "kwh", "use": True}, "Gesamtstrom_L3_kwh": { "port": 362, "digits": 2, "Unit": "kwh", "use": True}, "Import_L1_kvarh": { "port": 364, "digits": 2, "Unit": "kvarh", "use": True}, "Import_L2_kvarh": { "port": 366, "digits": 2, "Unit": "kvarh", "use": True}, "Import_L3_kvarh": { "port": 368, "digits": 2, "Unit": "kvarh", "use": True}, "Export_L1_kvarh": { "port": 370, "digits": 2, "Unit": "kvarh", "use": True}, "Export_L2_kvarh": { "port": 372, "digits": 2, "Unit": "kvarh", "use": True}, "Export_L3_kvarh": { "port": 374, "digits": 2, "Unit": "kvarh", "use": True}, "Total_L1_kvarh": { "port": 376, "digits": 2, "Unit": "kvarh", "use": True}, "Total_L2_kvarh": { "port": 378, "digits": 2, "Unit": "kvarh", "use": True}, "Total_L3_kvarh": { "port": 380, "digits": 2, "Unit": "kvarh", "use": True}, } for key in input_register: if input_register[key]["use"] == True: print(key + ": " + str(round(instrument.read_float(functioncode=4, registeraddress=input_register[key]["port"], number_of_registers=input_register[key]["digits"]), 2)) + input_register[key]["Unit"]) |
In Zeile 1 wird das Modbus Modul von Python importiert. Dieses musst du vielleicht noch installieren:
1 |
$ pip3 install minimalmodbus |
In der nächsten Zeile wird das Gerät initialisiert. Hier musst du evtl. noch den USB Port und die Modbus Adresse ändern. Danach gibt es einen sehr langen Part, durch den das Skript später weiß, welcher Wert welche Nummer und welche Einheit hat. Durch das „use“ kann festgelegt werden, ob der Wert verwendet werden soll oder nicht. Dazu einfach den Wert auf True bzw. False setzen. In Zeile 177 befindet sich eine for Schleife, die einmal für jeden Wert ausgeführt wird. Zeile 178 prüft, ob der Wert verwendet werden soll. Alles danach (Einrückungen nicht vergessen) kannst du jetzt frei programmieren. In meinem Beispiel werden alles Daten einfach nur per print ausgegeben. Die Zeile
1 |
instrument.read_float(functioncode=4, registeraddress=input_register[key]["port"], number_of_registers=input_register[key]["digits"]) |
gibt den Wert zurück (der, bei der die for Schleife gerade ist). Mit
1 |
input_register[key]["Unit"] |
bekommst du die Einheit.
Dieses Codebeispiel schreib zum Beispiel die Daten in eine Influx Datenbank.
Und jetzt viel Spaß beim Programmieren!
3. Mai 2022 um 11:28 Uhr
malne frage …. sieht aus wie ein bussystem an dem alle teilnehmer mittels adressen agieren –> gelbes kabel 802.3 ; könnte man das für den WR SPH4600 adaptieren um den WR damit zu steuern ? da gibts ne grosse gemeinde …. und danke fd seite hier … meld dich mal per mail danke
6. Mai 2022 um 8:09 Uhr
Schau dir doch mal die Software „Solaranzeige“ an: https://solaranzeige.de
Die bietet auch die Möglichkeit einen Growatt WR zu steuern/auslesen.
https://solaranzeige.de/phpBB3/viewtopic.php?t=1054
Da müsstest du nichts programmieren. Ansonsten wäre es natürlich auch möglich, das mit dem Skript oben im Beitrag zu machen. Man müsste eben manche Sachen ändern
4. Juli 2022 um 11:08 Uhr
Hallo JJK, ich habe keinen Raspberry Pi nur einen Windows PC mit Python 3x und einen USB auf RS485. Dieser ist mit dem Eastron SDM630 verbunden.
Was muss ich im Python Programm starten um dein Skript direkt auszuführen und die Daten auf dem PC anzuzeigen.
Danke monette999
4. Juli 2022 um 17:33 Uhr
Theoretisch sollte das Skript auch auf Windows laufen. Du musst nur den USB Port in Zeile 3 ändern. Das wird dort COM1 oder COM2, usw. sein.
4. Juli 2022 um 22:43 Uhr
Etwas so?
Mein COM Port ist COM6.
#Set up instrument
instrument = minimalmodbus.Instrument(PORT,6,mode=minimalmodbus.MODE_RTU)
#Make the settings explicit
instrument.serial.baudrate = 9600 # Baud
instrument.serial.bytesize = 8
instrument.serial.parity = minimalmodbus.serial.PARITY_NONE
instrument.serial.stopbits = 1
instrument.serial.timeout = 1 # seconds
5. Juli 2022 um 16:18 Uhr
So müsste es die Zeile 3 im Skript oben aussehen:
instrument = minimalmodbus.Instrument('COM6', 1)
Und dann einfach mein Skript von oben verwenden und mal testen. Auf Windows hab ich so etwas noch nicht gemacht…