Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. ioBroker Allgemein
    4. Shelly 3PM Pro Emulator

    NEWS

    • Neuer Blog: Fotos und Eindrücke aus Solingen

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    Shelly 3PM Pro Emulator

    This topic has been deleted. Only users with topic management privileges can see it.
    • miwi
      miwi last edited by

      Hallo,

      ich habe mir einen Marstek Venus Stromspeicher zugelegt und dieser kommuniziert unter anderem mit dem Shelly 3PM Pro zum Steuern des Lade- und Entladevorgangs.
      Da ich bereits einen Stromzähler im Zählerschrank verbaut habe und dieser über den Modbus-Adapter die aktuellen Stromwerte liefert, wäre es aus meiner Sicht unnötig einen zweiten Stromzähler einzubauen.

      Ich habe auch schon die Projekte uni-meter und B2500 meter in Github gefunden, wovon letzteres sogar als Homeassistant-Addon verfügbar ist, aber ist gibt keine native IOBroker Version.

      Frage deshalb: Gibt es einen Weg wie man Werte vom Modbus Adapter / eines IOBroker angelegten Objekt in ein virtuelles W-lan Signal verwandelt, dass einen Shelly 3PM Pro emuliert?

      Grüße

      miwi

      R 1 Reply Last reply Reply Quote -1
      • R
        Ray 1 @miwi last edited by

        @miwi

        Ich hänge mich hier mal mit dran, da ich die gleiche Frage bzw. ein ähnliches Problem habe.

        1 Reply Last reply Reply Quote -1
        • mcm1957
          mcm1957 last edited by mcm1957

          Ich schätze dass das was für euch sein könnte:

          https://github.com/sdeigm/uni-meter

          OK - grad erst gesehen, dass unimeter eh schon genannt wurde.

          1 Reply Last reply Reply Quote 0
          • M
            MikeRow last edited by

            Das GitHub B2500 Projekt hat eine Möglichkeit IOB Datenpunkte anzubinden. In diese Datenpunkte schreibst du deine Werte vom Zähler.

            1 Reply Last reply Reply Quote 0
            • P
              ple last edited by

              @mikerow sagte in Shelly 3PM Pro Emulator:

              Das GitHub B2500 Projekt hat eine Möglichkeit IOB Datenpunkte anzubinden. In diese Datenpunkte schreibst du deine Werte vom Zähler.

              Puh, weiß jemand was aktuell das einfachste ist den akku zu steuern? so wie ich das gelesen habe entweder mit ne shelly, oder shelly emulieren, oder Modbus und selbst steuern.
              Hat jemand da schon was im Einsatz und kann berichten, was am besten wäre?

              Gruß und Besten Dank.

              G 1 Reply Last reply Reply Quote 0
              • G
                gutgut30 @ple last edited by gutgut30

                @ple Das absolut einfachste ist natürlich der Marstek Zähler CT001 .. 003. Dann der Shelly.

                @miwi: was spricht denn gegen Uni-Meter? Das ist doch alles virtuell. Du musst nur einen Container in Docker installieren.
                Oder ist dein aktueller, per Mod-Bus ausgelesener Zähler, nicht kompatibel mit Uni-Meter? Wobei uni-Meter ja auch iob dp auslesen kann. Ist doch absolut genau das, was du suchst.

                1 Reply Last reply Reply Quote 0
                • K
                  kla960 last edited by

                  Interessante Lösung dieses Uni-Meter. Habe es mal parallel zum ioBroker im Docker erstellt und versucht das Uni-Meter für input Tasmota (habe ein BitShake IR SmartReader) zu konfigurieren.

                  Startet schon mal ohne Fehlermeldung. Allerdings bin ich mir nicht sicher, ob die Tasmotasettings auch Werte liefern.

                  So ein IR SmartReader ist auf jeden Fall billiger als ein Shelly, den ggf. notwendigen Elektriker für den Einbau kann man sich sparen und Spaß macht so eine Bastelei auch 😉

                  1 Reply Last reply Reply Quote 0
                  • K
                    kla960 last edited by Samson71

                    Kämpfe zwar noch damit den docker container vernünftig einzurichten. Aber Werte liefert der Shelly Emulator

                    {"id":0,"a_current":0.54,"a_voltage":230,"a_act_power":124.67,"a_aprt_power":124.67,"a_pf":1,"a_freq":50,"b_current":0.54,"b_voltage":230,"b_act_power":124.67,"b_aprt_power":124.67,"b_pf":1,"b_freq":50,"c_current":0.54,"c_voltage":230,"c_act_power":124.67,"c_aprt_power":124.67,"c_pf":1,"c_freq":50,"total_current":1.62,"total_act_power":374.01,"total_aprt_power":374.01}
                    

                    Nutzt hier irgendwer Uni-Meter????

                    Mod-Edit
                    Bitte Codetags </> benutzen!

                    1 Reply Last reply Reply Quote 0
                    • A
                      australien last edited by

                      ich habe zwar den uni-meter im docker am laufen, aber die Marstek APP 1.6.43 findet diesen nicht.

                      uni-meter {
                        output = "uni-meter.output-devices.shelly-pro3em"
                        input = "uni-meter.input-devices.shelly-3em"
                      
                        http-server {
                              port:4711
                        }
                      
                        output-devices {
                          shelly-pro3em {
                            mac = "DC4F22764880"
                            hostname = "shellypro3em-DC4F22764880"
                            port = 4711
                            udp-port = 1010
                            udp-interface ="0.0.0.0"
                            min-sample-period = 5000ms
                          }
                         }
                      
                        input-devices {
                          shelly-3em {
                            url = "http://10.xx.0.xxx"
                          }
                        }
                      }
                      
                      G A 2 Replies Last reply Reply Quote 0
                      • G
                        Gismoh @australien last edited by Gismoh

                        Komme auch nicht wirklich weiter, habe ein JS-Skript für den IOBroker mit Hilfe von einer KI gebaut,
                        Der Marstek Venus E kann sich mit dem Simulierten Shelly 3emPro verbinden, dort werden auch Realistische Werte angezeigt, wenn über 100Watt.
                        Hatte vorher alle drei Phasen ausprobiert, habe ich allerdings nicht hinbekommen.

                        Bin wieder bei meinem Problem, was ich auch bei anderen Versuchen hatte:
                        Wenn der Marstek sieht, er soll entladen, macht er das nicht zum reelen Wert, also z.B. 500 Watt, sondern fährt auf die Begrenzung in der App (800 Watt).
                        Laut Anzeige 797 Watt, und speist so 300 Watt in das Netz ein, was ich natürlich nicht so erwünsche.
                        (5 Tage investiert und das Ding macht immer noch was es will 🆘😭)

                        Hat dort jemand eine Lösung dafür?
                        (Firmware v152)

                        G 1 Reply Last reply Reply Quote 0
                        • G
                          Gismoh @Gismoh last edited by Gismoh

                          Nun kommen alle drei Phasen in der App an.
                          Weis aber noch nicht wie sich der Venus-E verhält, aktuelle sind die Speicher voll, und haben PV-Überschuss.

                          G 1 Reply Last reply Reply Quote 0
                          • G
                            Gismoh @Gismoh last edited by Gismoh

                            LoL, habe nun mal den anderen Marstek Venus e auf Eigenverbrauch gesetzt, dort regelt der Mustek nun selbstständig 😉
                            Muss nur noch beobachten wie, aber denke darauf habe ich mit echten Werten eh keinen Einfluss,
                            aber der JS scheint auszureichen.

                            // ===================================================
                            // Shelly EM3 Pro Emulation für Marstek Venus E (MIT ECHTEN SHELLY-WERTEN!)
                            // by Gismoh
                            // ===================================================
                            
                            // MARSTEK KONFIGURATION - HIER ANPASSEN!
                            var MARSTEK_CONFIG = {
                                useAbsoluteValues: false,       // Für CT001 Protokoll-Kompatibilität
                                invertSignForTest: false,       // ✅ RICHTIGE VORZEICHEN (wie echter Shelly!) - TESTWEISE AUF TRUE SETZEN!
                                clampNegativeToZero: false,     // Alternative: negative Werte auf 0
                                separateInputOutput: true,      // Separate Input/Output Behandlung
                                debugMode: false,               // ❌ Debug-Modus DEAKTIVIERT (reduziert Spam)
                                logInterval: 30000,             // Nur alle 30 Sekunden loggen
                                logOnlyChanges: true,           // Nur bei Wert-Änderungen loggen
                                minChangeThreshold: 50          // Mindestens 50W Änderung für Log
                            };
                            
                            // Konfiguration - Anpassen an deine Shelly EM3 Instanz
                            var SHELLY_EM3_INSTANCE = 'shelly.0.SHEM-3#XXXXXXXXXX'; // Deine Shelly EM3 Instanz ID
                            var EMULATION_PORT = 1010; // Port für die Emulation
                            var UPDATE_INTERVAL = 5000; // Update-Intervall in ms
                            
                            // Module laden
                            var http = require('http');
                            var url = require('url');
                            var dgram = require('dgram');
                            var os = require('os');
                            
                            // Globale Variablen für die Messwerte
                            var currentPowerTotal = 0;
                            var currentPowerL1 = 0;
                            var currentPowerL2 = 0;
                            var currentPowerL3 = 0;
                            
                            // ✅ ECHTE MESSWERTE FÜR ALLE PHASEN (AUS SHELLY DATEN!)
                            var currentCurrentL1 = 0;
                            var currentCurrentL2 = 0;
                            var currentCurrentL3 = 0;
                            var currentVoltageL1 = 230.0;
                            var currentVoltageL2 = 230.0;
                            var currentVoltageL3 = 230.0;
                            var currentPowerFactorL1 = 1.0;
                            var currentPowerFactorL2 = 1.0;
                            var currentPowerFactorL3 = 1.0;
                            
                            var energyTotal = 0;
                            var energyL1 = 0;
                            var energyL2 = 0;
                            var energyL3 = 0;
                            var energyReturnedL1 = 0;
                            var energyReturnedL2 = 0;
                            var energyReturnedL3 = 0;
                            
                            // Performance-Variablen
                            var lastLogTime = 0;
                            var requestCounter = 0;
                            var lastLoggedPower = 0;     // ✅ Für Change-Detection
                            var lastDetailedLog = 0;     // ✅ Für seltene Detail-Logs
                            
                            // Server-Instanzen
                            var serverInstance = null;
                            var udpSocket = null;
                            
                            function calculateMarstekPower(originalPower) {
                                var result = {
                                    originalPower: originalPower,
                                    marstekPower: originalPower,   // Für CT-Anzeige (immer Echtwert)
                                    limitedPower: originalPower,   // Wird unten korrigiert
                                    powerInput: 0,
                                    powerOutput: 0,
                                    direction: originalPower >= 0 ? 'Bezug' : 'Einspeisung',
                                    explanation: ''
                                };
                            
                                // ✅ VORZEICHEN UMKEHREN FÜR TEST
                                if (MARSTEK_CONFIG.invertSignForTest) {
                                    result.marstekPower = -originalPower;
                                    result.direction = result.marstekPower >= 0 ? 'Bezug (umgekehrt)' : 'Einspeisung (umgekehrt)';
                                    result.explanation = 'Vorzeichen umgekehrt für Venus E Test';
                                }
                            
                                // Begrenzung für Akkuverhalten (auf umgekehrten Wert anwenden)
                                var powerForLimit = result.marstekPower;
                                if (powerForLimit < 0) {
                                    // Einspeisung → Akku darf max. mit 1000 W laden
                                    result.limitedPower = Math.max(powerForLimit, -1000);
                                    result.explanation += ' - Ladebegrenzung auf max 1000W';
                                } else if (powerForLimit > 0) {
                                    // Netzbezug → Akku darf max. mit 1000 W entladen
                                    result.limitedPower = Math.min(powerForLimit, 1000);
                                    result.explanation += ' - Entladebegrenzung auf max 1000W';
                                } else {
                                    result.limitedPower = 0;
                                    result.explanation += ' - Kein Netzfluss – keine Aktion';
                                }
                            
                                if (MARSTEK_CONFIG.separateInputOutput) {
                                    if (result.marstekPower >= 0) {
                                        result.powerInput = result.marstekPower;
                                        result.powerOutput = 0;
                                    } else {
                                        result.powerInput = 0;
                                        result.powerOutput = Math.abs(result.marstekPower);
                                    }
                                }
                            
                                // ✅ NUR LOGGEN BEI GROßEN ÄNDERUNGEN
                                var powerChange = Math.abs(result.marstekPower - lastLoggedPower);
                                if (MARSTEK_CONFIG.debugMode && powerChange > MARSTEK_CONFIG.minChangeThreshold) {
                                    console.log('POWER CHANGE: ' + lastLoggedPower + 'W → ' + result.marstekPower + 'W (' + result.direction + ')');
                                    lastLoggedPower = result.marstekPower;
                                }
                            
                                return result;
                            }
                            
                            // ✅ KORRIGIERTE Funktion zum Lesen der ECHTEN Shelly EM3 Pro Werte
                            function readShellyValues() {
                                try {
                                    // ✅ HAUPTQUELLE: Tibber Pulse (direkt am Stromzähler)
                                    var tibberPower = getState('tibberlink.0.LocalPulse.0.Power').val;
                                    
                                    // ✅ ECHTE SHELLY EM3 PRO WERTE AUSLESEN
                                    var shellyL1Power = getState(SHELLY_EM3_INSTANCE + '.Emeter0.Power').val || 0;
                                    var shellyL2Power = getState(SHELLY_EM3_INSTANCE + '.Emeter1.Power').val || 0;
                                    var shellyL3Power = getState(SHELLY_EM3_INSTANCE + '.Emeter2.Power').val || 0;
                                    
                                    // ✅ ECHTE CURRENT-WERTE (Ampere)
                                    var shellyL1Current = getState(SHELLY_EM3_INSTANCE + '.Emeter0.Current').val || 0;
                                    var shellyL2Current = getState(SHELLY_EM3_INSTANCE + '.Emeter1.Current').val || 0;
                                    var shellyL3Current = getState(SHELLY_EM3_INSTANCE + '.Emeter2.Current').val || 0;
                                    
                                    // ✅ ECHTE POWER FACTOR WERTE
                                    var shellyL1PF = getState(SHELLY_EM3_INSTANCE + '.Emeter0.PowerFactor').val || 1.0;
                                    var shellyL2PF = getState(SHELLY_EM3_INSTANCE + '.Emeter1.PowerFactor').val || 1.0;
                                    var shellyL3PF = getState(SHELLY_EM3_INSTANCE + '.Emeter2.PowerFactor').val || 1.0;
                                    
                                    // ✅ ECHTE ENERGIE-WERTE (Wh)
                                    var shellyL1Energy = getState(SHELLY_EM3_INSTANCE + '.Emeter0.Total').val || 0;
                                    var shellyL2Energy = getState(SHELLY_EM3_INSTANCE + '.Emeter1.Total').val || 0;
                                    var shellyL3Energy = getState(SHELLY_EM3_INSTANCE + '.Emeter2.Total').val || 0;
                                    
                                    // ✅ ECHTE RÜCKSPEISUNG-WERTE (Wh)
                                    var shellyL1Returned = getState(SHELLY_EM3_INSTANCE + '.Emeter0.Total_Returned').val || 0;
                                    var shellyL2Returned = getState(SHELLY_EM3_INSTANCE + '.Emeter1.Total_Returned').val || 0;
                                    var shellyL3Returned = getState(SHELLY_EM3_INSTANCE + '.Emeter2.Total_Returned').val || 0;
                                    
                                    var shellyTotal = shellyL1Power + shellyL2Power + shellyL3Power;
                                    
                                    // ✅ PLAUSIBILITÄTSPRÜFUNG für Shelly-Werte
                                    if (Math.abs(shellyL1Power) > 5000 || Math.abs(shellyL2Power) > 5000 || Math.abs(shellyL3Power) > 5000) {
                                        console.log('⚠️ Unplausible Shelly-Werte detected: L1=' + shellyL1Power + ', L2=' + shellyL2Power + ', L3=' + shellyL3Power);
                                        return; // Keine Update bei unrealistischen Werten
                                    }
                                    
                                    // ✅ SICHERHEITSPRÜFUNG: Plausible Werte verwenden
                                    if (tibberPower !== null && tibberPower !== undefined && Math.abs(tibberPower) < 15000) {
                                        currentPowerTotal = tibberPower;
                                        if (MARSTEK_CONFIG.debugMode) {
                                            console.log('Verwende Tibber Pulse: ' + tibberPower + 'W');
                                        }
                                    } else {
                                        currentPowerTotal = shellyTotal;
                                        console.log('FALLBACK zu Shelly: ' + shellyTotal + 'W (Tibber: ' + tibberPower + ')');
                                    }
                                    
                                    // ✅ ALLE ECHTEN WERTE ÜBERNEHMEN
                                    currentPowerL1 = shellyL1Power;
                                    currentPowerL2 = shellyL2Power;
                                    currentPowerL3 = shellyL3Power;
                                    
                                    currentCurrentL1 = shellyL1Current;
                                    currentCurrentL2 = shellyL2Current;
                                    currentCurrentL3 = shellyL3Current;
                                    
                                    currentPowerFactorL1 = shellyL1PF;
                                    currentPowerFactorL2 = shellyL2PF;
                                    currentPowerFactorL3 = shellyL3PF;
                                    
                                    // ✅ VOLTAGE BERECHNUNG (falls verfügbar, sonst aus Power/Current)
                                    if (shellyL1Current > 0.1) {
                                        currentVoltageL1 = Math.abs(shellyL1Power / shellyL1Current / shellyL1PF);
                                    } else {
                                        currentVoltageL1 = 230.0; // Fallback
                                    }
                                    
                                    if (shellyL2Current > 0.1) {
                                        currentVoltageL2 = Math.abs(shellyL2Power / shellyL2Current / shellyL2PF);
                                    } else {
                                        currentVoltageL2 = 230.0; // Fallback
                                    }
                                    
                                    if (shellyL3Current > 0.1) {
                                        currentVoltageL3 = Math.abs(shellyL3Power / shellyL3Current / shellyL3PF);
                                    } else {
                                        currentVoltageL3 = 230.0; // Fallback
                                    }
                                    
                                    // ✅ ENERGIE-WERTE
                                    energyL1 = shellyL1Energy;
                                    energyL2 = shellyL2Energy;
                                    energyL3 = shellyL3Energy;
                                    energyTotal = energyL1 + energyL2 + energyL3;
                                    
                                    energyReturnedL1 = shellyL1Returned;
                                    energyReturnedL2 = shellyL2Returned;
                                    energyReturnedL3 = shellyL3Returned;
                                    
                                    if (MARSTEK_CONFIG.debugMode) {
                                        console.log('📊 ECHTE SHELLY WERTE:');
                                        console.log('  Power: L1=' + currentPowerL1.toFixed(1) + 'W, L2=' + currentPowerL2.toFixed(1) + 'W, L3=' + currentPowerL3.toFixed(1) + 'W, Total=' + currentPowerTotal.toFixed(1) + 'W');
                                        console.log('  Current: L1=' + currentCurrentL1.toFixed(2) + 'A, L2=' + currentCurrentL2.toFixed(2) + 'A, L3=' + currentCurrentL3.toFixed(2) + 'A');
                                        console.log('  Voltage: L1=' + currentVoltageL1.toFixed(1) + 'V, L2=' + currentVoltageL2.toFixed(1) + 'V, L3=' + currentVoltageL3.toFixed(1) + 'V');
                                        console.log('  PowerFactor: L1=' + currentPowerFactorL1.toFixed(2) + ', L2=' + currentPowerFactorL2.toFixed(2) + ', L3=' + currentPowerFactorL3.toFixed(2));
                                    }
                                    
                                } catch (error) {
                                    console.error('❌ Fehler beim Lesen der Shelly Werte:');
                                    console.error(error);
                                }
                            }
                            
                            // Lokale IP-Adresse ermitteln
                            function getLocalIP() {
                                try {
                                    var interfaces = os.networkInterfaces();
                                    for (var interfaceName in interfaces) {
                                        var addresses = interfaces[interfaceName];
                                        for (var i = 0; i < addresses.length; i++) {
                                            var address = addresses[i];
                                            if (address.family === 'IPv4' && !address.internal) {
                                                return address.address;
                                            }
                                        }
                                    }
                                } catch (e) {
                                    console.log('Fehler beim Ermitteln der IP-Adresse');
                                }
                                return '192.168.1.100';
                            }
                            
                            // ✅ MARSTEK VENUS E FORMAT - EXAKT 4 FELDER AUF ROOT-EBENE!
                            function createMarstekVenusEResponse() {
                                var powerCalc = calculateMarstekPower(currentPowerTotal);
                                
                                // ✅ GENAU DAS WAS MARSTEK ERWARTET - NUR 4 FELDER!
                                var response = {
                                    "a_act_power": currentPowerL1,
                                    "b_act_power": currentPowerL2,
                                    "c_act_power": currentPowerL3,
                                    "total_act_power": powerCalc.marstekPower
                                };
                                
                                // ✅ SICHERSTELLEN DASS NUR 4 FELDER GESENDET WERDEN
                                if (Object.keys(response).length !== 4) {
                                    console.log('⚠️ WARNUNG: Response hat ' + Object.keys(response).length + ' Felder statt 4!');
                                }
                                
                                return response;
                            }
                            
                            // ✅ ECHTE Shelly.GetStatus Response (VERSCHACHTELTE Struktur)
                            function createShellyGetStatusResponse() {
                                var demand = currentPowerTotal;
                                var correctedPower = demand;
                                var powerCalc = calculateMarstekPower(correctedPower);
                                
                                // ✅ NUR LOGGEN BEI DEBUG MODE UND GROßEN ÄNDERUNGEN
                                if (MARSTEK_CONFIG.debugMode && Math.abs(correctedPower - lastLoggedPower) > MARSTEK_CONFIG.minChangeThreshold) {
                                    console.log('📊 Shelly.GetStatus ECHTE WERTE: A=' + currentPowerL1.toFixed(1) + 'W/' + currentCurrentL1.toFixed(2) + 'A, B=' + currentPowerL2.toFixed(1) + 'W/' + currentCurrentL2.toFixed(2) + 'A, C=' + currentPowerL3.toFixed(1) + 'W/' + currentCurrentL3.toFixed(2) + 'A');
                                }
                            
                                // ✅ ECHTE SHELLY.GETSTATUS STRUKTUR - MIT 100% ECHTEN 3-PHASEN WERTEN!
                                return {
                                    "ble": {},
                                    "cloud": {"connected": true},
                                    "em:0": {
                                        "id": 0,
                                        "a_current": currentCurrentL1,          // ✅ ECHTER Current-Wert Phase A!
                                        "a_voltage": currentVoltageL1,          // ✅ ECHTER Voltage-Wert Phase A!
                                        "a_act_power": currentPowerL1,          // ✅ ECHTER Power-Wert Phase A!
                                        "a_aprt_power": Math.abs(currentPowerL1),
                                        "a_pf": currentPowerFactorL1,           // ✅ ECHTER PowerFactor Phase A!
                                        "a_freq": 50.0,
                                        
                                        "b_current": currentCurrentL2,          // ✅ ECHTER Current-Wert Phase B!
                                        "b_voltage": currentVoltageL2,          // ✅ ECHTER Voltage-Wert Phase B!
                                        "b_act_power": currentPowerL2,          // ✅ ECHTER Power-Wert Phase B!
                                        "b_aprt_power": Math.abs(currentPowerL2),
                                        "b_pf": currentPowerFactorL2,           // ✅ ECHTER PowerFactor Phase B!
                                        "b_freq": 50.0,
                                        
                                        "c_current": currentCurrentL3,          // ✅ ECHTER Current-Wert Phase C!
                                        "c_voltage": currentVoltageL3,          // ✅ ECHTER Voltage-Wert Phase C!
                                        "c_act_power": currentPowerL3,          // ✅ ECHTER Power-Wert Phase C!
                                        "c_aprt_power": Math.abs(currentPowerL3),
                                        "c_pf": currentPowerFactorL3,           // ✅ ECHTER PowerFactor Phase C!
                                        "c_freq": 50.0,
                                        
                                        "n_current": null,                      // ✅ Wie echter Shelly (oft null)
                                        "total_current": currentCurrentL1 + currentCurrentL2 + currentCurrentL3, // ✅ Summe der echten Ströme
                                        "total_act_power": powerCalc.marstekPower,
                                        "total_aprt_power": Math.abs(powerCalc.marstekPower),
                                        "user_calibrated_phase": []
                                    },
                                    "emdata:0": {
                                        "id": 0,
                                        "a_total_act_energy": energyL1,         // ✅ ECHTE Energie Phase A
                                        "a_total_act_ret_energy": energyReturnedL1, // ✅ ECHTE Rückspeisung Phase A
                                        "b_total_act_energy": energyL2,         // ✅ ECHTE Energie Phase B
                                        "b_total_act_ret_energy": energyReturnedL2, // ✅ ECHTE Rückspeisung Phase B
                                        "c_total_act_energy": energyL3,         // ✅ ECHTE Energie Phase C
                                        "c_total_act_ret_energy": energyReturnedL3, // ✅ ECHTE Rückspeisung Phase C
                                        "total_act": energyTotal,               // ✅ ECHTE Gesamt-Energie
                                        "total_act_ret": energyReturnedL1 + energyReturnedL2 + energyReturnedL3 // ✅ ECHTE Gesamt-Rückspeisung
                                    },
                                    "eth": {"ip": getLocalIP()},
                                    "modbus": {},
                                    "mqtt": {"connected": false},
                                    "sys": {
                                        "mac": "XXXXXXXXXXXX",
                                        "restart_required": false,
                                        "time": new Date().toTimeString().split(' ')[0],
                                        "unixtime": Math.floor(Date.now() / 1000),
                                        "uptime": 12345,
                                        "ram_size": 255736,
                                        "ram_free": 76476,
                                        "fs_size": 524288,
                                        "fs_free": 188416,
                                        "cfg_rev": 12,
                                        "kvs_rev": 1
                                    }
                                };
                            }
                            
                            // HTTP Server erstellen
                            var server = http.createServer(function(req, res) {
                                var parsedUrl = url.parse(req.url, true);
                                
                                // CORS Headers setzen
                                res.setHeader('Access-Control-Allow-Origin', '*');
                                res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
                                res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
                                
                                if (req.method === 'OPTIONS') {
                                    res.writeHead(200);
                                    res.end();
                                    return;
                                }
                                
                                // ✅ NUR WICHTIGE HTTP REQUESTS LOGGEN
                                var isImportantRequest = parsedUrl.pathname.includes('/rpc/EM.GetStatus') || 
                                                        parsedUrl.pathname.includes('/rpc/Shelly.GetStatus') ||
                                                        parsedUrl.pathname.includes('/settings');
                                
                                if (isImportantRequest) {
                                    console.log('🌐 HTTP: ' + parsedUrl.pathname + ' von ' + req.connection.remoteAddress);
                                }
                                
                                // ✅ KRITISCH: VERSCHIEDENE ENDPOINTS = VERSCHIEDENE STRUKTUREN!
                                
                                // Venus E erwartet: /rpc/EM.GetStatus → MARSTEK FORMAT (4 Felder)
                                if (parsedUrl.pathname === '/rpc/EM.GetStatus') {
                                    res.writeHead(200, { 'Content-Type': 'application/json' });
                                    var response = createMarstekVenusEResponse();
                                    
                                    console.log('🎯 VENUS E EM.GetStatus! Sende MARSTEK FORMAT: total_act_power=' + response.total_act_power + 'W (ROOT-LEVEL)');
                                    
                                    res.end(JSON.stringify(response));
                                    return;
                                }
                                
                                // Legacy Support: /rpc/Shelly.GetStatus → VERSCHACHTELTE Struktur
                                if (parsedUrl.pathname === '/rpc/Shelly.GetStatus' || parsedUrl.pathname === '/status') {
                                    res.writeHead(200, { 'Content-Type': 'application/json' });
                                    var response = createShellyGetStatusResponse();
                                    
                                    // ✅ NUR BEI GROßEN ÄNDERUNGEN LOGGEN
                                    var powerChange = Math.abs(response['em:0'].total_act_power - lastLoggedPower);
                                    if (powerChange > MARSTEK_CONFIG.minChangeThreshold) {
                                        console.log('📊 Legacy Shelly.GetStatus! em:0.total_act_power: ' + response['em:0'].total_act_power + 'W');
                                    }
                                    
                                    res.end(JSON.stringify(response));
                                    return;
                                }
                                
                                // Shelly Info API emulieren
                                if (parsedUrl.pathname === '/rpc/Shelly.GetInfo' || parsedUrl.pathname === '/settings') {
                                    res.writeHead(200, { 'Content-Type': 'application/json' });
                                    var infoResponse = {
                                        "id": 0,
                                        "src": "shellypro3em-XXXXXXXXXXXX",
                                        "result": {
                                            "name": "Shelly Pro 3EM Emulation (ECHTE SHELLY-DATEN)",
                                            "id": "shellypro3em-XXXXXXXXXXXX",
                                            "mac": "XXXXXXXXXXXX",
                                            "slot": 1,
                                            "model": "SPRO-3EM",
                                            "gen": 2,
                                            "fw_id": "20230913-XXXXXX/v1.14.0-XXXXXXXX",
                                            "ver": "1.14.0",
                                            "app": "Pro3EM",
                                            "auth_en": false,
                                            "auth_domain": null
                                        }
                                    };
                                    res.end(JSON.stringify(infoResponse));
                                    return;
                                }
                                
                                // Zusätzliche Shelly-Endpunkte
                                if (parsedUrl.pathname === '/shelly') {
                                    res.writeHead(200, { 'Content-Type': 'application/json' });
                                    res.end(JSON.stringify({
                                        "type": "SPRO-3EM",
                                        "mac": "XXXXXXXXXXXX",
                                        "auth": false,
                                        "fw": "1.14.0",
                                        "discoverable": true,
                                        "longid": 1,
                                        "num_outputs": 1,
                                        "num_meters": 3
                                    }));
                                    return;
                                }
                                
                                // RPC über HTTP (fallback) - AUCH MARSTEK FORMAT
                                if (parsedUrl.pathname === '/rpc') {
                                    res.writeHead(200, { 'Content-Type': 'application/json' });
                                    res.end(JSON.stringify(createMarstekVenusEResponse()));
                                    return;
                                }
                                
                                // Device Description
                                if (parsedUrl.pathname === '/description.xml') {
                                    res.writeHead(200, { 'Content-Type': 'text/xml' });
                                    var xml = '<?xml version="1.0"?>\n' +
                                              '<root xmlns="urn:schemas-upnp-org:device-1-0">\n' +
                                              '<device>\n' +
                                              '<deviceType>urn:shelly:device:pro3em:1</deviceType>\n' +
                                              '<friendlyName>Shelly Pro 3EM Emulation (ECHTE SHELLY-DATEN)</friendlyName>\n' +
                                              '<manufacturer>Allterco</manufacturer>\n' +
                                              '<modelName>Shelly Pro 3EM</modelName>\n' +
                                              '<UDN>uuid:shelly-pro3em-emulation</UDN>\n' +
                                              '</device>\n' +
                                              '</root>';
                                    res.end(xml);
                                    return;
                                }
                                
                                // Fallback für unbekannte Anfragen
                                // ✅ NUR UNBEKANNTE REQUESTS LOGGEN (reduziert Spam)
                                res.writeHead(404, { 'Content-Type': 'text/plain' });
                                res.end('Not Found: ' + parsedUrl.pathname);
                            });
                            
                            // ✅ KORRIGIERTE RPC Request Handler für UDP
                            function handleRPCRequest(msg, rinfo, socket) {
                                var message = msg.toString();
                                
                                try {
                                    // RPC-Anfrage parsen
                                    if (message.includes('EM.GetStatus') || message.includes('Shelly.GetStatus')) {
                                        
                                        var correctedPower = currentPowerTotal;
                                        var powerCalc = calculateMarstekPower(correctedPower);
                                        
                                        requestCounter++;
                                        var now = Date.now();
                                        
                                        // Reduziertes Logging
                                        if (now - lastLogTime > MARSTEK_CONFIG.logInterval || requestCounter % 20 === 0) {
                                            console.log('📡 UDP REQUEST #' + requestCounter + ' von ' + rinfo.address + ' - Method: ' + (message.includes('EM.GetStatus') ? 'EM.GetStatus' : 'Shelly.GetStatus'));
                                            lastLogTime = now;
                                        }
                                        
                                        // Parse die Anfrage um die ID zu bekommen
                                        var requestData;
                                        try {
                                            requestData = JSON.parse(message);
                                        } catch (e) {
                                            requestData = { id: 1, method: 'EM.GetStatus', params: { id: 0 } };
                                        }
                                        
                                        // ✅ VERSCHIEDENE RPC RESPONSES je nach Method!
                                        var rpcResponse;
                                        
                                        if (message.includes('EM.GetStatus')) {
                                            // ✅ MARSTEK VENUS E UDP REQUEST → NUR 4 FELDER AUF ROOT-EBENE!
                                            rpcResponse = createMarstekVenusEResponse();
                                            console.log('🎯 UDP EM.GetStatus! Sende MARSTEK FORMAT: total_act_power=' + rpcResponse.total_act_power + 'W (ROOT-LEVEL)');
                                        } else {
                                            // Legacy UDP Request → VERSCHACHTELTE Struktur
                                            rpcResponse = {
                                                "id": requestData.id || 1,
                                                "src": "shellypro3em-XXXXXXXXXXXX",
                                                "result": createShellyGetStatusResponse()
                                            };
                                            console.log('📊 UDP Shelly.GetStatus! Sende em:0.total_act_power: ' + powerCalc.marstekPower + 'W (VERSCHACHTELT)');
                                        }
                                        
                                        var responseStr = JSON.stringify(rpcResponse);
                                        
                                        socket.send(responseStr, rinfo.port, rinfo.address, function(err) {
                                            if (err && MARSTEK_CONFIG.debugMode) {
                                                console.log('Fehler beim Senden: ' + err);
                                            }
                                        });
                                    }
                                    // Fallback: JSON RPC versuchen zu parsen
                                    else {
                                        try {
                                            var rpcRequest = JSON.parse(message);
                                            if (rpcRequest.method) {
                                                console.log('🔧 RPC Method: ' + rpcRequest.method);
                                                
                                                var rpcResponse = createMarstekVenusEResponse();
                                                
                                                var responseStr = JSON.stringify(rpcResponse);
                                                socket.send(responseStr, rinfo.port, rinfo.address);
                                                console.log('📤 JSON RPC Response gesendet');
                                            }
                                        } catch (e) {
                                            if (MARSTEK_CONFIG.debugMode) {
                                                console.log('❓ Unbekannte UDP-Nachricht: ' + message.substring(0, 100));
                                            }
                                        }
                                    }
                                } catch (error) {
                                    console.log('❌ Fehler bei UDP-Verarbeitung: ' + error);
                                }
                            }
                            
                            // UDP Socket für Discovery erstellen
                            function createUDPSocket() {
                                udpSocket = dgram.createSocket('udp4');
                                
                                udpSocket.on('message', function(msg, rinfo) {
                                    var message = msg.toString();
                                    
                                    // Discovery Response
                                    if (message.includes('M-SEARCH') || message.includes('shelly') || message.includes('SSDP')) {
                                        var localIP = getLocalIP();
                                        var response = 'HTTP/1.1 200 OK\r\n' +
                                                      'ST: urn:shelly:device\r\n' +
                                                      'USN: uuid:shelly-pro3em-emulation\r\n' +
                                                      'LOCATION: http://' + localIP + ':' + EMULATION_PORT + '/settings\r\n' +
                                                      'SERVER: Shelly/1.14.0\r\n' +
                                                      'CACHE-CONTROL: max-age=1800\r\n' +
                                                      '\r\n';
                                        
                                        udpSocket.send(response, rinfo.port, rinfo.address, function(err) {
                                            // Kein Success-Logging für Discovery
                                        });
                                    }
                                    // Falls doch RPC über Port 1900 kommt
                                    else {
                                        handleRPCRequest(msg, rinfo, udpSocket);
                                    }
                                });
                                
                                udpSocket.on('error', function(err) {
                                    console.log('UDP Discovery Fehler: ' + err);
                                });
                            }
                            
                            // Emulation starten
                            function startEmulation() {
                                if (serverInstance) {
                                    console.log('Emulation läuft bereits');
                                    return;
                                }
                                
                                try {
                                    // HTTP Server starten
                                    serverInstance = server.listen(EMULATION_PORT, function() {
                                        console.log('=== ECHTE SHELLY PRO 3EM EMULATION GESTARTET ===');
                                        console.log('Port: ' + EMULATION_PORT);
                                        console.log('Erreichbar unter: http://localhost:' + EMULATION_PORT);
                                        console.log('');
                                        console.log('✅ ECHTE API STRUKTUR:');
                                        console.log('  /rpc/EM.GetStatus      → DIREKTE Struktur (für Venus E)');
                                        console.log('  /rpc/Shelly.GetStatus  → VERSCHACHTELTE Struktur (Legacy)');
                                        console.log('');
                                        console.log('🎯 Venus E sollte /rpc/EM.GetStatus verwenden!');
                                        console.log('📊 Verwendet echte Shelly EM3 Pro Messwerte!');
                                        console.log('========================================================');
                                    });
                                    
                                    // UDP Discovery starten (Port 1900)
                                    createUDPSocket();
                                    udpSocket.bind(1900, function() {
                                        console.log('UDP Discovery läuft auf Port 1900');
                                    });
                                    
                                    // UDP Socket für Port 1010 (RPC)
                                    var rpcSocket = dgram.createSocket('udp4');
                                    rpcSocket.bind(1010, function() {
                                        console.log('UDP RPC Socket läuft auf Port 1010');
                                    });
                                    
                                    rpcSocket.on('message', function(msg, rinfo) {
                                        handleRPCRequest(msg, rinfo, rpcSocket);
                                    });
                                    
                                    rpcSocket.on('error', function(err) {
                                        console.log('UDP RPC Port 1010 Fehler: ' + err);
                                    });
                                    
                                    // Regelmäßige Updates der Messwerte
                                    setInterval(readShellyValues, UPDATE_INTERVAL);
                                    
                                    // Initiale Werte laden
                                    readShellyValues();
                                    
                                } catch (error) {
                                    console.error('Fehler beim Starten der Emulation:');
                                    console.error(error);
                                }
                            }
                            
                            function stopEmulation() {
                                if (serverInstance) {
                                    serverInstance.close(function() {
                                        console.log('Shelly EM3 Pro Emulation gestoppt');
                                        serverInstance = null;
                                    });
                                }
                                if (udpSocket) {
                                    udpSocket.close(function() {
                                        console.log('UDP Discovery gestoppt');
                                    });
                                }
                            }
                            
                            // ZUSÄTZLICHE Überwachungsfunktion für Marstek-Verhalten
                            function monitorMarstekBehavior() {
                                console.log('\n=== MARSTEK STATUS UPDATE ===');
                                console.log('⚡ Aktueller Verbrauch: ' + currentPowerTotal + 'W');
                                console.log('📊 Phase Details: L1=' + currentPowerL1.toFixed(1) + 'W, L2=' + currentPowerL2.toFixed(1) + 'W, L3=' + currentPowerL3.toFixed(1) + 'W');
                                console.log('🔌 Current Details: L1=' + currentCurrentL1.toFixed(2) + 'A, L2=' + currentCurrentL2.toFixed(2) + 'A, L3=' + currentCurrentL3.toFixed(2) + 'A');
                                console.log('⚡ Voltage Details: L1=' + currentVoltageL1.toFixed(1) + 'V, L2=' + currentVoltageL2.toFixed(1) + 'V, L3=' + currentVoltageL3.toFixed(1) + 'V');
                                console.log('📡 UDP Requests: ' + requestCounter + ' (seit Start)');
                                console.log('🔧 API-Struktur: EM.GetStatus (DIREKT) + Shelly.GetStatus (VERSCHACHTELT)');
                                
                                if (currentPowerTotal !== 0) {
                                    var calc = calculateMarstekPower(currentPowerTotal);
                                    console.log('🎯 Venus E erhält: total_act_power=' + calc.marstekPower + 'W (' + calc.direction + ')');
                                }
                                
                                // Reset Counter für bessere Übersicht
                                if (requestCounter > 1000) {
                                    requestCounter = 0;
                                    console.log('🔄 Request Counter zurückgesetzt');
                                }
                                
                                console.log('=============================\n');
                            }
                            
                            // Monitoring alle 2 Minuten
                            setInterval(monitorMarstekBehavior, 120000);
                            
                            // Emulation starten
                            startEmulation();
                            
                            // Cleanup bei Script-Stop
                            onStop(function() {
                                console.log('Script wird gestoppt...');
                                stopEmulation();
                            });
                            
                            // Test-Funktion für Venus E Kompatibilität
                            function testVenusECompatibility() {
                                console.log('\n=== VENUS E KOMPATIBILITÄTS-TEST ===');
                                
                                console.log('🎯 Teste EM.GetStatus (Venus E Endpoint):');
                                var emResponse = createMarstekVenusEResponse();
                                console.log('- total_act_power: ' + (emResponse.total_act_power !== undefined ? '✅ ' + emResponse.total_act_power + 'W' : '❌ FEHLT'));
                                console.log('- id: ' + (emResponse.id !== undefined ? '✅ ' + emResponse.id : '❌ FEHLT'));
                                console.log('- a_act_power: ' + (emResponse.a_act_power !== undefined ? '✅ ' + emResponse.a_act_power + 'W' : '❌ FEHLT'));
                                console.log('- Struktur: ' + (emResponse.result === undefined ? '✅ ROOT-LEVEL (korrekt für Venus E)' : '❌ VERSCHACHTELT'));
                                console.log('- Felder-Anzahl: ' + (Object.keys(emResponse).length === 4 ? '✅ 4 Felder (korrekt)' : '❌ ' + Object.keys(emResponse).length + ' Felder'));
                                console.log('- Felder: ' + JSON.stringify(Object.keys(emResponse)));
                                
                                console.log('\n📊 Teste Shelly.GetStatus (Legacy Endpoint):');
                                var shellyResponse = createShellyGetStatusResponse();
                                console.log('- em:0.total_act_power: ' + (shellyResponse['em:0'] && shellyResponse['em:0'].total_act_power !== undefined ? '✅ ' + shellyResponse['em:0'].total_act_power + 'W' : '❌ FEHLT'));
                                console.log('- Struktur: ' + (shellyResponse['em:0'] !== undefined ? '✅ VERSCHACHTELT (korrekt für Legacy)' : '❌ NICHT VERSCHACHTELT'));
                                
                                console.log('\n📊 ECHTE SHELLY-DATEN INTEGRATION:');
                                console.log('- Power Werte: ' + (currentPowerL1 !== 0 || currentPowerL2 !== 0 || currentPowerL3 !== 0 ? '✅ Echte Werte geladen' : '❌ Keine echten Werte'));
                                console.log('- Current Werte: ' + (currentCurrentL1 !== 0 || currentCurrentL2 !== 0 || currentCurrentL3 !== 0 ? '✅ Echte Ampere-Werte' : '❌ Standard-Werte'));
                                console.log('- PowerFactor: ' + (currentPowerFactorL1 !== 1.0 || currentPowerFactorL2 !== 1.0 || currentPowerFactorL3 !== 1.0 ? '✅ Echte PF-Werte' : '❌ Standard-Werte'));
                                console.log('- Energie-Werte: ' + (energyL1 > 0 || energyL2 > 0 || energyL3 > 0 ? '✅ Echte Energie-Daten' : '❌ Keine Energie-Daten'));
                                
                                console.log('\n💡 LOGGING KONFIGURATION:');
                                console.log('- Debug Mode: ' + (MARSTEK_CONFIG.debugMode ? '🔍 AN (ausführlich)' : '🔇 AUS (reduziert)'));
                                console.log('- Change Threshold: ' + MARSTEK_CONFIG.minChangeThreshold + 'W (nur bei größeren Änderungen loggen)');
                                console.log('- Log Interval: ' + (MARSTEK_CONFIG.logInterval / 1000) + 's (reduziert Spam)');
                                console.log('====================================\n');
                            }
                            
                            // Test bei Start ausführen
                            setTimeout(testVenusECompatibility, 3000);
                            
                            // DEBUGGING: Zeige alle HTTP Requests im Detail
                            function enableDetailedLogging() {
                                MARSTEK_CONFIG.debugMode = true;
                                MARSTEK_CONFIG.minChangeThreshold = 0;  // Jede Änderung loggen
                                MARSTEK_CONFIG.logInterval = 5000;      // Alle 5 Sekunden
                                console.log('🔍 DETAILED LOGGING AKTIVIERT');
                                console.log('- Jede Wert-Änderung wird geloggt');
                                console.log('- Alle HTTP/UDP Requests werden geloggt'); 
                                console.log('- Echte Shelly-Werte werden im Detail angezeigt');
                                console.log('- Aufruf: disableDetailedLogging() zum Deaktivieren');
                            }
                            
                            function disableDetailedLogging() {
                                MARSTEK_CONFIG.debugMode = false;
                                MARSTEK_CONFIG.minChangeThreshold = 50; // Nur große Änderungen
                                MARSTEK_CONFIG.logInterval = 30000;     // Alle 30 Sekunden
                                console.log('🔇 DETAILED LOGGING DEAKTIVIERT');
                                console.log('- Nur noch wichtige Änderungen werden geloggt');
                                console.log('- Reduzierte Log-Ausgabe für bessere Übersicht');
                            }
                            
                            // Spezielle Test-Funktion für echte Shelly-Werte
                            function testRealShellyValues() {
                                console.log('\n=== ECHTE SHELLY-WERTE TEST ===');
                                console.log('📊 Teste Shelly EM3 Instance: ' + SHELLY_EM3_INSTANCE);
                                
                                try {
                                    // Test alle Shelly-Werte
                                    var shellyL1Power = getState(SHELLY_EM3_INSTANCE + '.Emeter0.Power').val;
                                    var shellyL1Current = getState(SHELLY_EM3_INSTANCE + '.Emeter0.Current').val;
                                    var shellyL1PF = getState(SHELLY_EM3_INSTANCE + '.Emeter0.PowerFactor').val;
                                    var shellyL1Energy = getState(SHELLY_EM3_INSTANCE + '.Emeter0.Total').val;
                                    var shellyL1Returned = getState(SHELLY_EM3_INSTANCE + '.Emeter0.Total_Returned').val;
                                    
                                    console.log('Phase A (L1):');
                                    console.log('  Power: ' + (shellyL1Power !== null ? shellyL1Power + 'W ✅' : 'FEHLT ❌'));
                                    console.log('  Current: ' + (shellyL1Current !== null ? shellyL1Current + 'A ✅' : 'FEHLT ❌'));
                                    console.log('  PowerFactor: ' + (shellyL1PF !== null ? shellyL1PF + ' ✅' : 'FEHLT ❌'));
                                    console.log('  Energy: ' + (shellyL1Energy !== null ? shellyL1Energy + 'Wh ✅' : 'FEHLT ❌'));
                                    console.log('  Returned: ' + (shellyL1Returned !== null ? shellyL1Returned + 'Wh ✅' : 'FEHLT ❌'));
                                    
                                    // Tibber Test
                                    var tibberPower = getState('tibberlink.0.LocalPulse.0.Power').val;
                                    console.log('\nTibber Pulse:');
                                    console.log('  Power: ' + (tibberPower !== null ? tibberPower + 'W ✅' : 'FEHLT ❌'));
                                    
                                } catch (error) {
                                    console.log('❌ Fehler beim Testen der Shelly-Werte: ' + error);
                                }
                                
                                console.log('====================================\n');
                            }
                            
                            // Test der echten Werte bei Start
                            setTimeout(testRealShellyValues, 5000);
                            
                            // Aufruf: enableDetailedLogging() zum Aktivieren des Detailed Logging
                            // Aufruf: testRealShellyValues() zum Testen der Shelly-Verbindung
                            
                            1 Reply Last reply Reply Quote 0
                            • A
                              australien @australien last edited by

                              @australien

                              nach einem Update des Marstek Venus E auf FW 153 war plötzlich alles ok.
                              Der Emulierte Shelly wird gefunden und arbeitet richtig.

                              1 Reply Last reply Reply Quote 0
                              • First post
                                Last post

                              Support us

                              ioBroker
                              Community Adapters
                              Donate
                              FAQ Cloud / IOT
                              HowTo: Node.js-Update
                              HowTo: Backup/Restore
                              Downloads
                              BLOG

                              443
                              Online

                              31.9k
                              Users

                              80.1k
                              Topics

                              1.3m
                              Posts

                              9
                              13
                              3989
                              Loading More Posts
                              • Oldest to Newest
                              • Newest to Oldest
                              • Most Votes
                              Reply
                              • Reply as topic
                              Log in to reply
                              Community
                              Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
                              The ioBroker Community 2014-2023
                              logo