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.
    • 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

                        868
                        Online

                        31.9k
                        Users

                        80.1k
                        Topics

                        1.3m
                        Posts

                        9
                        13
                        3975
                        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