Marstek Venus E Gen 3.0 AC gekoppeltes Energiespeichersystem einbinden

ja, danke. Das hatten wir ja schonmal im Vorfeld grob besprochen.
Die Anbindung des TibberPulse über Uni-Meter werde ich angehen, wenn ich mit dem Testen der API durch bin.
Ich melde mich dann nochmal, wenn ich Hilfe brauche.

ich hätte Interesse an Deinen Skripten für die Marstek API. Vielleicht reicht mir das ja schon und ich muss nicht den Umweg über Modbus nehmen……..

Kannst gerne mal hier berichten, wie es mit der local API läuft.
Hatte die auch an getestet, aber lief nicht so Rund bei mir.
Vor allem musst aufpassen mit der Häufigkeit der Anfragen bzw. mit dem Poling,
weil wenn zu häufig Anfragen sendest hängt sich die Schnittstelle auf.

mache ich gerne…
und für @marcusb

  1. Vorbereitung API: UDP-Socket und Registervariable in Symcon anlegen.
  2. Zwei Programme: aufbereiten und senden der Befehle über den UDP-Socket und als 2. PGM= Auswertung der Registervariable mit den Rückmeldungen dewr Venus.
  3. Aktivierung der API in der APP. Hier ist auch ein Link zur API-Dokumentation

Die Programme sind noch unfertig, aber ich kann den aktuellen Status auch hier posten.

hier noch einScreenshot aus der VISU:

Nächste woche kommt mein Venus E 3.0 Speicher. Bei einem Preis inkl. Versand von 989€ konnte ich nicht wiederstehen…

Noch bin ich am grübeln, ob ich den Ecotracker kaufe und auf den Zähler packe. Oder ob ich einen CT002 vom Elektriker einbauen lasse…

ALternativ hätte ich aber eigentlich auch ein Fronius Smartmeter von meiner PV Anlage - das sich wohl auch emulieren lässt.

Bin schon gespannt auf deine Skripte/Anbindung des Marsteks.

Funktioniert das mit dem uni-meter Projekt und einem Fronius wirklich stressfrei?
ESP8266 und ESP32 hätte ich noch rumliegen….

Der CT002 hat den Vorteil, wenn ich es richtig verstanden habe, dass er bis zu 3 Venus steuern kann. Das geht mit dem ShellyPro3EM NICHT (egal ob emuliert über Uni-Meter oder physikalisch eingebaut). Der Shelly kann nur einen steuern.
Ich habe nun Uni-Meter über MQTT an IP-Symcon angebunden. Das läuft seit 3 Tagen problemlos.

Am liebsten wäre mir eine Lösung, mit der ich in IP-Symcon bis zu 3 Venus Speicher über die Energieverteilung laden und entladen könnte. Es gibt wohl schon etwas für HA: GitHub - diegoschlauri/marstek_venus_ha: Home Assistant - Intelligente Batteriesteuerung für Marstek Venus E . Dann würde auch die Einspeisung/Verbrauch wieder korrekt angezeigt werden. Im Moment wird die Venus dem Zähler für den Haushaltsstrom zugerechnet.

Das wird über den Modbus gesteuert. Ich werde also nun im nächsten Schritt die Modbus-Schnittstelle testen.

1 „Gefällt mir“

poste doch gerne mal den aktuellen Status. :grinning_face:

Wenn ich die API Doku richtig gelesen habe, dann geht nur lesen aber kein forcen von laden oder entladen. Richtig?

Achso was ist denn das Ziel der Register Variable?

Hast Du den Standard Port 30000 gewählt? Warum sollte ich und wenn wie ändere ich ihn?

Bei deinem Wunsch ist aber zwingend ein laufendes IP-Symcon nötig.

Da wäre ich “altmodisch”, und würde mir fürs erste einen Ecotracker zum aufstecken kaufen.

Wenn AKKU 2 oder 3 kommen soll, dann in den sauren Apfel beissen und einen Elektriker machen lassen, mit nem CT002

Ich benutze die erste Einstellung (0-9 möglich) der manuellen Steuerung. Dann kann ich Lade-/entladedaten einstellen. Das mache ich im Programm „Ladesteuerung“.

Als Ziel für die Registervariable habe ich mein Programm „Registervariable lesen“ angegeben. Die Registervariable liefert z.B. die Antwort auf Abfragen.

Ja habe den Port 30000 gewählt. Man kann auch einen anderen Port zwischen 49152 und 65535 nehmen. Eingestellt wird er im UDP-Socket.

Meinen aktuellen Programmstand werde ich gleich mal posten.

Hier mal mein aktueller Programmstand für die API:

  1. API über UDP-Socket abfragen:
<?php

//******************************************************************************
// Abfrage der Marstek API
// 24405
//******************************************************************************

include '17825.ips.php';

$id_udp			= 44188;
$id_method		= 27139;

$test			= false;
$meldung		= "";
$sender			= $_IPS['SENDER'];
$webfrontNR		= 40850;
$ip				= "192.168.1.42";
$port			= 30000;

$method			= "method fehlerhaft";



//******************************************************************************
IF($sender == "WebFront")
{
	SetValue($_IPS["VARIABLE"], $_IPS["VALUE"]);    // Variable im WF aktualisieren
	$var	= $_IPS['VARIABLE'];					// auslösende Variable
	$wert	= $_IPS['VALUE'];						// aktueller Wert der Variablen
}


//******************************************************************************
// PGM-Aufruf mit z.B.
// IPS_RunScriptEx(31688, Array("VAR"=>0, "WERT"=>0));
//******************************************************************************
IF($sender == "RunScript")
{
	$var	= $VAR;
	$wert	= $WERT;
}

//******************************************************************************
// 16392
// 27076
// 40518

IF($sender == "TimerEvent")
{
	$var	= $_IPS['EVENT'];
}

//******************************************************************************
IF($_IPS['SENDER'] == "Variable")
{
	$var	= $_IPS['VARIABLE'];		// z.B. Taste Wandsender #37031
	$wert	= $_IPS['VALUE'];			// aktueller Wert der Variablen
}

//******************************************************************************
// hier den Auslöser zum Testen eintragen

IF($sender == "Execute")
{
	$var	= 16392;	
	$wert	= 0.0;
}


//******************************************************************************
// Funktion ausführen
// Auswahl	= $var	z.B. auslösende Variable
// Wert		= $wert z.B. Wert der auslösenden Variable
// mehrfach = case <var>: case <var>:
//******************************************************************************


switch ($var)
{
	case 16392:
		//
		$method			= "ES.GetStatus";
		$json = '{
			"id": 1,
			"method": "ES.GetStatus",
			"params": {
				"id": 0
			}
		}';
		break;
		

	case 27076:
		//
		$method			= "Marstek.GetDevice";
		$json = '{
			"id": 0,
			"method": "Marstek.GetDevice",
			"params": {
				"ble_mac":"009b08a5b73f"
			}
		}';
		break;
		

	case 40518:
		//
		$method			= "Bat.GetStatus";
		$json = '{
			"id": 1,
			"method": "Bat.GetStatus",
			"params": {
				"id": 0
			}
		}';
		break;
		

	default:
		// zum testen von abfragen
		$method			= "ES.GetMode";
		$json = '{
"id": 0,
"method": "ES.GetMode",
"params": {
"id": 0
}
			}
		}';
		break;
}

// methode abfragen
$response		= USCK_SendText($id_udp, $json);
// methode speichern für Auswertung Register-Variable
SetValueString($id_method, $method);





//******************************************************************************
// Testausgabe
//******************************************************************************

if($sender	== "Execute")	$test = true;
if($test	== true)
{
	echo "Rückmeldung: ";
	Var_dump($response);
	echo "json: ";
	Var_dump($json);
	//echo "meldung: ";
	//Var_dump($meldung);
}



//******************************************************************************
// universelle Ausgabe auf verschiedene Medien als Funktionsaufruf
//******************************************************************************

IF($meldung <> "")
{
	//MELDUNG_soundfile($meldung);
	//MELDUNG_usb(10);
	//MELDUNG_logfile($meldung);
	//MELDUNG_prowl('', '1110', $meldung);
	//MELDUNG_webfront($webfrontNR, $meldung);
	//MELDUNG_vu($meldung);
	//MELDUNG_mail();
	//WFC_PushNotification($webfrontNR, 'Marstek', $meldung, '', 0);
}
  1. Die Antwort kommt über die Registervariable und wird in diesem PGMausgewertet:
<?php

//******************************************************************************
// 54713
//******************************************************************************
// Register-Variable = 23078
//******************************************************************************


include '17825.ips.php';

$id_method		= 27139;
$id_soc			= 37451;
$id_firmware	= 40251;
$id_netzpower	= 34007;
$id_temperatur	= 42434;
$id_energie		= 48202;
$id_powerplan	= 30128;
$id_enable		= 54255;
$id_error		= 19033;

$test			= false;
$meldung		= "";
$webfrontNR		= 40850;
$error			= "";

$method			= GetValueString($id_method);

//******************************************************************************
// Werte aus RegisterVariable holen
//******************************************************************************

$data       = $_IPS['VALUE'];   
// JSON bereinigen (falls nötig)
$clean = trim($data);
// JSON in Array wandeln
$data = json_decode($clean, true);

// auf Fehler prüfen
if (!empty($data['error'])) {
    $error	= $method.": ".$data['error']['message'];
	$method	= "Fehler";
}

switch ($method)
{
	case "Fehler":
		//
			$meldung	= "Fehler erkannt: ".$error;
			SetValueInteger($id_powerplan,GetValueInteger($id_netzpower));	// rücksetzen neuer Wert für laden/entladen
		break;

	case "ES.GetStatus":
		// Result-Werte
		$result				= $data['result'];
		$res_id				= $result['id'];
		$soc				= $result['bat_soc'];
		$bat_cap			= $result['bat_cap'];
		$pv_power			= $result['pv_power'];
		$netzpower			= $result['ongrid_power'];
		$offgrid_power		= $result['offgrid_power'];
		$total_pv_energy	= $result['total_pv_energy'];
		$total_grid_output	= $result['total_grid_output_energy'];
		$total_grid_input	= $result['total_grid_input_energy'];
		$total_load_energy	= $result['total_load_energy'];

		$netzpower			= $netzpower-$offgrid_power;

		SetValueInteger($id_soc, $soc);
		SetValueInteger($id_netzpower,$netzpower);
		SetValueInteger($id_powerplan,$netzpower);
		//SetValueInteger($id_netzpower,$netzpower-$offgrid_power);
		break;
		

	case "Marstek.GetDevice":
		// Result-Werte
		$result            = $data['result'];
		$firmware          = $result['ver'];
		/*
		[device] => VenusE 3.0
        [ver] => 144
		[ble_mac] => 009b08a5b73f
		[wifi_mac] => 2c3afd050423
		[wifi_name] => FRITZ!Box WLAN 3170
		[ip] => 192.168.1.42
		*/
		SetValueInteger($id_firmware,$firmware);
		break;
	

	case "Bat.GetStatus":
		// Result-Werte
		$soc				= $data['result']['soc'];
		$temperatur			= $data['result']['bat_temp'];
		$energie			= $data['result']['bat_capacity'];
		
		/*
    [result] => Array
        (
            [id] => 0
            [soc] => 100
            [charg_flag] => 1
            [dischrg_flag] => 1
            [bat_temp] => 17
            [bat_capacity] => 5120
            [rated_capacity] => 5120
        )

)
*/
		SetValueInteger($id_soc, $soc);
		SetValueInteger($id_temperatur,$temperatur);
		SetValueInteger($id_energie,$energie);
		break;
	

	case "ES.SetMode":
		//
		SetValueInteger($id_netzpower,GetValueInteger($id_powerplan));
		break;
	
	default:
		//
		break;
}

if($error<>"")	$error		= date("H:i:s ").$error;			// Fehlermeldung mit Zeit
SetValueString($id_error,$error);								// für Anzeige speichern



//******************************************************************************
// Testausgabe
//******************************************************************************

if($test	== true)
{
	
	echo "Methode: ";
	Var_dump($method);
	echo "Fehler: ";
	var_dump($error);
	echo "meldung: ";
	Var_dump($meldung);

	print_r($data);
}


//******************************************************************************
// universelle Ausgabe auf verschiedene Medien als Funktionsaufruf
//******************************************************************************

IF($meldung <> "")
{
	//MELDUNG_soundfile($meldung);
	//MELDUNG_usb(10);
	//MELDUNG_logfile($meldung);
	//MELDUNG_prowl('', '1110', $meldung);
	//MELDUNG_webfront($webfrontNR, $meldung);
	//MELDUNG_vu($meldung);
	//MELDUNG_mail();
	//WFC_PushNotification($webfrontNR, 'Marstek', $meldung, '', 0);
}

Für die Lade-/Entladesteuerung mein 3. PGM:

<?php

//******************************************************************************
// Steuerung der Venus zum Laden/Entladen
// 36589
//******************************************************************************

include '17825.ips.php';

$id_udp			= 44188;
$id_method		= 27139;
$id_preis		= 51164;
$id_powerist	= 55934;
$id_powerplan	= 30128;
$id_soc			= 37451;
$id_enable		= 54255;

$test			= false;
$meldung		= "";
$sender			= $_IPS['SENDER'];
$webfrontNR		= 40850;
$ip				= "192.168.1.42";
$port			= 30000;
//$response		= false;

// Variable für json
$json			= "";
$method       = "ES.SetMode";
$mode         = "Manual";
$time_num     = 0;
$start_time   = "00:00";
$end_time     = "23:59";
$week_set     = 127;
$power        = -200;		// wird neu berechnet, negativ = Akku laden
$enable       = 1;


//******************************************************************************
// logik für Laden/entladen/inaktiv = Eigenverbrauch (Nulleinspeisung)
//******************************************************************************

$powerist	= (int)GetValueFloat($id_powerist);				// power vom Tibber-Pulse
$powerplan	= GetValueInteger($id_powerplan)+$powerist;		// Berechnung Nullwert
$power		= round($powerplan / 10) * 10;					// auf 10-er runden

if($power > 800)	$power	= 800;							// max 800 Watt einspeisen
if(($power < 0) and ($power > -100))	$power	= 0;		// min. 100 Watt aus dem Netz speichern / Ladesteuerung deaktiviert
if($power < -2000)	$power	= -2000;						// max 2000 Watt aus dem Netz speichern



// wenn SOC < x%, dann keine weitere Entladung
if($power > 0){
	$soc		= GetValueInteger($id_soc);
	if($soc < 15)	$enable		= 0;						// Steuerung deaktivieren
}

$json	= Venus_ES_SetMode($id_udp,$id_method,$id_powerplan,$power,$enable);	// Befehl aufbereiten und senden

SetValueInteger($id_enable,$enable);						// Status speichern


//******************************************************************************
// Testausgabe
//******************************************************************************

if($sender	== "Execute")	$test = true;
if($test	== true)
{
	echo "manuelle Steuerung: ";
	Var_dump($enable);
	echo "Power neu: ";
	Var_dump($power);
	echo "Power Zähler: ";
	Var_dump($powerist);
	echo "json: ";
	Var_dump($json);
	//echo "meldung: ";
	//Var_dump($meldung);
}



//******************************************************************************
// universelle Ausgabe auf verschiedene Medien als Funktionsaufruf
//******************************************************************************

IF($meldung <> "")
{
	//MELDUNG_soundfile($meldung);
	//MELDUNG_usb(10);
	//MELDUNG_logfile($meldung);
	//MELDUNG_prowl('', '1110', $meldung);
	//MELDUNG_webfront($webfrontNR, $meldung);
	//MELDUNG_vu($meldung);
	//MELDUNG_mail();
	//WFC_PushNotification($webfrontNR, 'Marstek', $meldung, '', 0);
}







//******************************************************************************
// json aus Variablen erstellen und senden
//******************************************************************************

function Venus_ES_SetMode($id_udp,$id_method,$id_powerplan,$power,$enable){
	$method       = "ES.SetMode";
	$mode         = "Manual";
	$time_num     = 0;
	$start_time   = "00:00";
	$end_time     = "23:59";
	$week_set     = 127;
	//$power        = -200;		// wird neu berechnet, negativ = Akku laden
	//$enable       = 1;
	// Array zusammenbauen
	$data = [
		"id" => 1,
		"method" => $method,
		"params" => [
			"id" => 0,
			"config" => [
				"mode" => $mode,
				"manual_cfg" => [
					"time_num"   => $time_num,
					"start_time" => $start_time,
					"end_time"   => $end_time,
					"week_set"   => $week_set,
					"power"      => $power,
					"enable"     => $enable
				]
			]
		]
	];

	// JSON erzeugen
	$json = json_encode($data, JSON_PRETTY_PRINT);
	// json senden
	$response		= USCK_SendText($id_udp, $json);	// Daten an Venus senden
	SetValueString($id_method, $method);				// methode speichern für Auswertung Register-Variable
	SetValueInteger($id_powerplan, $power);				// Einstellung speichern / wird durch ES.GetStatus aktualisiert
	return $json;
}

und hier noch ein Auszug aus Symcon-Objektbaum:

Bitte nur als Anregung/Muster verstehen. Das sind meine ersten Versuche.
Die Variablen-ID’s müsst ihr natürlich anpassen.
Fragen dazu beantworte ich natürlich gerne.

Hallo zusammen,

Ich bin auch stolzer Besitzer eines Marstek Venus E Gen 3.0.

Da ich Schwierigkeiten mit der LAN Verbindung hatte, habe ich den Support über die Marstek App kontaktiert.

Der Support hat mir eine neue Firmware freigeschaltet, die ich über die App installiert habe.

Die neue Version hat die Bezeichnung V144.

Seither geht nicht nur die LAN Verbindung einwandfrei, sondern ich habe auch noch Zugriff auf ModBus über TCP auf Port 502 und der IP über den LAN Anschluss.

Per WLAN Verbindung hat man keinen Zugriff auf den Port 502.

Ich konnte alle für mich nötigen Register über TCP abrufen.

So hoffe ich, dass das hier im Thread seinen Platz hat und Ihr auch das neueste Firmware Update anfragt und erhaltet. Das vereinfacht die Sache ein wenig.

Gruß, Nico.

Danke für den Tipp Nico. Habe ich angefragt. Kann ich das Modbustemplate aus dem thread hier nutzen oder sind die Modbusadressen für die V3 anders?

Konntest Du damit die Venus in den Energiemanager integrieren? Ich würde mir gerne noch eine 2. anschaffen damit ich auf 10kw/h Kapazität komme. Dann kann ich nur leider nicht mehr das Uni-Meter nutzen, denn zwei laden aber nur mit den Marstek CT Messgeräten zuverlässig. Vielleicht gibt es auch die Möglichkeit diese per Modbus direkt anzusteuern z.Bsp. dann geregelt über den Energiemanager.

Habe jemanden gefunden, der eine intelligente Batteriesteuerung für HA gebaut hat: GitHub - diegoschlauri/marstek_venus_ha: Home Assistant - Intelligente Batteriesteuerung für Marstek Venus E
Das Prinzip müsste sich doch auch in Symcon über den Energiemanager implementieren lassen.

Wie machst Du das?

Hallo,
also ich habe in der App ebenfalls das Update angefordert.
War zuvor auf V139 und konnte damit mittels Modbus Adapter am RS485 Anschluss die Werte auslesen und den Akku steuern.
Nun habe ich die V144 erhalten und kann bestätigen, dass auch bei mir nun Modbus über den LAN Anschluß auf Port 502 funktioniert.


und hier noch meine Modbus Vorlage die mit Venus E3 funktioniert und die Nico von mir erhalten hat und auch bei Ihm funktioniert.
Symcon-Marstek-Venus-E3-modbus.json (11,7 KB)
Vielleicht noch als Anmerkung, ich habe nicht alle Register drin sondern nur die mir wichtig waren bzw. sind.

klasse Vielen Dank. Habe auch gerade auf 1.44 upgedatet. Seltsamerweise findet die Venus den emulierten Shelly nicht mehr, sobald ich das Ethernetkabel verbinde. Habt ihr das auch?

Wenn das Update durch ist, habe ich bei mir das LAN Kabel ausgestöpselt, dann den Akku am Button ausgeschaltet. Habe ein wenig gewartet, dann LAN Kabel wieder dran und über den Button wieder eingeschaltet. Danach ging alles.
Bevor ich das gemacht habe, hat der Akku auch etwas gezickt bzw. die LAN Verbindung.

Noch ein wichtiger Hinweis:
Wenn in meiner Modbus Vorlage RS485 auf On stellst, hat Modbus Regelung Vorrang. Das bedeutet alles andere funktioniert nicht mehr. Also CT ist dann Off. Eigenverbrauch ist Off usw. Das liegt aber nicht an der Vorlage, sondern die Modbus Register vom Akku sind so konzipiert. Rs Control Mode On heisst Übersteuern aller Automatissmen des Akkus, da musst von Hand Regeln was Du haben willst.
Ich habe die von mir verwendeten Register aus dieser Tabelle entnommen:

Wichtig ist der Satz ganz am Ende.
Note: For access to registers in the 42000–42999 range, the battery must be set to RS485 control mode.

Hallo,
ich würde nun auch gerne mal die modbus-Anbindung testen. Da ich noch nie mit modbus gearbeitet habe erstmal eine Anfängerfrage:
Welche Instanzen muss ich für die Anbindung anlegen?


Den Rest versuche ich dann erstmal selbständig.
Danke, Peter

Verwende das Modbus Gerät und dort kannst dann die Vorlage importieren.
Dann musst nur noch den Übergeordneten Gateway Konfigurieren am einfachsten direkt aus der Instanz heraus.

Im Gateway “Modbus TCP” und Geräte-Id auf “1” belassen.

Im übergeordneten Client Socket Port 502 eintragen.

Die Vorlage von drdigital funktioniert super. Für den Energie Manager musste ich noch für die Batterie (BAT-Soc) auch ein Werteprofil mit % hinterlegen.

Da es regnet konnte ich noch nicht testen, ob der Akku nun auch über den Energiemanager lädt.