Marstek Venus – Register schreiben per Modbus/RS485 in openHAB

Kurzlich habe ich über die Integration des Marstek Venus E in openHAB per modbus-Binding berichtet. Da ich bisher nur lesend auf die Register zugegriffen habe, war es jetzt an der Zeit, auch Teile der Steuerung per modbus umzusetzen. Das genutzte Gateway ist bei mir der Waveshare Rail-Mount Serial Server, RS232/485/422 to RJ45 Ethernet.

Konkreter Anwendungsfall:

  • Die Steuerung des eAuto-Ladens war recht hemdsärmlig umgesetzt. Ziel war es den Speicher wegzuschalten, wenn „normal“ und nicht per Überschuss geladen wird.
    Da ich – bevor ich die modbus-Anbindung vorgenommen hatte – nur über einen emulierten Shelly Werte an den Venus liefern konnte, musste ich den virtuellen Wert so setzen, dass sich der Speicher beim normalen Laden in Richtung 0W bewegt. Das ist nur in mehreren Schritten gelungen und war nicht schön umgesetzt.
  • Durch Modbus-Steuerung ist es leicht möglich, den Speicher in den RS485-Modus zu versetzen, so dass er den emulierten Shelly-Wert ignoriert, auf 0W in den Standby geht und nur noch auf RS485-Befehle hört. Dies macht er, bis der RS485-Modus wieder deaktiviert wird. Und genau das nutze ich nun, um den Speicher im Fall des normalen eAuto-Ladens „wegzuschalten“.

Analog zum Aktivieren / Deaktivieren des RS485-Modus kann man natürlich andere Register beschreiben und so mit all den Möglichkeiten, die aus der Register-Dokumentation ersichtlich sind, arbeiten.

Konkrete Umsetzung:

Die Registerbelegung ist im Ursprungsbeitrag einsehbar. Für das Aktivieren des RS485-Modus muss in Register 42000 (Typ uint16) der Wert 0X55AA (entspricht dezimal 21930) geschrieben werden. Für das Deaktivieren der Wert 0x55BB (entspricht dezimal 21947). Um den Wert schreiben zu können ist eine Rule die einfachste Möglichkeit.

Wir brauchen daher:

Zwei Things, eines, welches das Register via Modbus überhaupt erst zugreifbar macht (Bridge) und ein weiteres, welches den Lese- und Schreibzugriff auf das Register über die Bridge ermöglicht:

Zwei Items, eines, welches den Wert des Registers beinhaltet und beschrieben werden kann und einen Switch, der dann einfach per An- und Ausschalten den nötigen Wert schreibt:

Und zuletzt eine Rule, die das Tatsächliche Schreiben bei Bedienen des Switches übernimmt.

Thing 1 – Verbindung zum Waveshare

UID: modbus:poller:venus-waveshare:venus-holding-registers-42000-42000
label: Marstek Venus Modbus Holding Register 42000-42000
thingTypeUID: modbus:poller
configuration:
  start: 42000
  length: 1
  refresh: 500
  maxTries: 3
  cacheMillis: 50
  type: holding
bridgeUID: modbus:tcp:venus-waveshare

Thing 2 – Verbindung zum Register

UID: modbus:data:venus-holding-registers-42000-rs485:42000-write-rs485controlmode
label: Marstek Venus Modbus Write Register 42000 Control RS485 ON OFF
thingTypeUID: modbus:data
configuration:
  readValueType: uint16
  readTransform: default
  writeType: holding
  writeTransform: default
  readStart: "42000"
  updateUnchangedValuesEveryMillis: 1000
  writeValueType: int16
  writeMultipleEvenWithSingleRegisterOrCoil: false
  writeMaxTries: 3
  writeStart: "42000"
bridgeUID: modbus:poller:venus-waveshare:venus-holding-registers-42000-42000
channels:
  - id: number
    channelTypeUID: modbus:number-type
    label: Value as Number
    description: Number item channel
    configuration: {}
  - id: switch
    channelTypeUID: modbus:switch-type
    label: Value as Switch
    description: Switch item channel
    configuration: {}
  - id: contact
    channelTypeUID: modbus:contact-type
    label: Value as Contact
    description: Contact item channel
    configuration: {}
  - id: dimmer
    channelTypeUID: modbus:dimmer-type
    label: Value as Dimmer
    description: Dimmer item channel
    configuration: {}
  - id: datetime
    channelTypeUID: modbus:datetime-type
    label: Value as DateTime
    description: DateTime item channel
    configuration: {}
  - id: string
    channelTypeUID: modbus:string-type
    label: Value as String
    description: String item channel
    configuration: {}
  - id: rollershutter
    channelTypeUID: modbus:rollershutter-type
    label: Value as Rollershutter
    description: Rollershutter item channel
    configuration: {}
  - id: lastReadSuccess
    channelTypeUID: modbus:last-successful-read-type
    label: Last Successful Read
    description: Date of last read
    configuration: {}
  - id: lastReadError
    channelTypeUID: modbus:last-erroring-read-type
    label: Last Erroring Read
    description: Date of last read error
    configuration: {}
  - id: lastWriteSuccess
    channelTypeUID: modbus:last-successful-write-type
    label: Last Successful Write
    description: Date of last write
    configuration: {}
  - id: lastWriteError
    channelTypeUID: modbus:last-erroring-write-type
    label: Last Erroring Write
    description: Date of last write error
    configuration: {}

Item 1 – Wert des Registers

Code ist recht simpel, wichtig ist natürlich die Verknüpfung mit dem Value as Number-Channel des things:

label: Venus Control RS485 Register Value
type: Number
category: ""
groupNames:
  - pvspeicher
tags:
  - Point

Item 2 – Switch für Darstellung und Steuerung RS485-Modus

Code:

label: Venus Control RS485 Switch
type: Switch
category: ""
groupNames:
  - pvspeicher
tags: []

Rule für den Switch

Datei Venus.rules

rule "Venus Switch für RS485-Steuerung synchron zum Status halten bzw. schaltbar machen"
when Item venus_control_rs485_switch changed 
then 
    if (venus_control_rs485_switch.state == OFF) venus_rs485_write_register.sendCommand(0x55BB) // Entspricht Dezimal 21947
    else venus_rs485_write_register.sendCommand(0X55AA) // Entspricht Dezimal 21930
end

Visualisierung als Widget

die Werte meines Speichers habe ich mir dann in einem Widget visualisiert und je nachdem, ob der Modus RS485 ist oder Selbstanpassung steht dort nun „RS485“ oder „auto“:

Beispiel: Anwendungsfall für die Steuerung des Speichers bei eAuto-Laden

Konkretes Beispiel, wie ich nun meine E-Auto-Ladesteuerungslogik im Kontext des virtuellen Shellies angepasst habe. Den Ursprungsbeitrag findet ihr hier.

var boolean log = false

rule "Publish Strom saldierend bei Änderung zu virtuellem Shelly-Device und steuere Speicher AN/AUS"
when
    Item strom_saldierend changed
then
    var powerValue = 0.0
    // Wert für virtuellen Shelly: saldierender Wert, der von realen Shellies ausgelesen wird.
    powerValue = powerValue = (strom_saldierend.state as QuantityType<Power>).doubleValue

    // Speicher berücksichtigen und ggf. je nach Lademodus RS485-Modus anschalten oder auch nicht

    // Lädt Auto nicht? Dann sollte Speicher immer an sein.
    if ((GoeCharger_Power_All.state as Number) < 1) {
        if (log) logInfo("virtualShelly", "Wallbox lädt nicht, Speicher wird - wenn nicht an - aktiviert")
        if (venus_control_rs485_switch.state != OFF)  {
            if (log) logInfo("virtualShelly","RS 485 Modus wird ausgeschalten")
            venus_control_rs485_switch.sendCommand(OFF)
        }
    } else { // Lädt Auto? Dann prüfen, ob Überschussladen stattfindet.
        if (log) logInfo("virtualShelly", "Wallbox lädt, Speicher wird ggf. aktiviert oder deaktiviert")
        // Überschussladen aus? Dann speicher aus
        if ((ueberschussladen_aktiv.state != ON)) {
            if (log) logInfo("virtualShelly","Überschussladen ist AUS, speicher wird deaktiviert, falls an")
            if  (venus_control_rs485_switch.state != ON) {
                if (log) logInfo("virtualShelly","Speicher wird Deaktiviert, RS485 Modus wird eingeschalten")
                venus_control_rs485_switch.sendCommand(ON)
            }
        }
        // Überschussladen an? Dann speicher ein, Speicher hat später ja Vorrang vor Überschussladen
        if (ueberschussladen_aktiv.state != OFF) {
            if (log) logInfo("virtualShelly","Überschussladen ist AN")
            if (venus_control_rs485_switch.state != OFF) {
                if (log) logInfo("virtualShelly","Speicher wird aktiviert, RS485 Modus wird ausgeschalten")
                venus_control_rs485_switch.sendCommand(OFF)
            }
            // Wenn Auto per Überschussladen lädt, dann soll Speicher mit voller Leistung laden. Die Regelung übernimmt dann ja das Überschussladen.
            // Einspeisung vorgaukeln.
            powerValue = -500.0
        } 
    } 

    val json = '{"power": ' + powerValue + '}'
    val mqttActions = getActions("mqtt","mqtt:broker:c73084e70c")
    mqttActions.publishMQTT("shellypro3em-virtual/SENSOR", json, false)

    if (log) logInfo("virtualShelly", "Powervalue: " + powerValue.toString)
end

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre, wie deine Kommentardaten verarbeitet werden.

Durch die weitere Nutzung der Seite wird der Verwendung von Cookies und den Inhalten der Datenschutzerklärung zugestimmt. Weitere Informationen

Die Cookie-Einstellungen auf dieser Website sind auf "Cookies zulassen" eingestellt, um das beste Surferlebnis zu ermöglichen. Wenn du diese Website ohne Änderung der Cookie-Einstellungen verwendest oder auf "Akzeptieren" klickst, erklärst du sich damit einverstanden.

Schließen