Programmierer gesucht....

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
Pete60
User
Beiträge: 4
Registriert: Mittwoch 14. Februar 2018, 17:30

Hallo Leute,

ich suche einen Programmierer für ein Pi3 Projekt.

Was soll umgesetzt werden (grober Überblick):

.) Überschussverwertung, aufheizen eines Warmwasserspeicher mittels Photovoltaik.

.) Je nach verfügbarer PV Leistung stufenweises zuschalten (oder wieder wegschalten) von bis zu sechs Heizstäben

.) Kriterien fürs Zu- wegschalten der Lasten sind z.B.
Batterie Ladezustand SOC
Batteriespannung
Batteriestrom
Status Laderegler (OFF, Bulk, ABS, Float.... )
Status Wechselrichter (Durchleiten, Invert...)
Aktuelle Last der Wechselrichter

.) Die Werte für oben angeführte Kriterien sind über Modbus TCP aus einer Victron Color Control
auszulesen. Detailierte Adressliste der entsprechenden Register ist vorhanden.

https://www.victronenergy.de/panel-syst ... or-control

Aufwandsentschädigung nach Abstimmung.

Bei Interesse oder Fragen bitte PN.

Danke

Grüße

Peter
Cynob
User
Beiträge: 15
Registriert: Montag 11. Dezember 2017, 19:41

Ist das Gesuch noch aktuell?
Pete60
User
Beiträge: 4
Registriert: Mittwoch 14. Februar 2018, 17:30

Cynob hat geschrieben:Ist das Gesuch noch aktuell?
Danke für die Nachfrage.
Nach einiger Recherche hab ichs mal soweit selbst hinbekommen :D
Pete60
User
Beiträge: 4
Registriert: Mittwoch 14. Februar 2018, 17:30

Sieht im Moment so aus und das Zu und Wegschalten der Heizstäbe funktioniert.
Die "print" sind derzeit nur zum Testen.
Ein paar Dinge gehören noch angepasst: z.B. Fehlerbehandlung #assert(rr.function_code < 0x80) # test that we are not an error
Assert is da glaube ich falsch am Platz.

Aber eins nach dem Anderen.... :D

Code: Alles auswählen


from pymodbus.client.sync import ModbusTcpClient
import time
import RPi.GPIO as GPIO

#Victron Color Control IP Adresse
host = '192.168.0.214'
port = 502

#GPIO Pins init

GPIO.setwarnings(False)

GPIO.setmode(GPIO.BCM)
GPIO.setup(22, GPIO.OUT)
GPIO.output(22, GPIO.LOW)
GPIO.setup(23, GPIO.OUT)
GPIO.output(23, GPIO.LOW)
GPIO.setup(24, GPIO.OUT)
GPIO.output(24, GPIO.LOW)
GPIO.setup(25, GPIO.OUT)
GPIO.output(25, GPIO.LOW)
GPIO.setup(26, GPIO.OUT)
GPIO.output(26, GPIO.LOW)
GPIO.setup(27, GPIO.OUT)
GPIO.output(27, GPIO.LOW)



# Unit IDs
UID_BATT = 245              #Color Control VE.Direkt port2
UID_SOLARCHARGER = 100      #VE CAN inst 0
UID_VEBUS = 246             #Color Control VE.Bus port

# Batteriemonitor
ADR_BMON_TEMP = 262
ADR_BMON_VOLTAGE = 259
ADR_BMON_CURRENT = 261
ADR_BMON_SOC = 266

#Solarcharger
ADR_SOLARCHARGER_BATTEMP = 773

#Solarcharger ON/OFF
# 1=On 4=Off
ADR_SOLARCHARGER_ONOFF = 774

#Solarcharger state
# 0=Off 2=Fault 3=Bulk 4=Absorption 5=Float 6=Storage
# 7=Equalize 11=Other(Hub-1) 252=Hub-1
SCS_OFF = 0
SCS_FAULT = 2
SCS_BULK = 3
SCS_ABS = 4
SCS_FLOAT = 5
SCS_STORAGE = 6
SCS_EQUALIZE = 7
SCS_OTHER = 11
SCS_HUB1 = 252
ADR_SOLARCHARGER_STATE = 775


#Solarcharger error
# 0=No error
# 1=Battery temperature too high
# 2=Battery voltage too high
# 3=Battery temperature sensor miswired (+)
# 4=Battery temperature sensor miswired (-)
# 5=Battery temperature sensor disconnected
# 6=Battery voltage sense miswired (+)
# 7=Battery voltage sense miswired (-)
# 8=Battery voltage sense disconnected
# 9=Battery voltage wire losses too high
# 17=Charger temperature too high
# 18=Charger over-current
# 19=Charger current polarity reversed
# 20=Bulk time limit reached
# 22=Charger temperature sensor miswired
# 23=Charger temperature sensor disconnected
# 34=Input current too high
ADR_SOLARCHARGER_ERR = 788



#Wechselrichter Load Phase L1, L2, L3
ADR_WR_POWER_L1 = 23
ADR_WR_POWER_L2 = 24
ADR_WR_POWER_L3 = 25



# Wechselrichter overload alarm L1, L2. L3
# 0=Ok 1=Warning 2=Alarm
ADR_WR_OLALARM_L1 = 46
ADR_WR_OLALARM_L2 = 50
ADR_WR_OLALARM_L3 = 54



# Vebus (Wechselrichter) state
# 0=OFF 1=Low Power 2=Fault 3=Bulk 4=Absorption 5=Float 6=Storage 7=Equalize
# 8=Passthru 9=Inverting 10=Power assist 11=Power supply 252=Bulk protection
VE_INVERTING = 9
ADR_VEBUS_STATE = 31



#Vebus (Wechselrichter) error
# 0=No error;
# 1=VE.Bus Error 1: Device is switched off because one of the other phases in the system has switched off;
# 2=VE.Bus Error 2: New and old types MK2 are mixed in the system;
# 3=VE.Bus Error 3: Not all- or more than- the expected devices were found in the system;
# 4=VE.Bus Error 4: No other device whatsoever detected;
# 5=VE.Bus Error 5: Overvoltage on AC-out;
# 6=VE.Bus Error 6: Error in DDC Program;
# 7=VE.Bus BMS connected- which requires an Assistant- but no assistant found;
# 10=VE.Bus Error 10: System time synchronisation problem occurred;
# 14=VE.Bus Error 14: Device cannot transmit data;
# 16=VE.Bus Error 16: Dongle missing;
# 17=VE.Bus Error 17: One of the devices assumed master status because the original master failed;
# 18=VE.Bus Error 18: AC Overvoltage on the output of a slave has occurred while already switched off;
# 22=VE.Bus Error 22: This device cannot function as slave;
# 24=VE.Bus Error 24: Switch-over system protection initiated;
# 25=VE.Bus Error 25: Firmware incompatibility. The firmware of one of the connected device is not
# sufficiently up to date to operate in conjunction with this device;
# 26=VE.Bus Error 26: Internal error
VE_ERROR_0 = 0
ADR_VEBUS_ERROR = 32




def main():

    client = ModbusTcpClient(host, port)
    client.connect()

    heizung_an = False

    abs_ok = 0
    abs_nok = 0
    ABS_OK_MAX = 900  #ABS Phase muss 15min UNUNTERBROCHEN stabil sein um einen Heizstab zuzuschalten
    ABS_NOK_MAX = 60  #ABS Phase muss 1min UNUNTERBROCHEN stabil sein um Heizstab wegzuschalten

    heizung_cnt = 0          # Zähler für aktiven Heizstab. Bei 0 ist kein Heistab aktiv
    heizung_cnt_max = 6      # Anzahl Heistäbe
    heizung_cnt_min = 0



    while True:


	# Auslesen der relevanten Werte
	
        rr = client.read_holding_registers(ADR_BMON_VOLTAGE,1,unit = UID_BATT)
        #assert(rr.function_code < 0x80)     # test that we are not an error
        batt_voltage = (rr.registers[0]) / 100

        rr = client.read_holding_registers(ADR_BMON_CURRENT,1,unit = UID_BATT)
        #assert(rr.function_code < 0x80)     # test that we are not an error
        batt_current = (rr.registers[0])

        if batt_current > 32767:			#Strom im Format sint16
            batt_current = (batt_current - 65535) / 10
        else:
            batt_current = batt_current / 10

        rr = client.read_holding_registers(ADR_BMON_SOC,1,unit = UID_BATT)
        #assert(rr.function_code < 0x80)     # test that we are not an error
        batt_soc = (rr.registers[0]) / 10

        rr = client.read_holding_registers(ADR_VEBUS_STATE,1,unit = UID_VEBUS)
        #assert(rr.function_code < 0x80)     # test that we are not an error
        vebus_state = (rr.registers[0])

        rr = client.read_holding_registers(ADR_SOLARCHARGER_STATE,1,unit = UID_SOLARCHARGER)
        #assert(rr.function_code < 0x80)     # test that we are not an error
        solarcharger_state = (rr.registers[0])

        print("--------------------------------------------")
        print ("Batteriespannung:   ", batt_voltage, "V")
        print ("Batteriestrom:      ", batt_current, "A")
        print ("Ladezustand:        ", batt_soc,"%")
        print ("Solarcharger State: ", solarcharger_state)
        print("--------------------------------------------")



        if solarcharger_state == SCS_OFF or solarcharger_state == SCS_FAULT:

            if heizung_an:       # ALLE Heizungstäbe ausschalten wenn Laderegler Status "OFF" oder "FAULT"

                abs_ok = 0
                abs_nok = 0
                ABS_OK_MAX = 900
                ABS_NOK_MAX = 30
                heizung_cnt = 0
                HEIZUNG_CNT_MAX = 6
                HEIZUNG_CNT_MIN = 0

                for heizung_cnt in range(1,heizung_cnt_max + 1):
                    time.sleep(1)
                    GPIO.output(heizung_cnt + 22, GPIO.LOW)    # Alle Heizstäbe ausschalten

                heizung_cnt = 0
                heizung_an = False


        else:


            if vebus_state == VE_INVERTING:	# Heizung nur aktiv wenn Wechselrichter im Inverterbetrieb

                if solarcharger_state == SCS_ABS or solarcharger_state == SCS_FLOAT:

                    abs_ok = abs_ok + 1
                    abs_nok = 0
                    if abs_ok == ABS_OK_MAX:
                        abs_ok = 0
                        if heizung_cnt < HEIZUNG_CNT_MAX:
                            heizung_cnt = heizung_cnt + 1
                            heizung_an = True
                            GPIO.output(heizung_cnt + 22 - 1, GPIO.HIGH)


                else:
                    abs_nok = abs_nok + 1
                    abs_ok = 0
                    if abs_nok == ABS_NOK_MAX:
                        abs_nok = 0
                        if heizung_cnt > HEIZUNG_CNT_MIN:
                            GPIO.output(heizung_cnt + 22 - 1, GPIO.LOW)
                            heizung_cnt = heizung_cnt - 1
                            if heizung_cnt == 0:
                                heizung_an = False


            else:
                
                if heizung_an:       # ALLE Heizungstäbe ausschalten wenn Wechselrichter nicht im Inverterbetrieb

                    abs_ok = 0
                    abs_nok = 0
                    ABS_OK_MAX = 600
                    ABS_NOK_MAX = 30
                    heizung_cnt = 0
                    HEIZUNG_CNT_MAX = 6
                    HEIZUNG_CNT_MIN = 0

                    for heizung_cnt in range(1,heizung_cnt_max + 1):
                        time.sleep(1)
                        GPIO.output(heizung_cnt + 22, GPIO.LOW)    # Alle Heizstäbe ausschalten

                    heizung_cnt = 0
                    heizung_an = False


        print ("Heizung An: ", heizung_an)
        print ("Aktiver Heizstab: ", heizung_cnt)
        print ("Sekunden über ABS Phase: ", abs_ok)
        print ("Sekunden unter ABS Phase: ", abs_nok)
        
        time.sleep(1)

    client.close()

if __name__ == "__main__":
    main()

Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Pete60: Warnungen sind dazu da, dass man sie behebt und nicht einfach ignoriert. Die main-Funktion ist viel zu lang und sollte in mehrere Funktionen aufgeteilt werden. Es werden Konstanten innerhalb von if-Blöcken definiert und in anderen verwendet. Das ist ein Fehler. Konstanten sollten am Anfang des Programms stehen. Die if-Blöcke sind doppelt und sollten in Funktionen ausgegliedert werden.
Pete60
User
Beiträge: 4
Registriert: Mittwoch 14. Februar 2018, 17:30

Hallo Sirius3
Sirius3 hat geschrieben:Warnungen sind dazu da, dass man sie behebt und nicht einfach ignoriert.
Hatte ich mir gedacht und werde ich berücksichtigen.
Sirius3 hat geschrieben:. Es werden Konstanten innerhalb von if-Blöcken definiert und in anderen verwendet. Das ist ein Fehler. Konstanten sollten am Anfang des Programms stehen.
Ok, wird geändert.
Sirius3 hat geschrieben: Die if-Blöcke sind doppelt und sollten in Funktionen ausgegliedert werden.
Leuchtet mir ein und wird ebenso geändert....wenn ich weiß wie ich das umsetze.
Antworten