FHEM Forum

FHEM - Energiemanagement und Energieerzeugung => Solaranlagen => Thema gestartet von: chri0815 am 01 April 2026, 20:39:11

Titel: Marstek Venus E Modulentwicklung
Beitrag von: chri0815 am 01 April 2026, 20:39:11
Hallo Zusammen
ich habe mir vor kurzem einen Marstek Venus E angeschafft und bin damit auch ganz zufrieden. Nun habe ich entdeckt, dass es da eine Local API Schnittstelle mittels udp gibt. Ich habe mit ChatGpt und der API Beschreibung von Marstek auch schon erste erfolge und kann nun Daten vom Marstek empfangen. Nur ist mein Perl mehr als schlecht und ich benötige Hilfe bei der Implementierung der Set Befehle. Hätte jemand Lust mich dabei zu unterstützen?
Titel: Aw: Marstek Venus E Modulentwicklung
Beitrag von: rudolfkoenig am 02 April 2026, 09:55:20
Ich empfehle eine erste Version des Moduls mit ChatGpt zu erstellen, laut anderen Beitraegen hier im Forum kommt dabei eine funktionsfaehige Version nach ein paar Runden raus.
Ich kann dann gerne das Ergebnis anschauen, und helfen, verbliebene Probleme zu beseitigen.
Titel: Aw: Marstek Venus E Modulentwicklung
Beitrag von: Moli am 06 April 2026, 10:57:14
Guten Morgen, ich habe einen Venus E Gen 2 und einen B2500, mit Python und FHEM habe ich einen Shelly Simulator für den Venus und mit ESP32 C3 Mini (BT) lese ich den B2500.
Den Venus E lese ich mit Adapter und MQTT aus, da ich gerne einen 2 haben möchte, wäre mir aber die Local API lieber.

Habt ihr etwas hinbekommen, wo ich ansetzten kann?
Der Port 30000 ist offen, aber ich bekomme keine Daten.

Falls mir jemand seinen Ansatz im FHEM geben könnte, wäre ich dankbar, vielleicht zickt ja auch der Venus.

Gruß
Titel: Aw: Marstek Venus E Modulentwicklung
Beitrag von: Dracolein am 12 April 2026, 18:09:14
Schau mal hier vorbei, LAN-Verbindung vorausgesetzt https://forum.fhem.de/index.php?topic=144399
Titel: Aw: Marstek Venus E Modulentwicklung
Beitrag von: Moli am 13 April 2026, 08:21:26
Moin. soweit ich weiß, geht die cloud app nicht mehr wenn man mqtt freischalten lässt.

Würde ich gerne vermeiden.

Gruß
Titel: Aw: Marstek Venus E Modulentwicklung
Beitrag von: chri0815 am 19 April 2026, 18:05:31
Hallo Zusammen,
lang hat es gedauert aber ich habe jetzt eine erste Modulversion für den Marstek Venus E. Wer Verbesserungen hat, kann das gern einfügen. Ich habe aus der API Doku nur die Get Befehle übernommen. Zum Konfigurieren die IP Adresse und Den Port 30000 angeben. Das Intervall bei den attr definieren, aber nicht zu klein setzen, eher 10s oder höher.
Nicht vergessen im Marstek die Local API Schnitstelle einschalten!!!
Grüße

######################################################################
# 99_Marstek.pm
# FHEM Modul für Marstek Geräte (Venus C/E/D)
# Liest SOC, Bat-Power, PV-Power, Lade-/Entladeleistung
# Unterstützt Startwert für SOC (soc_start) und Polling
######################################################################

package main;

use strict;
use warnings;
use IO::Socket::INET;
use JSON::PP;
use Time::HiRes qw(gettimeofday);

##########################
# Modul-Initialisierung
##########################
sub Marstek_Initialize {
    my ($hash) = @_;
    $hash->{DefFn}    = "Marstek_Define";
    $hash->{UndefFn}  = "Marstek_Undef";
    $hash->{AttrFn}   = "Marstek_Attr";
    $hash->{GetFn}   = "Marstek_Get";
    $hash->{NotifyFn} = "Marstek_Notify";
    $hash->{AttrList} = "interval";
}

##########################
# Define
##########################
sub Marstek_Define {
    my ($hash, $def) = @_;
    my @args = split(" ", $def);

    return "Usage: define <name> Marstek <IP> <PORT>" unless @args == 4;

    $hash->{IP}       = $args[2];
    $hash->{PORT}     = $args[3];
    $hash->{INTERVAL} = 60;

    InternalTimer(gettimeofday()+1, sub { Marstek_Poll($hash) }, 0);
    return undef;
}

##########################
# Undef
##########################
sub Marstek_Undef {
    my ($hash) = @_;
    RemoveInternalTimer($hash);
    return undef;
}

##########################
# Attribute
##########################
sub Marstek_Attr {
    my ($cmd, $name, $attrName, $attrValue) = @_;
    my $hash = $defs{$name};

    if ($attrName eq "interval" && $attrValue =~ /^\d+$/) {
        $hash->{INTERVAL} = $attrValue;
    }
    return undef;
}

##########################
# Notify
##########################
sub Marstek_Notify {
    my ($hash, $dev) = @_;
    return undef;
}

##########################
# Gemeinsame Request-Funktion
##########################
sub Marstek_DoRequest {
    my ($hash, $method, $units) = @_;
    my $success = 0;
    my $sock = IO::Socket::INET->new(
        PeerAddr => $hash->{IP},
        PeerPort => $hash->{PORT},
        Proto    => 'udp',
        Timeout  => 2
    );

    if ($sock) {
        my $req = {
            id     => 1,
            method => $method,
            params => { id => 0 }
        };

        my $json = encode_json($req);
        $sock->send($json);

        my $resp = "";

        eval {
            local $SIG{ALRM} = sub { die "Timeout\n" };
            alarm 2;
            $sock->recv($resp, 4096);
            alarm 0;
        };

        if ($@ && $@ ne "Timeout\n") {
            Log 3, "Marstek Poll recv error ($method): $@";
        }

        my $data;
        eval { $data = decode_json($resp) };

        if ($@) {
            Log 3, "Marstek JSON decode error ($method): $@";
        }

        if ($data && $data->{result}) {
            for my $key (keys %{$units}) {
                if (exists $data->{result}{$key}) {
                    readingsSingleUpdate(
                        $hash,
                        $key,
                        $data->{result}{$key} . " " . $units->{$key},
                        1
                    );
                    $success = 1;  # mark success if at least one reading updated
                }
            }
        }

        close($sock);
    }
    else {
        readingsSingleUpdate($hash, "state", "timeout", 1);
    }
    return $success;
}

##########################
# Polling
##########################
sub Marstek_Poll {
    my ($hash) = @_;
    return unless $hash;
    my $success = 0;
    eval {
        $success ||= Marstek_DoRequest($hash, "ES.GetStatus", {
            bat_soc       => "%",
            bat_cap       => "Wh",
            pv_power      => "W",
            ongrid_power  => "W",
            offgrid_power => "W",
            total_pv_energy           => "Wh",
            total_grid_output_energy  => "Wh",
            total_grid_input_energy   => "Wh",
            total_load_energy         => "Wh",
        });

        $success ||= Marstek_DoRequest($hash, "Bat.GetStatus", {
            id              => "",
            soc             => "%",
            charge_flag     => "",
            dischrg_flag    => "",
            bat_temp        => "C",
            bat_capacity    => "Wh",
            rated_capacity  => "Wh",
        });

        $success ||= Marstek_DoRequest($hash, "Wifi.GetStatus", {
            id        => "",
            wifi_mac  => "",
            ssid      => "",
            rssi      => "",
            sta_ip    => "",
        });

        $success ||= Marstek_DoRequest($hash, "ES.GetMode", {
            id             => "",
            mode           => "",
            ct_state       => "",
            total_power    => "W",
            input_energy   => "Wh",
            output_energy  => "Wh",
        });
    };

    if ($@) {
        Log 3, "Marstek Poll error: $@";
    }

    # State korrekt setzen
    readingsSingleUpdate($hash, "state", $success ? "ok" : "timeout", 1);


    InternalTimer(
        gettimeofday() + ($hash->{INTERVAL} // 60),
        sub { Marstek_Poll($hash) },
        0
    );
}
##########################
# Get
##########################
sub Marstek_Get {
    my ($hash, $name, $opt, @args) = @_;

    return "\"get $name\" needs at least one argument" unless(defined($opt));

    if ($opt eq "update") {
        Marstek_Poll($hash);
        return "Update triggered";
    }else {
    # IMPORTANT! This defines the list of possible commands
    my $list = "update:noArg";
        return "Unknown argument $opt, choose one of $list";
    }
  return -1;
   }
1;
Titel: Aw: Marstek Venus E Modulentwicklung
Beitrag von: Moli am 20 April 2026, 15:55:40
Hi, vielen Dank fürs Sharen, ich habe es ausprobieren, leider fliegt mir FHEM um die Ohren, erst langsam und dann hat es sogar neu gestartet.
Habe schon 2 Wochen ein Ticket bei Marstek auf, früher waren die echt fix, der Port ist auf, aber es kommen keine Daten.

Gruß

Titel: Aw: Marstek Venus E Modulentwicklung
Beitrag von: Moli am 10 Mai 2026, 10:51:52
Moin, gibt es Marstek noch? Mein Ticket ist seit dem 6.4. ohne jede Reaktion.
Ich weiß, die Webseite ist noch da.
Titel: Aw: Marstek Venus E Modulentwicklung
Beitrag von: enfantterrible am 22 Mai 2026, 10:55:08
cooles modul, soweit geht es, und die readings sehen gut aus. da du alle readings mit Einheit machst, kann ich sie nicht als zahl weiterverwenden denn sie werden als string gelesen, vielleicht packst du die Einheit mit in den Namen des readings, damit sind es dann wieder integer oder float

falls noch wer drueber stolpert, alle marstek geraete melden sich am router mit dem hostnamen "wlan0"
hat man mehrere geraete muss man probieren, wer es nun ist.

wenn wir grad bei marstek sind, gibts schon moeglichkeiten, den CT002 auszulesen?
Titel: Aw: Marstek Venus E Modulentwicklung
Beitrag von: enfantterrible am 22 Mai 2026, 12:52:07
so, interessanterweise habe ich hier einen VenusE 2.0 und einen VenusE 3.0... beim der Version 3.0 geht das modul und bei der 2.0 geht nix, da kommt nur ein timeout
Titel: Aw: Marstek Venus E Modulentwicklung
Beitrag von: Moli am 22 Mai 2026, 14:00:28
Glaub der Venus 2 hat das nur Fake eingebaut :)