Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. ioBroker Allgemein
  4. Shelly 3PM Pro Emulator

NEWS

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    15
    1
    571

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    13
    1
    625

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    25
    1
    1.9k

Shelly 3PM Pro Emulator

Geplant Angeheftet Gesperrt Verschoben ioBroker Allgemein
26 Beiträge 13 Kommentatoren 10.7k Aufrufe 15 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • C cwa

    @gismoh
    Ja wäre super, wenn du es posten könntest.
    Ich hab mich auch dran versucht, aber die Simulation wird einfach nicht von Venus erkannt.

    G Offline
    G Offline
    Gismoh
    schrieb am zuletzt editiert von Gismoh
    #17

    @cwa
    Erstmal das erste Skript (An Ende sind Konfigurationshinweise)
    Aber, wie bereits geschrieben, es ist noch in Arbeit ;)
    1-MARSTEK-Core-Engine:

    // ===================================================
    // MARSTEK-Core-Engine v2.0 - KORREKTE CT-SIMULATION
    // ===================================================
    // 
    // 🎯 ZWECK: ROCK-SOLID CT-SIMULATION - DARF NIEMALS CRASHEN!
    // ✅ HTTP/UDP Server (Ports 1010, 2220, 1011) 
    // ✅ Shelly Pro 3EM Emulation
    // ✅ Basis Power-Reading (Tibber + Shelly)
    // ✅ ECHTE PHASENVERTEILUNG (Shelly-basiert + 66%/20%/14% Fallback)
    // ✅ v2.0: Kompatibel mit korrigierter Intelligence-Logik
    // ❌ KEINE komplexen Berechnungen (Crash-Risiko!)
    // 
    // ===================================================
    
    // KONFIGURATION (MINIMAL)
    const CORE_CONFIG = {
        // Hardware-Pfade - BITTE ANPASSEN!
        shellyInstance: 'shelly.0.SHEM-3#XXXXXXXXXXXX#1',  // ← Deine Shelly-Geräte-ID hier eintragen
        tibberPowerPath: 'tibberlink.0.LocalPulse.0.Power', // ← Dein Tibber-Pfad hier eintragen
        
        // Netzwerk
        httpPort: 1010,
        udpPort1: 1010,
        udpPort2: 2220,
        udpPort3: 1011,
        
        // Timing
        UPDATE_INTERVAL: 3000,
        
        // Geteilte Datenpunkte - BITTE ANPASSEN!
        SHARED_PREFIX: '0_userdata.0.marstek_V-E.shared.',  // ← Dein Prefix hier eintragen
        
        // Logging
        LOG_BASIC: true,
        LOG_PHASE_DISTRIBUTION: false    // v2.0: Reduziertes Logging
    };
    
    // MINIMALER STATE (NUR BASICS)
    let coreState = {
        // Basis-Werte
        tibberRaw: 0,
        tibberCurrent: 0,
        shellyL1: 0,
        shellyL2: 0,
        shellyL3: 0,
        
        // ⭐ v2.0: Von Intelligence empfangen (neuer Name) ⭐
        reportedPower: 0,             // Intelligence → Core (gemessener/manipulierter Wert)
        correctionFactor: 1,          // Nicht mehr verwendet, aber kompatibel
        limitingActive: false,        // Status-Info von Intelligence
        
        // Server-Objekte
        httpServer: null,
        udpSocket1: null,
        udpSocket2: null,
        udpSocket3: null,
        
        // Status
        lastUpdate: 0,
        lastUdpLog: 0,
        lastPhaseLog: 0,
        coreActive: true
    };
    
    // ===================================================
    // GETEILTE DATENPUNKTE ERSTELLEN
    // ===================================================
    
    function createSharedDatapoints() {
        const prefix = CORE_CONFIG.SHARED_PREFIX;
        
        const datapoints = [
            // Core → Intelligence
            { name: 'tibber_current', value: 0, desc: 'Aktuelle Tibber-Leistung [W]' },
            { name: 'tibber_raw', value: 0, desc: 'Rohe Tibber-Leistung [W]' },
            { name: 'shelly_l1', value: 0, desc: 'Shelly Phase L1 [W]' },
            { name: 'shelly_l2', value: 0, desc: 'Shelly Phase L2 [W]' },
            { name: 'shelly_l3', value: 0, desc: 'Shelly Phase L3 [W]' },
            { name: 'core_active', value: true, desc: 'Core-Engine läuft' },
            
            // Intelligence → Core (v2.0: Neue Namen)
            { name: 'target_power', value: 0, desc: 'Gemeldeter Netzbezug von Intelligence [W]' },
            { name: 'correction_factor', value: 1, desc: 'Korrekturfaktor (legacy)' },
            { name: 'limiting_active', value: false, desc: 'Begrenzung aktiv' },
            
            // Monitor → Alle
            { name: 'override_mode', value: '', desc: 'Manueller Override (test/normal)' },
            { name: 'core_status', value: 'starting', desc: 'Core-Engine Status' }
        ];
        
        datapoints.forEach(dp => {
            try {
                createState(prefix + dp.name, dp.value, {
                    name: dp.desc,
                    type: typeof dp.value,
                    read: true,
                    write: true,
                    desc: `MARSTEK Core-Engine v2.0 - ${dp.desc}`
                });
            } catch (error) {
                // State existiert bereits - OK
            }
        });
    }
    
    // ===================================================
    // POWER-READING (EINFACH & SICHER)
    // ===================================================
    
    function readBasicPowerValues() {
        try {
            // Tibber lesen (mit Error-Handling)
            const tibberValue = getState(CORE_CONFIG.tibberPowerPath).val;
            if (tibberValue !== null && !isNaN(tibberValue)) {
                coreState.tibberRaw = tibberValue;
                coreState.tibberCurrent = tibberValue; // Basis-Version ohne Glättung
                
                // An Intelligence weiterleiten
                setState(CORE_CONFIG.SHARED_PREFIX + 'tibber_current', tibberValue);
                setState(CORE_CONFIG.SHARED_PREFIX + 'tibber_raw', tibberValue);
            }
            
            // Shelly Phasen lesen (mit Error-Handling)
            try {
                coreState.shellyL1 = getState(CORE_CONFIG.shellyInstance + '.Emeter0.Power').val || 0;
                coreState.shellyL2 = getState(CORE_CONFIG.shellyInstance + '.Emeter1.Power').val || 0;
                coreState.shellyL3 = getState(CORE_CONFIG.shellyInstance + '.Emeter2.Power').val || 0;
                
                setState(CORE_CONFIG.SHARED_PREFIX + 'shelly_l1', coreState.shellyL1);
                setState(CORE_CONFIG.SHARED_PREFIX + 'shelly_l2', coreState.shellyL2);
                setState(CORE_CONFIG.SHARED_PREFIX + 'shelly_l3', coreState.shellyL3);
            } catch (error) {
                // Shelly-Fehler nicht kritisch - weiter mit 0-Werten
                if (CORE_CONFIG.LOG_BASIC) {
                    console.log('⚠️ Core: Shelly-Lesefehler (nicht kritisch)');
                }
            }
            
            // ⭐ v2.0: Von Intelligence empfangen (neuer Name) ⭐
            try {
                // Intelligence sendet jetzt "gemessenen/manipulierten Wert" statt Sollwert
                // ⭐ KRITISCHER FIX: 0W ist ein gültiger Wert! Nur bei null/undefined Fallback ⭐
                const targetPowerVal = getState(CORE_CONFIG.SHARED_PREFIX + 'target_power').val;
                coreState.reportedPower = (targetPowerVal !== null && targetPowerVal !== undefined) 
                                         ? targetPowerVal 
                                         : coreState.tibberCurrent;
                
                const correctionVal = getState(CORE_CONFIG.SHARED_PREFIX + 'correction_factor').val;
                coreState.correctionFactor = (correctionVal !== null && correctionVal !== undefined) 
                                            ? correctionVal 
                                            : 1;
                
                const limitingVal = getState(CORE_CONFIG.SHARED_PREFIX + 'limiting_active').val;
                coreState.limitingActive = (limitingVal !== null && limitingVal !== undefined) 
                                          ? limitingVal 
                                          : false;
            } catch (error) {
                // Fallback: Tibber-Werte verwenden
                coreState.reportedPower = coreState.tibberCurrent;
            }
            
            coreState.lastUpdate = Date.now();
            
        } catch (error) {
            // KRITISCHER FEHLER - aber Core darf nicht crashen!
            console.error('❌ Core: Kritischer Power-Reading Fehler:', error.message);
            // Fallback-Werte verwenden
            coreState.reportedPower = 0;
        }
    }
    
    // ===================================================
    // ECHTE PHASENVERTEILUNG (BEREITS KORREKT - BEIBEHALTEN)
    // ===================================================
    
    function createRealPhaseDistribution(totalPower) {
        try {
            // Echte Shelly-Phasen-Verhältnisse berechnen
            const shellyTotal = Math.abs(coreState.shellyL1) + Math.abs(coreState.shellyL2) + Math.abs(coreState.shellyL3);
            
            // Fallback bei Shelly-Total = 0 oder sehr klein
            if (shellyTotal < 10) {
                // FALLBACK: Echte Haushalts-Verteilung (66%/20%/14% - typisch DE)
                return {
                    l1: totalPower * 0.66,
                    l2: totalPower * 0.20,
                    l3: totalPower * 0.14
                };
            }
            
            // Echte prozentuale Verteilung basierend auf Shelly-Verhältnissen
            const l1Ratio = Math.abs(coreState.shellyL1) / shellyTotal;
            const l2Ratio = Math.abs(coreState.shellyL2) / shellyTotal;
            const l3Ratio = Math.abs(coreState.shellyL3) / shellyTotal;
            
            // v2.0: DEBUG-LOG für Phasenverteilung (reduziert)
            const now = Date.now();
            const shouldLog = CORE_CONFIG.LOG_PHASE_DISTRIBUTION && 
                             (!coreState.lastPhaseLog || (now - coreState.lastPhaseLog) > 120000) && 
                             Math.abs(totalPower) > 100;
            
            if (shouldLog) {
                console.log(`📊 Core: Phasenverteilung - Shelly: L1=${Math.round(coreState.shellyL1)}W(${Math.round(l1Ratio*100)}%) L2=${Math.round(coreState.shellyL2)}W(${Math.round(l2Ratio*100)}%) L3=${Math.round(coreState.shellyL3)}W(${Math.round(l3Ratio*100)}%)`);
                console.log(`📊 Core: Reported ${Math.round(totalPower)}W → L1=${Math.round(totalPower * l1Ratio)}W L2=${Math.round(totalPower * l2Ratio)}W L3=${Math.round(totalPower * l3Ratio)}W`);
                coreState.lastPhaseLog = now;
            }
            
            return {
                l1: totalPower * l1Ratio,
                l2: totalPower * l2Ratio,
                l3: totalPower * l3Ratio
            };
            
        } catch (error) {
            // NOTFALL-FALLBACK: Echte Haushalts-Verteilung (66%/20%/14%)
            console.error('❌ Core: Phasenverteilung Fehler - verwende Fallback');
            return {
                l1: totalPower * 0.66,
                l2: totalPower * 0.20,
                l3: totalPower * 0.14
            };
        }
    }
    
    // ===================================================
    // VENUS RESPONSE (STABIL)
    // ===================================================
    
    function createBasicVenusResponse() {
        try {
            // ⭐ v2.0: Intelligence sendet "gemessenen/manipulierten Wert" ⭐
            let reportedTotal = coreState.reportedPower;
            
            // Override-Modus prüfen (von Monitor)
            const overrideMode = getState(CORE_CONFIG.SHARED_PREFIX + 'override_mode').val;
            if (overrideMode === 'test') {
                reportedTotal = 100; // Test-Wert
            } else if (overrideMode === 'zero') {
                reportedTotal = 0;   // Force Zero
            }
            
            // Echte Phasenverteilung basierend auf Shelly-Verhältnissen
            const phases = createRealPhaseDistribution(reportedTotal);
            const l1 = phases.l1;
            const l2 = phases.l2;
            const l3 = phases.l3;
            
            // Shelly Pro 3EM Response (Standard-Werte)
            const voltage = 230.0;
            const frequency = 50.0;
            const power_factor = 1.0;
            
            const a_current = Math.abs(l1) / voltage;
            const b_current = Math.abs(l2) / voltage;
            const c_current = Math.abs(l3) / voltage;
            const total_current = Math.abs(reportedTotal) / voltage;
            
            const a_aprt_power = Math.abs(l1);
            const b_aprt_power = Math.abs(l2);
            const c_aprt_power = Math.abs(l3);
            const total_aprt_power = Math.abs(reportedTotal);
            
            return {
                id: 0,
                a_current: Math.round(a_current * 1000) / 1000,
                a_voltage: voltage,
                a_act_power: Math.round(l1 * 10) / 10,
                a_aprt_power: Math.round(a_aprt_power * 10) / 10,
                a_pf: power_factor,
                a_freq: frequency,
                b_current: Math.round(b_current * 1000) / 1000,
                b_voltage: voltage,
                b_act_power: Math.round(l2 * 10) / 10,
                b_aprt_power: Math.round(b_aprt_power * 10) / 10,
                b_pf: power_factor,
                b_freq: frequency,
                c_current: Math.round(c_current * 1000) / 1000,
                c_voltage: voltage,
                c_act_power: Math.round(l3 * 10) / 10,
                c_aprt_power: Math.round(c_aprt_power * 10) / 10,
                c_pf: power_factor,
                c_freq: frequency,
                n_current: null,
                total_current: Math.round(total_current * 1000) / 1000,
                total_act_power: Math.round(reportedTotal * 10) / 10,
                total_aprt_power: Math.round(total_aprt_power * 10) / 10,
                user_calibrated_phase: []
            };
            
        } catch (error) {
            // NOTFALL-RESPONSE - Core darf nicht crashen!
            console.error('❌ Core: Venus Response Fehler - verwende Notfall-Response');
            return {
                id: 0,
                total_act_power: 0,
                total_aprt_power: 0,
                total_current: 0,
                a_act_power: 0, a_aprt_power: 0, a_current: 0, a_voltage: 230, a_pf: 1, a_freq: 50,
                b_act_power: 0, b_aprt_power: 0, b_current: 0, b_voltage: 230, b_pf: 1, b_freq: 50,
                c_act_power: 0, c_aprt_power: 0, c_current: 0, c_voltage: 230, c_pf: 1, c_freq: 50,
                n_current: null,
                user_calibrated_phase: []
            };
        }
    }
    
    // ===================================================
    // HTTP SERVER (STABIL)
    // ===================================================
    
    function createStableHTTPServer() {
        const http = require('http');
        const url = require('url');
        
        return http.createServer(function(req, res) {
            try {
                res.setHeader('Access-Control-Allow-Origin', '*');
                res.setHeader('Content-Type', 'application/json');
                const parsedUrl = url.parse(req.url, true);
                
                if (parsedUrl.pathname === '/rpc/EM.GetStatus') {
                    const response = createBasicVenusResponse();
                    
                    // v2.0: Verbessertes Logging mit 0W-Fix-Info
                    if (CORE_CONFIG.LOG_BASIC) {
                        const status = coreState.limitingActive ? " (BEGRENZT)" : "";
                        const socInfo = response.total_act_power === 0 ? " (SOC-SCHUTZ)" : "";
                        console.log(`📤 Core v2.0 FIX: ${response.total_act_power}W (L1=${Math.round(response.a_act_power)}W L2=${Math.round(response.b_act_power)}W L3=${Math.round(response.c_act_power)}W)${status}${socInfo}`);
                    }
                    
                    res.writeHead(200);
                    res.end(JSON.stringify(response));
                    return;
                }
                
                if (parsedUrl.pathname === '/rpc/Shelly.GetInfo') {
                    const info = {
                        "id": "marstek-core-engine-v20-fix",
                        "mac": "MARSTEKCOREXX",  // Anonymisiert
                        "model": "SPRO-3EM",
                        "gen": 2,
                        "fw_id": "20250810-000000/2.0.1-core-engine-fixed",
                        "ver": "2.0.1",
                        "app": "Pro3EM"
                    };
                    res.writeHead(200);
                    res.end(JSON.stringify(info));
                    return;
                }
                
                res.writeHead(404);
                res.end(JSON.stringify({error: "Not Found"}));
                
            } catch (error) {
                // HTTP-Fehler nicht kritisch - Standard-Response senden
                console.error('❌ Core: HTTP Error:', error.message);
                try {
                    res.writeHead(500);
                    res.end(JSON.stringify({error: "Core Engine Error"}));
                } catch (e) {
                    // Auch das könnte fehlschlagen - ignorieren
                }
            }
        });
    }
    
    // ===================================================
    // UDP HANDLER (STABIL)
    // ===================================================
    
    function handleStableUDPMessage(msg, rinfo, socket) {
        try {
            const message = msg.toString();
            
            // UDP-Logging (begrenzt)
            const now = Date.now();
            if (!coreState.lastUdpLog || (now - coreState.lastUdpLog) > 60000) {
                if (CORE_CONFIG.LOG_BASIC) {
                    console.log(`📡 Core: UDP aktiv (Port ${socket.address().port})`);
                }
                coreState.lastUdpLog = now;
            }
            
            if (message.includes('EM.GetStatus')) {
                const response = createBasicVenusResponse();
                socket.send(Buffer.from(JSON.stringify(response)), rinfo.port, rinfo.address);
            }
            
        } catch (error) {
            // UDP-Fehler nicht kritisch
            if (CORE_CONFIG.LOG_BASIC) {
                console.log('⚠️ Core: UDP Fehler (nicht kritisch)');
            }
        }
    }
    
    // ===================================================
    // CORE-ENGINE START
    // ===================================================
    
    function startCoreEngine() {
        console.log('🚀 MARSTEK-Core-Engine v2.0.1 - KORREKTE CT-SIMULATION (0W-FIX)\n');
        console.log('🎯 ZWECK: ROCK-SOLID CT-SIMULATION');
        console.log('✅ HTTP/UDP Server für Shelly Pro 3EM Emulation');
        console.log('✅ Basis Power-Reading (Tibber + Shelly)');
        console.log('✅ ECHTE PHASENVERTEILUNG (Shelly-basiert + 66%/20%/14% Fallback)');
        console.log('✅ v2.0: Kompatibel mit korrigierter Intelligence-Logik');
        console.log('✅ v2.0.1: KRITISCHER 0W-BUG REPARIERT!');
        console.log('❌ KEINE komplexen Berechnungen (Crash-Schutz!)');
        console.log('');
        console.log('🔗 KOMMUNIKATION:');
        console.log('   📤 Sendet: tibber_current, shelly_l1/l2/l3');
        console.log('   📥 Empfängt: target_power (jetzt gemessener/manipulierter Wert)');
        console.log('   🤝 Intelligence-Script v2.0 sendet korrekte Messwerte');
        console.log('   📊 Monitor-Script überwacht und steuert');
        console.log('');
        console.log('🔄 v2.0.1 KRITISCHER FIX:');
        console.log('   🚨 0W-Bug repariert: 0W ist ein gültiger Wert!');
        console.log('   📊 Fallback nur noch bei null/undefined');
        console.log('   🔋 SOC-Schutz funktioniert jetzt korrekt');
        console.log('   📝 Verbessertes Logging mit SOC-Info');
        console.log('=====================================');
        
        // Geteilte Datenpunkte erstellen
        createSharedDatapoints();
        
        // HTTP Server starten
        try {
            coreState.httpServer = createStableHTTPServer();
            coreState.httpServer.listen(CORE_CONFIG.httpPort, () => {
                console.log('✅ HTTP Server auf Port ' + CORE_CONFIG.httpPort);
            });
        } catch (error) {
            console.error('❌ HTTP Server Start-Fehler:', error.message);
            // Trotzdem weitermachen - UDP könnte funktionieren
        }
        
        // Multi-UDP Server starten
        const dgram = require('dgram');
        
        try {
            coreState.udpSocket1 = dgram.createSocket('udp4');
            coreState.udpSocket1.bind(CORE_CONFIG.udpPort1, () => {
                console.log('✅ UDP Port ' + CORE_CONFIG.udpPort1 + ' (FW <= v224)');
            });
            coreState.udpSocket1.on('message', (msg, rinfo) => {
                handleStableUDPMessage(msg, rinfo, coreState.udpSocket1);
            });
        } catch (error) {
            console.error('❌ UDP1 Fehler:', error.message);
        }
        
        try {
            coreState.udpSocket2 = dgram.createSocket('udp4');
            coreState.udpSocket2.bind(CORE_CONFIG.udpPort2, () => {
                console.log('✅ UDP Port ' + CORE_CONFIG.udpPort2 + ' (FW >= v226)');
            });
            coreState.udpSocket2.on('message', (msg, rinfo) => {
                handleStableUDPMessage(msg, rinfo, coreState.udpSocket2);
            });
        } catch (error) {
            console.error('❌ UDP2 Fehler:', error.message);
        }
        
        try {
            coreState.udpSocket3 = dgram.createSocket('udp4');
            coreState.udpSocket3.bind(CORE_CONFIG.udpPort3, () => {
                console.log('✅ UDP Port ' + CORE_CONFIG.udpPort3 + ' (Fallback)');
            });
            coreState.udpSocket3.on('message', (msg, rinfo) => {
                handleStableUDPMessage(msg, rinfo, coreState.udpSocket3);
            });
        } catch (error) {
            console.error('❌ UDP3 Fehler:', error.message);
        }
        
        // Status setzen
        setState(CORE_CONFIG.SHARED_PREFIX + 'core_status', 'running');
        setState(CORE_CONFIG.SHARED_PREFIX + 'core_active', true);
        
        // Haupt-Loop starten
        setInterval(readBasicPowerValues, CORE_CONFIG.UPDATE_INTERVAL);
        
        // Sofort ersten Wert lesen
        setTimeout(readBasicPowerValues, 1000);
        
        console.log('\n🎯 CORE-ENGINE v2.0.1 AKTIV - 0W-BUG REPARIERT!');
        console.log('💡 Basis-CT funktioniert - Intelligence-Script v2.0 sendet korrekte Messwerte');
        console.log('🛡️ CRASH-SICHER: Basis-CT läuft auch wenn andere Scripts crashen');
        console.log('📊 Phasenverteilung: Shelly-basiert oder 66%/20%/14% Fallback');
        console.log('🔧 Kompatibel mit neuer Intelligence-Regelungslogik');
        console.log('🚨 KRITISCHER 0W-BUG REPARIERT: SOC-Schutz funktioniert jetzt!');
        console.log('=====================================\n');
    }
    
    function stopCoreEngine() {
        try {
            if (coreState.httpServer) coreState.httpServer.close();
            if (coreState.udpSocket1) coreState.udpSocket1.close();
            if (coreState.udpSocket2) coreState.udpSocket2.close();
            if (coreState.udpSocket3) coreState.udpSocket3.close();
            
            setState(CORE_CONFIG.SHARED_PREFIX + 'core_status', 'stopped');
            setState(CORE_CONFIG.SHARED_PREFIX + 'core_active', false);
            
            console.log('🛑 MARSTEK-Core-Engine v2.0 beendet');
        } catch (error) {
            console.error('❌ Stop-Fehler:', error.message);
        }
    }
    
    // ===================================================
    // SCRIPT START
    // ===================================================
    
    startCoreEngine();
    
    onStop(() => {
        stopCoreEngine();
    });
    
    // ===================================================
    // KONFIGURATIONSHINWEISE FÜR FORUM-NUTZER:
    // ===================================================
    /*
    WICHTIGE ANPASSUNGEN NÖTIG:
    
    1. SHELLY-GERÄTE-ID ANPASSEN:
       Zeile 14: shellyInstance: 'shelly.0.SHEM-3#XXXXXXXXXXXX#1'
       → Ersetze XXXXXXXXXXXX durch deine echte Shelly-Geräte-ID
       
    2. TIBBER-PFAD PRÜFEN:
       Zeile 15: tibberPowerPath: 'tibberlink.0.LocalPulse.0.Power'
       → Prüfe ob dein Tibber-Adapter denselben Pfad verwendet
       
    3. SHARED-PREFIX ANPASSEN:
       Zeile 25: SHARED_PREFIX: '0_userdata.0.marstek_V-E.shared.'
       → Passe den Prefix an deine ioBroker-Struktur an
       
    4. SHELLY-GERÄTE-ID FINDEN:
       - In ioBroker: Objekte → shelly.0 → SHEM-3#[DEINE-ID]#1
       - Oder im Shelly-Adapter unter "Instanzen"
       
    5. TIBBER-PFAD FINDEN:
       - In ioBroker: Objekte → tibberlink.0 → LocalPulse.0 → Power
       - Oder deinen entsprechenden Stromzähler-Pfad
    */
    

    ioBroker auf: Lenovo ThinkCentre M910Q Tiny i5-7500T 16 GB mit proxmox in VM (Bookworm)

    G 1 Antwort Letzte Antwort
    0
    • G Gismoh

      @cwa
      Erstmal das erste Skript (An Ende sind Konfigurationshinweise)
      Aber, wie bereits geschrieben, es ist noch in Arbeit ;)
      1-MARSTEK-Core-Engine:

      // ===================================================
      // MARSTEK-Core-Engine v2.0 - KORREKTE CT-SIMULATION
      // ===================================================
      // 
      // 🎯 ZWECK: ROCK-SOLID CT-SIMULATION - DARF NIEMALS CRASHEN!
      // ✅ HTTP/UDP Server (Ports 1010, 2220, 1011) 
      // ✅ Shelly Pro 3EM Emulation
      // ✅ Basis Power-Reading (Tibber + Shelly)
      // ✅ ECHTE PHASENVERTEILUNG (Shelly-basiert + 66%/20%/14% Fallback)
      // ✅ v2.0: Kompatibel mit korrigierter Intelligence-Logik
      // ❌ KEINE komplexen Berechnungen (Crash-Risiko!)
      // 
      // ===================================================
      
      // KONFIGURATION (MINIMAL)
      const CORE_CONFIG = {
          // Hardware-Pfade - BITTE ANPASSEN!
          shellyInstance: 'shelly.0.SHEM-3#XXXXXXXXXXXX#1',  // ← Deine Shelly-Geräte-ID hier eintragen
          tibberPowerPath: 'tibberlink.0.LocalPulse.0.Power', // ← Dein Tibber-Pfad hier eintragen
          
          // Netzwerk
          httpPort: 1010,
          udpPort1: 1010,
          udpPort2: 2220,
          udpPort3: 1011,
          
          // Timing
          UPDATE_INTERVAL: 3000,
          
          // Geteilte Datenpunkte - BITTE ANPASSEN!
          SHARED_PREFIX: '0_userdata.0.marstek_V-E.shared.',  // ← Dein Prefix hier eintragen
          
          // Logging
          LOG_BASIC: true,
          LOG_PHASE_DISTRIBUTION: false    // v2.0: Reduziertes Logging
      };
      
      // MINIMALER STATE (NUR BASICS)
      let coreState = {
          // Basis-Werte
          tibberRaw: 0,
          tibberCurrent: 0,
          shellyL1: 0,
          shellyL2: 0,
          shellyL3: 0,
          
          // ⭐ v2.0: Von Intelligence empfangen (neuer Name) ⭐
          reportedPower: 0,             // Intelligence → Core (gemessener/manipulierter Wert)
          correctionFactor: 1,          // Nicht mehr verwendet, aber kompatibel
          limitingActive: false,        // Status-Info von Intelligence
          
          // Server-Objekte
          httpServer: null,
          udpSocket1: null,
          udpSocket2: null,
          udpSocket3: null,
          
          // Status
          lastUpdate: 0,
          lastUdpLog: 0,
          lastPhaseLog: 0,
          coreActive: true
      };
      
      // ===================================================
      // GETEILTE DATENPUNKTE ERSTELLEN
      // ===================================================
      
      function createSharedDatapoints() {
          const prefix = CORE_CONFIG.SHARED_PREFIX;
          
          const datapoints = [
              // Core → Intelligence
              { name: 'tibber_current', value: 0, desc: 'Aktuelle Tibber-Leistung [W]' },
              { name: 'tibber_raw', value: 0, desc: 'Rohe Tibber-Leistung [W]' },
              { name: 'shelly_l1', value: 0, desc: 'Shelly Phase L1 [W]' },
              { name: 'shelly_l2', value: 0, desc: 'Shelly Phase L2 [W]' },
              { name: 'shelly_l3', value: 0, desc: 'Shelly Phase L3 [W]' },
              { name: 'core_active', value: true, desc: 'Core-Engine läuft' },
              
              // Intelligence → Core (v2.0: Neue Namen)
              { name: 'target_power', value: 0, desc: 'Gemeldeter Netzbezug von Intelligence [W]' },
              { name: 'correction_factor', value: 1, desc: 'Korrekturfaktor (legacy)' },
              { name: 'limiting_active', value: false, desc: 'Begrenzung aktiv' },
              
              // Monitor → Alle
              { name: 'override_mode', value: '', desc: 'Manueller Override (test/normal)' },
              { name: 'core_status', value: 'starting', desc: 'Core-Engine Status' }
          ];
          
          datapoints.forEach(dp => {
              try {
                  createState(prefix + dp.name, dp.value, {
                      name: dp.desc,
                      type: typeof dp.value,
                      read: true,
                      write: true,
                      desc: `MARSTEK Core-Engine v2.0 - ${dp.desc}`
                  });
              } catch (error) {
                  // State existiert bereits - OK
              }
          });
      }
      
      // ===================================================
      // POWER-READING (EINFACH & SICHER)
      // ===================================================
      
      function readBasicPowerValues() {
          try {
              // Tibber lesen (mit Error-Handling)
              const tibberValue = getState(CORE_CONFIG.tibberPowerPath).val;
              if (tibberValue !== null && !isNaN(tibberValue)) {
                  coreState.tibberRaw = tibberValue;
                  coreState.tibberCurrent = tibberValue; // Basis-Version ohne Glättung
                  
                  // An Intelligence weiterleiten
                  setState(CORE_CONFIG.SHARED_PREFIX + 'tibber_current', tibberValue);
                  setState(CORE_CONFIG.SHARED_PREFIX + 'tibber_raw', tibberValue);
              }
              
              // Shelly Phasen lesen (mit Error-Handling)
              try {
                  coreState.shellyL1 = getState(CORE_CONFIG.shellyInstance + '.Emeter0.Power').val || 0;
                  coreState.shellyL2 = getState(CORE_CONFIG.shellyInstance + '.Emeter1.Power').val || 0;
                  coreState.shellyL3 = getState(CORE_CONFIG.shellyInstance + '.Emeter2.Power').val || 0;
                  
                  setState(CORE_CONFIG.SHARED_PREFIX + 'shelly_l1', coreState.shellyL1);
                  setState(CORE_CONFIG.SHARED_PREFIX + 'shelly_l2', coreState.shellyL2);
                  setState(CORE_CONFIG.SHARED_PREFIX + 'shelly_l3', coreState.shellyL3);
              } catch (error) {
                  // Shelly-Fehler nicht kritisch - weiter mit 0-Werten
                  if (CORE_CONFIG.LOG_BASIC) {
                      console.log('⚠️ Core: Shelly-Lesefehler (nicht kritisch)');
                  }
              }
              
              // ⭐ v2.0: Von Intelligence empfangen (neuer Name) ⭐
              try {
                  // Intelligence sendet jetzt "gemessenen/manipulierten Wert" statt Sollwert
                  // ⭐ KRITISCHER FIX: 0W ist ein gültiger Wert! Nur bei null/undefined Fallback ⭐
                  const targetPowerVal = getState(CORE_CONFIG.SHARED_PREFIX + 'target_power').val;
                  coreState.reportedPower = (targetPowerVal !== null && targetPowerVal !== undefined) 
                                           ? targetPowerVal 
                                           : coreState.tibberCurrent;
                  
                  const correctionVal = getState(CORE_CONFIG.SHARED_PREFIX + 'correction_factor').val;
                  coreState.correctionFactor = (correctionVal !== null && correctionVal !== undefined) 
                                              ? correctionVal 
                                              : 1;
                  
                  const limitingVal = getState(CORE_CONFIG.SHARED_PREFIX + 'limiting_active').val;
                  coreState.limitingActive = (limitingVal !== null && limitingVal !== undefined) 
                                            ? limitingVal 
                                            : false;
              } catch (error) {
                  // Fallback: Tibber-Werte verwenden
                  coreState.reportedPower = coreState.tibberCurrent;
              }
              
              coreState.lastUpdate = Date.now();
              
          } catch (error) {
              // KRITISCHER FEHLER - aber Core darf nicht crashen!
              console.error('❌ Core: Kritischer Power-Reading Fehler:', error.message);
              // Fallback-Werte verwenden
              coreState.reportedPower = 0;
          }
      }
      
      // ===================================================
      // ECHTE PHASENVERTEILUNG (BEREITS KORREKT - BEIBEHALTEN)
      // ===================================================
      
      function createRealPhaseDistribution(totalPower) {
          try {
              // Echte Shelly-Phasen-Verhältnisse berechnen
              const shellyTotal = Math.abs(coreState.shellyL1) + Math.abs(coreState.shellyL2) + Math.abs(coreState.shellyL3);
              
              // Fallback bei Shelly-Total = 0 oder sehr klein
              if (shellyTotal < 10) {
                  // FALLBACK: Echte Haushalts-Verteilung (66%/20%/14% - typisch DE)
                  return {
                      l1: totalPower * 0.66,
                      l2: totalPower * 0.20,
                      l3: totalPower * 0.14
                  };
              }
              
              // Echte prozentuale Verteilung basierend auf Shelly-Verhältnissen
              const l1Ratio = Math.abs(coreState.shellyL1) / shellyTotal;
              const l2Ratio = Math.abs(coreState.shellyL2) / shellyTotal;
              const l3Ratio = Math.abs(coreState.shellyL3) / shellyTotal;
              
              // v2.0: DEBUG-LOG für Phasenverteilung (reduziert)
              const now = Date.now();
              const shouldLog = CORE_CONFIG.LOG_PHASE_DISTRIBUTION && 
                               (!coreState.lastPhaseLog || (now - coreState.lastPhaseLog) > 120000) && 
                               Math.abs(totalPower) > 100;
              
              if (shouldLog) {
                  console.log(`📊 Core: Phasenverteilung - Shelly: L1=${Math.round(coreState.shellyL1)}W(${Math.round(l1Ratio*100)}%) L2=${Math.round(coreState.shellyL2)}W(${Math.round(l2Ratio*100)}%) L3=${Math.round(coreState.shellyL3)}W(${Math.round(l3Ratio*100)}%)`);
                  console.log(`📊 Core: Reported ${Math.round(totalPower)}W → L1=${Math.round(totalPower * l1Ratio)}W L2=${Math.round(totalPower * l2Ratio)}W L3=${Math.round(totalPower * l3Ratio)}W`);
                  coreState.lastPhaseLog = now;
              }
              
              return {
                  l1: totalPower * l1Ratio,
                  l2: totalPower * l2Ratio,
                  l3: totalPower * l3Ratio
              };
              
          } catch (error) {
              // NOTFALL-FALLBACK: Echte Haushalts-Verteilung (66%/20%/14%)
              console.error('❌ Core: Phasenverteilung Fehler - verwende Fallback');
              return {
                  l1: totalPower * 0.66,
                  l2: totalPower * 0.20,
                  l3: totalPower * 0.14
              };
          }
      }
      
      // ===================================================
      // VENUS RESPONSE (STABIL)
      // ===================================================
      
      function createBasicVenusResponse() {
          try {
              // ⭐ v2.0: Intelligence sendet "gemessenen/manipulierten Wert" ⭐
              let reportedTotal = coreState.reportedPower;
              
              // Override-Modus prüfen (von Monitor)
              const overrideMode = getState(CORE_CONFIG.SHARED_PREFIX + 'override_mode').val;
              if (overrideMode === 'test') {
                  reportedTotal = 100; // Test-Wert
              } else if (overrideMode === 'zero') {
                  reportedTotal = 0;   // Force Zero
              }
              
              // Echte Phasenverteilung basierend auf Shelly-Verhältnissen
              const phases = createRealPhaseDistribution(reportedTotal);
              const l1 = phases.l1;
              const l2 = phases.l2;
              const l3 = phases.l3;
              
              // Shelly Pro 3EM Response (Standard-Werte)
              const voltage = 230.0;
              const frequency = 50.0;
              const power_factor = 1.0;
              
              const a_current = Math.abs(l1) / voltage;
              const b_current = Math.abs(l2) / voltage;
              const c_current = Math.abs(l3) / voltage;
              const total_current = Math.abs(reportedTotal) / voltage;
              
              const a_aprt_power = Math.abs(l1);
              const b_aprt_power = Math.abs(l2);
              const c_aprt_power = Math.abs(l3);
              const total_aprt_power = Math.abs(reportedTotal);
              
              return {
                  id: 0,
                  a_current: Math.round(a_current * 1000) / 1000,
                  a_voltage: voltage,
                  a_act_power: Math.round(l1 * 10) / 10,
                  a_aprt_power: Math.round(a_aprt_power * 10) / 10,
                  a_pf: power_factor,
                  a_freq: frequency,
                  b_current: Math.round(b_current * 1000) / 1000,
                  b_voltage: voltage,
                  b_act_power: Math.round(l2 * 10) / 10,
                  b_aprt_power: Math.round(b_aprt_power * 10) / 10,
                  b_pf: power_factor,
                  b_freq: frequency,
                  c_current: Math.round(c_current * 1000) / 1000,
                  c_voltage: voltage,
                  c_act_power: Math.round(l3 * 10) / 10,
                  c_aprt_power: Math.round(c_aprt_power * 10) / 10,
                  c_pf: power_factor,
                  c_freq: frequency,
                  n_current: null,
                  total_current: Math.round(total_current * 1000) / 1000,
                  total_act_power: Math.round(reportedTotal * 10) / 10,
                  total_aprt_power: Math.round(total_aprt_power * 10) / 10,
                  user_calibrated_phase: []
              };
              
          } catch (error) {
              // NOTFALL-RESPONSE - Core darf nicht crashen!
              console.error('❌ Core: Venus Response Fehler - verwende Notfall-Response');
              return {
                  id: 0,
                  total_act_power: 0,
                  total_aprt_power: 0,
                  total_current: 0,
                  a_act_power: 0, a_aprt_power: 0, a_current: 0, a_voltage: 230, a_pf: 1, a_freq: 50,
                  b_act_power: 0, b_aprt_power: 0, b_current: 0, b_voltage: 230, b_pf: 1, b_freq: 50,
                  c_act_power: 0, c_aprt_power: 0, c_current: 0, c_voltage: 230, c_pf: 1, c_freq: 50,
                  n_current: null,
                  user_calibrated_phase: []
              };
          }
      }
      
      // ===================================================
      // HTTP SERVER (STABIL)
      // ===================================================
      
      function createStableHTTPServer() {
          const http = require('http');
          const url = require('url');
          
          return http.createServer(function(req, res) {
              try {
                  res.setHeader('Access-Control-Allow-Origin', '*');
                  res.setHeader('Content-Type', 'application/json');
                  const parsedUrl = url.parse(req.url, true);
                  
                  if (parsedUrl.pathname === '/rpc/EM.GetStatus') {
                      const response = createBasicVenusResponse();
                      
                      // v2.0: Verbessertes Logging mit 0W-Fix-Info
                      if (CORE_CONFIG.LOG_BASIC) {
                          const status = coreState.limitingActive ? " (BEGRENZT)" : "";
                          const socInfo = response.total_act_power === 0 ? " (SOC-SCHUTZ)" : "";
                          console.log(`📤 Core v2.0 FIX: ${response.total_act_power}W (L1=${Math.round(response.a_act_power)}W L2=${Math.round(response.b_act_power)}W L3=${Math.round(response.c_act_power)}W)${status}${socInfo}`);
                      }
                      
                      res.writeHead(200);
                      res.end(JSON.stringify(response));
                      return;
                  }
                  
                  if (parsedUrl.pathname === '/rpc/Shelly.GetInfo') {
                      const info = {
                          "id": "marstek-core-engine-v20-fix",
                          "mac": "MARSTEKCOREXX",  // Anonymisiert
                          "model": "SPRO-3EM",
                          "gen": 2,
                          "fw_id": "20250810-000000/2.0.1-core-engine-fixed",
                          "ver": "2.0.1",
                          "app": "Pro3EM"
                      };
                      res.writeHead(200);
                      res.end(JSON.stringify(info));
                      return;
                  }
                  
                  res.writeHead(404);
                  res.end(JSON.stringify({error: "Not Found"}));
                  
              } catch (error) {
                  // HTTP-Fehler nicht kritisch - Standard-Response senden
                  console.error('❌ Core: HTTP Error:', error.message);
                  try {
                      res.writeHead(500);
                      res.end(JSON.stringify({error: "Core Engine Error"}));
                  } catch (e) {
                      // Auch das könnte fehlschlagen - ignorieren
                  }
              }
          });
      }
      
      // ===================================================
      // UDP HANDLER (STABIL)
      // ===================================================
      
      function handleStableUDPMessage(msg, rinfo, socket) {
          try {
              const message = msg.toString();
              
              // UDP-Logging (begrenzt)
              const now = Date.now();
              if (!coreState.lastUdpLog || (now - coreState.lastUdpLog) > 60000) {
                  if (CORE_CONFIG.LOG_BASIC) {
                      console.log(`📡 Core: UDP aktiv (Port ${socket.address().port})`);
                  }
                  coreState.lastUdpLog = now;
              }
              
              if (message.includes('EM.GetStatus')) {
                  const response = createBasicVenusResponse();
                  socket.send(Buffer.from(JSON.stringify(response)), rinfo.port, rinfo.address);
              }
              
          } catch (error) {
              // UDP-Fehler nicht kritisch
              if (CORE_CONFIG.LOG_BASIC) {
                  console.log('⚠️ Core: UDP Fehler (nicht kritisch)');
              }
          }
      }
      
      // ===================================================
      // CORE-ENGINE START
      // ===================================================
      
      function startCoreEngine() {
          console.log('🚀 MARSTEK-Core-Engine v2.0.1 - KORREKTE CT-SIMULATION (0W-FIX)\n');
          console.log('🎯 ZWECK: ROCK-SOLID CT-SIMULATION');
          console.log('✅ HTTP/UDP Server für Shelly Pro 3EM Emulation');
          console.log('✅ Basis Power-Reading (Tibber + Shelly)');
          console.log('✅ ECHTE PHASENVERTEILUNG (Shelly-basiert + 66%/20%/14% Fallback)');
          console.log('✅ v2.0: Kompatibel mit korrigierter Intelligence-Logik');
          console.log('✅ v2.0.1: KRITISCHER 0W-BUG REPARIERT!');
          console.log('❌ KEINE komplexen Berechnungen (Crash-Schutz!)');
          console.log('');
          console.log('🔗 KOMMUNIKATION:');
          console.log('   📤 Sendet: tibber_current, shelly_l1/l2/l3');
          console.log('   📥 Empfängt: target_power (jetzt gemessener/manipulierter Wert)');
          console.log('   🤝 Intelligence-Script v2.0 sendet korrekte Messwerte');
          console.log('   📊 Monitor-Script überwacht und steuert');
          console.log('');
          console.log('🔄 v2.0.1 KRITISCHER FIX:');
          console.log('   🚨 0W-Bug repariert: 0W ist ein gültiger Wert!');
          console.log('   📊 Fallback nur noch bei null/undefined');
          console.log('   🔋 SOC-Schutz funktioniert jetzt korrekt');
          console.log('   📝 Verbessertes Logging mit SOC-Info');
          console.log('=====================================');
          
          // Geteilte Datenpunkte erstellen
          createSharedDatapoints();
          
          // HTTP Server starten
          try {
              coreState.httpServer = createStableHTTPServer();
              coreState.httpServer.listen(CORE_CONFIG.httpPort, () => {
                  console.log('✅ HTTP Server auf Port ' + CORE_CONFIG.httpPort);
              });
          } catch (error) {
              console.error('❌ HTTP Server Start-Fehler:', error.message);
              // Trotzdem weitermachen - UDP könnte funktionieren
          }
          
          // Multi-UDP Server starten
          const dgram = require('dgram');
          
          try {
              coreState.udpSocket1 = dgram.createSocket('udp4');
              coreState.udpSocket1.bind(CORE_CONFIG.udpPort1, () => {
                  console.log('✅ UDP Port ' + CORE_CONFIG.udpPort1 + ' (FW <= v224)');
              });
              coreState.udpSocket1.on('message', (msg, rinfo) => {
                  handleStableUDPMessage(msg, rinfo, coreState.udpSocket1);
              });
          } catch (error) {
              console.error('❌ UDP1 Fehler:', error.message);
          }
          
          try {
              coreState.udpSocket2 = dgram.createSocket('udp4');
              coreState.udpSocket2.bind(CORE_CONFIG.udpPort2, () => {
                  console.log('✅ UDP Port ' + CORE_CONFIG.udpPort2 + ' (FW >= v226)');
              });
              coreState.udpSocket2.on('message', (msg, rinfo) => {
                  handleStableUDPMessage(msg, rinfo, coreState.udpSocket2);
              });
          } catch (error) {
              console.error('❌ UDP2 Fehler:', error.message);
          }
          
          try {
              coreState.udpSocket3 = dgram.createSocket('udp4');
              coreState.udpSocket3.bind(CORE_CONFIG.udpPort3, () => {
                  console.log('✅ UDP Port ' + CORE_CONFIG.udpPort3 + ' (Fallback)');
              });
              coreState.udpSocket3.on('message', (msg, rinfo) => {
                  handleStableUDPMessage(msg, rinfo, coreState.udpSocket3);
              });
          } catch (error) {
              console.error('❌ UDP3 Fehler:', error.message);
          }
          
          // Status setzen
          setState(CORE_CONFIG.SHARED_PREFIX + 'core_status', 'running');
          setState(CORE_CONFIG.SHARED_PREFIX + 'core_active', true);
          
          // Haupt-Loop starten
          setInterval(readBasicPowerValues, CORE_CONFIG.UPDATE_INTERVAL);
          
          // Sofort ersten Wert lesen
          setTimeout(readBasicPowerValues, 1000);
          
          console.log('\n🎯 CORE-ENGINE v2.0.1 AKTIV - 0W-BUG REPARIERT!');
          console.log('💡 Basis-CT funktioniert - Intelligence-Script v2.0 sendet korrekte Messwerte');
          console.log('🛡️ CRASH-SICHER: Basis-CT läuft auch wenn andere Scripts crashen');
          console.log('📊 Phasenverteilung: Shelly-basiert oder 66%/20%/14% Fallback');
          console.log('🔧 Kompatibel mit neuer Intelligence-Regelungslogik');
          console.log('🚨 KRITISCHER 0W-BUG REPARIERT: SOC-Schutz funktioniert jetzt!');
          console.log('=====================================\n');
      }
      
      function stopCoreEngine() {
          try {
              if (coreState.httpServer) coreState.httpServer.close();
              if (coreState.udpSocket1) coreState.udpSocket1.close();
              if (coreState.udpSocket2) coreState.udpSocket2.close();
              if (coreState.udpSocket3) coreState.udpSocket3.close();
              
              setState(CORE_CONFIG.SHARED_PREFIX + 'core_status', 'stopped');
              setState(CORE_CONFIG.SHARED_PREFIX + 'core_active', false);
              
              console.log('🛑 MARSTEK-Core-Engine v2.0 beendet');
          } catch (error) {
              console.error('❌ Stop-Fehler:', error.message);
          }
      }
      
      // ===================================================
      // SCRIPT START
      // ===================================================
      
      startCoreEngine();
      
      onStop(() => {
          stopCoreEngine();
      });
      
      // ===================================================
      // KONFIGURATIONSHINWEISE FÜR FORUM-NUTZER:
      // ===================================================
      /*
      WICHTIGE ANPASSUNGEN NÖTIG:
      
      1. SHELLY-GERÄTE-ID ANPASSEN:
         Zeile 14: shellyInstance: 'shelly.0.SHEM-3#XXXXXXXXXXXX#1'
         → Ersetze XXXXXXXXXXXX durch deine echte Shelly-Geräte-ID
         
      2. TIBBER-PFAD PRÜFEN:
         Zeile 15: tibberPowerPath: 'tibberlink.0.LocalPulse.0.Power'
         → Prüfe ob dein Tibber-Adapter denselben Pfad verwendet
         
      3. SHARED-PREFIX ANPASSEN:
         Zeile 25: SHARED_PREFIX: '0_userdata.0.marstek_V-E.shared.'
         → Passe den Prefix an deine ioBroker-Struktur an
         
      4. SHELLY-GERÄTE-ID FINDEN:
         - In ioBroker: Objekte → shelly.0 → SHEM-3#[DEINE-ID]#1
         - Oder im Shelly-Adapter unter "Instanzen"
         
      5. TIBBER-PFAD FINDEN:
         - In ioBroker: Objekte → tibberlink.0 → LocalPulse.0 → Power
         - Oder deinen entsprechenden Stromzähler-Pfad
      */
      
      G Offline
      G Offline
      Gismoh
      schrieb am zuletzt editiert von
      #18

      @gismoh
      2-MARSTEK-Intelligence:

      // ===================================================
      // MARSTEK-Intelligence v2.0 - KORREKTE REGELUNGSLOGIK
      // ===================================================
      // 
      // 🧠 ZWECK: INTELLIGENTE 0W-REGELUNG (KORREKT IMPLEMENTIERT!)
      // ✅ GRUNDLEGENDE ÄNDERUNG: Sendet gemessenen Netzbezug statt Sollwerte
      // ✅ SOC-Intelligence (Werte-Manipulation statt falsche Berechnungen)
      // ✅ Intelligente Begrenzung (min/max des gemessenen Werts)
      // ✅ Anti-Oszillations-Glättung (des Tibber-Werts)
      // ✅ Tasmota Reality-Check für Effizienz-Monitoring
      // ✅ 0W-Metriken & Tagesstatistiken
      // 
      // 🔧 KERNPRINZIP: MARSTEK regelt selbst auf 0W - wir senden nur IST-Werte!
      // 
      // ===================================================
      
      // KONFIGURATION
      const INTEL_CONFIG = {
          // Hardware für Reality-Check - BITTE ANPASSEN!
          tasmotaXXXX: 'sonoff.0.TasmotaXXX-MSTXXXX.ENERGY_Power',  // ← Deine Tasmota-Geräte hier eintragen
          tasmotayyyy: 'sonoff.0.TasmotaXXX-MSTXXXX.ENERGY_Power',  // ← Optional: zweites Gerät
          
          // Intelligente Begrenzung (des gemessenen Werts)
          POWER_LIMIT: 750,              // Max Netzbezug/Einspeisung die gemeldet wird
          HYSTERESIS_ENABLED: true,      
          HYSTERESIS_OFFSET: 75,         // 750W→825W Grenze, 675W zurück
          
          // ⭐ ANTI-OSZILLATIONS-GLÄTTUNG (des Tibber-Werts) ⭐
          SMOOTHING_ENABLED: true,       // Glättung aktivieren
          SMOOTH_FACTOR: 0.3,            // Glättungsfaktor für Tibber-Wert
          THROTTLE_INTERVAL: 4000,       // 4s Sendepause (MARSTEK-Rhythmus)
          DEAD_ZONE_WATTS: 50,           // Kleine Änderungen ignorieren
          MAX_CHANGE_PER_CYCLE: 200,     // Max Änderung pro Zyklus
          
          // ⭐ SOC-INTELLIGENCE (Werte-Manipulation) ⭐
          SOC_PROTECTION_ENABLED: true,  // SOC-Schutz aktiv
          SOC_HIGH_THRESHOLD: 95,        // Ab 95% SOC Ladung verhindern
          SOC_LOW_THRESHOLD: 10,         // Ab 10% SOC Entladung reduzieren
          
          // Features
          CLOUD_SMOOTHING: true,         // Wolken-Glättung
          TASMOTA_REALITY_CHECK: true,   // Effizienz-Monitoring
          ZERO_WATT_FOCUS: true,         // 0W-Metriken
          
          // Timing
          UPDATE_INTERVAL: 3000,
          
          // Kommunikation - BITTE ANPASSEN!
          SHARED_PREFIX: '0_userdata.0.marstek_V-E.shared.',        // ← Dein Shared-Prefix hier eintragen
          INTEL_PREFIX: '0_userdata.0.marstek_V-E.intel.',          // ← Dein Intelligence-Prefix hier eintragen
          
          // Logging
          LOG_INTELLIGENCE: true,
          LOG_SOC_ACTIONS: true,
          LOG_SMOOTHING: false           // Reduziertes Logging
      };
      
      // INTELLIGENCE STATE
      let intelState = {
          // Von Core empfangen
          tibberCurrent: 0,
          tibberRaw: 0,
          shellyL1: 0,
          shellyL2: 0,
          shellyL3: 0,
          coreActive: false,
          
          // ⭐ NEUE LOGIK: Gemessener Wert (geglättet/manipuliert) ⭐
          reportedPower: 0,              // Was an MARSTEK gesendet wird
          lastReportedPower: 0,          // Letzter gesendeter Wert
          limitingActive: false,         // Begrenzung aktiv
          
          // Glättung
          smoothingHistory: [],          // Historie für Glättung
          smoothedTibber: 0,            // Geglätteter Tibber-Wert
          lastSendTime: 0,              // Letztes Senden (Throttling)
          
          // SOC-Intelligence
          deviceSoc: 0,                 // SOC vom Monitor
          socActionActive: false,       // SOC-Aktion aktiv
          lastSocReason: "",           // Grund der SOC-Aktion
          
          // Wolken-Erkennung
          cloudModeActive: false,
          pvHistory: [],
          lastCloudLog: 0,
          
          // Tasmota Reality-Check (nur Monitoring)
          tasmotaXXXXPower: 0,
          tasmotayyyyPower: 0,
          storageEfficiency: 0,
          lastEfficiencyLog: 0,
          
          // Metriken
          zeroWattTime: 0,
          dailyNetPurchase: 0,
          dailyAdjustments: 0,
          lastMetricReset: Date.now(),
          bestDailyResult: 999,
          lastMetricUpdate: 0,
          limitingActivations: 0,
          totalLimitingTime: 0,
          
          // Status
          intelActive: true,
          lastUpdate: 0
      };
      
      // ===================================================
      // ROBUSTER STATE-SETTER
      // ===================================================
      
      function safeSetState(id, value) {
          if (existsState(id)) {
              try {
                  setState(id, value);
              } catch (e) {
                  console.warn(`⚠️ Intelligence safeSetState: Fehler beim Setzen von ${id}: ${e.message}`);
              }
          }
      }
      
      // ===================================================
      // INTELLIGENCE DATENPUNKTE
      // ===================================================
      
      function createIntelligenceDatapoints() {
          const prefix = INTEL_CONFIG.INTEL_PREFIX;
          
          const datapoints = [
              // Konfiguration
              { name: 'power_limit', value: INTEL_CONFIG.POWER_LIMIT, desc: '⚡ Leistungsgrenze [W]' },
              { name: 'smoothing_enabled', value: INTEL_CONFIG.SMOOTHING_ENABLED, desc: '🌊 Glättung aktiv' },
              { name: 'soc_protection_enabled', value: INTEL_CONFIG.SOC_PROTECTION_ENABLED, desc: '🔋 SOC-Schutz aktiv' },
              
              // Status
              { name: 'intel_active', value: true, desc: '🧠 Intelligence läuft' },
              { name: 'limiting_active', value: false, desc: '🔒 Begrenzung aktiv' },
              { name: 'cloud_mode_active', value: false, desc: '☁️ Wolken-Modus aktiv' },
              { name: 'soc_action_active', value: false, desc: '🔋 SOC-Aktion aktiv' },
              
              // Berechnungen
              { name: 'tibber_raw', value: 0, desc: '📊 Roher Tibber-Wert [W]' },
              { name: 'tibber_smoothed', value: 0, desc: '🌊 Geglätteter Tibber [W]' },
              { name: 'reported_power', value: 0, desc: '📤 An MARSTEK gesendeter Wert [W]' },
              { name: 'power_change', value: 0, desc: '📈 Leistungsänderung [W]' },
              
              // SOC-Intelligence
              { name: 'device_soc', value: 0, desc: '🔋 Speicher SOC [%]' },
              { name: 'soc_reason', value: '', desc: '📝 SOC-Aktion Grund' },
              
              // Tasmota Reality-Check (Monitoring)
              { name: 'tasmota_power', value: 0, desc: '📊 Tasmota Messung [W]' },
              { name: 'storage_efficiency', value: 0, desc: '📈 Speicher-Effizienz [%]' },
              { name: 'storage_responds', value: false, desc: '✅ Speicher reagiert' },
              
              // Metriken
              { name: 'zero_watt_time_percent', value: 0, desc: '🎯 0W-Zeit [%]' },
              { name: 'daily_net_purchase_kwh', value: 0, desc: '⚡ Netzbezug [kWh]' },
              { name: 'daily_adjustments', value: 0, desc: '🔄 Regelzyklen' },
              { name: 'limiting_activations_today', value: 0, desc: '🔒 Begrenzungs-Aktivierungen' },
              { name: 'limiting_time_percent', value: 0, desc: '⏱️ Zeit mit Begrenzung [%]' },
              { name: 'best_daily_result', value: 999, desc: '🏆 Bester Tageswert [kWh]' }
          ];
          
          datapoints.forEach(dp => {
              try {
                  createState(prefix + dp.name, dp.value, {
                      name: dp.desc,
                      type: typeof dp.value,
                      read: true,
                      write: true,
                      desc: `MARSTEK Intelligence v2.0 - ${dp.desc}`
                  });
              } catch (error) {
                  // State existiert bereits
              }
          });
      }
      
      // ===================================================
      // KOMMUNIKATION MIT CORE
      // ===================================================
      
      function readFromCore() {
          try {
              const prefix = INTEL_CONFIG.SHARED_PREFIX;
              
              intelState.tibberCurrent = getState(prefix + 'tibber_current').val || 0;
              intelState.tibberRaw = getState(prefix + 'tibber_raw').val || 0;
              intelState.shellyL1 = getState(prefix + 'shelly_l1').val || 0;
              intelState.shellyL2 = getState(prefix + 'shelly_l2').val || 0;
              intelState.shellyL3 = getState(prefix + 'shelly_l3').val || 0;
              intelState.coreActive = getState(prefix + 'core_active').val || false;
              
              // SOC-Werte vom Monitor lesen
              try {
                  const monitorPrefix = '0_userdata.0.marstek_V-E.monitor.';  // ← ANPASSBAR
                  intelState.deviceSoc = getState(monitorPrefix + 'device_soc').val || 0;
                  safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'device_soc', intelState.deviceSoc);
              } catch (error) {
                  intelState.deviceSoc = 0;
              }
              
              return true;
          } catch (error) {
              console.error('❌ Intelligence: Fehler beim Lesen von Core:', error.message);
              return false;
          }
      }
      
      function sendToCore() {
          try {
              const prefix = INTEL_CONFIG.SHARED_PREFIX;
              
              // ⭐ KERNÄNDERUNG: Sende gemessenen/manipulierten Wert (nicht Sollwert!) ⭐
              safeSetState(prefix + 'target_power', intelState.reportedPower);
              safeSetState(prefix + 'correction_factor', 1); // Nicht mehr verwendet
              safeSetState(prefix + 'limiting_active', intelState.limitingActive);
              
              return true;
          } catch (error) {
              console.error('❌ Intelligence: Fehler beim Senden an Core:', error.message);
              return false;
          }
      }
      
      // ===================================================
      // ⭐ TIBBER-WERT GLÄTTUNG (ANTI-OSZILLATION) ⭐
      // ===================================================
      
      function smoothTibberValue(currentValue) {
          if (!INTEL_CONFIG.SMOOTHING_ENABLED) return currentValue;
          
          try {
              const now = Date.now();
              
              // History aktualisieren (letzte 30s)
              intelState.smoothingHistory.push({ time: now, value: currentValue });
              const thirtySecondsAgo = now - 30000;
              intelState.smoothingHistory = intelState.smoothingHistory.filter(h => h.time > thirtySecondsAgo);
              
              if (intelState.smoothingHistory.length < 2) {
                  intelState.smoothedTibber = currentValue;
                  return currentValue;
              }
              
              // Glättung anwenden
              const lastSmoothed = intelState.smoothedTibber || currentValue;
              const smoothed = lastSmoothed * (1 - INTEL_CONFIG.SMOOTH_FACTOR) + currentValue * INTEL_CONFIG.SMOOTH_FACTOR;
              
              intelState.smoothedTibber = smoothed;
              
              // Logging bei größeren Änderungen
              const change = Math.abs(currentValue - smoothed);
              if (INTEL_CONFIG.LOG_SMOOTHING && change > 100) {
                  console.log(`🌊 Intelligence: Tibber-Glättung ${Math.round(currentValue)}W → ${Math.round(smoothed)}W`);
              }
              
              return smoothed;
              
          } catch (error) {
              console.error('❌ Intelligence: Glättung Fehler:', error.message);
              return currentValue;
          }
      }
      
      // ===================================================
      // ⭐ SOC-INTELLIGENCE (WERTE-MANIPULATION) ⭐
      // ===================================================
      
      function applySocProtection(measuredValue) {
          if (!INTEL_CONFIG.SOC_PROTECTION_ENABLED) {
              intelState.socActionActive = false;
              return measuredValue;
          }
          
          try {
              const soc = intelState.deviceSoc;
              let manipulatedValue = measuredValue;
              let socReason = "";
              let socActive = false;
              
              // ⭐ SOC >95%: LADUNG VERHINDERN durch Werte-Manipulation ⭐
              if (soc >= INTEL_CONFIG.SOC_HIGH_THRESHOLD && measuredValue < 0) {
                  // Negative Werte (Einspeisung) → auf 0 setzen = keine Ladung
                  manipulatedValue = 0;
                  socReason = `SOC ${soc}% ≥${INTEL_CONFIG.SOC_HIGH_THRESHOLD}% - Einspeisung unterdrückt (Ladeschutz)`;
                  socActive = true;
                  
              } 
              // ⭐ SOC <10%: ENTLADUNG REDUZIEREN ⭐ 
              else if (soc <= INTEL_CONFIG.SOC_LOW_THRESHOLD && measuredValue > 0) {
                  // Positive Werte (Netzbezug) → reduzieren = weniger Entladung
                  manipulatedValue = measuredValue * 0.5; // 50% reduzieren
                  socReason = `SOC ${soc}% ≤${INTEL_CONFIG.SOC_LOW_THRESHOLD}% - Netzbezug reduziert (Entladeschutz)`;
                  socActive = true;
                  
              } else {
                  socReason = `SOC ${soc}% - normale Regelung`;
                  socActive = false;
              }
              
              // Status aktualisieren
              intelState.socActionActive = socActive;
              
              // Logging bei Zustandsänderung
              if (socReason !== intelState.lastSocReason) {
                  if (INTEL_CONFIG.LOG_SOC_ACTIONS && socActive) {
                      console.log(`🔋 Intelligence: ${socReason} - ${Math.round(measuredValue)}W → ${Math.round(manipulatedValue)}W`);
                  }
                  intelState.lastSocReason = socReason;
              }
              
              // Datenpunkte aktualisieren
              safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'soc_action_active', socActive);
              safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'soc_reason', socReason);
              
              return manipulatedValue;
              
          } catch (error) {
              console.error('❌ Intelligence: SOC-Schutz Fehler:', error.message);
              return measuredValue;
          }
      }
      
      // ===================================================
      // INTELLIGENTE BEGRENZUNG (des gemessenen Werts)
      // ===================================================
      
      function applyIntelligentLimiting(measuredValue) {
          try {
              const limit = INTEL_CONFIG.POWER_LIMIT;
              const hysteresis = INTEL_CONFIG.HYSTERESIS_OFFSET;
              const now = Date.now();
              
              // Begrenzung prüfen
              let needsLimiting = false;
              
              if (INTEL_CONFIG.HYSTERESIS_ENABLED) {
                  if (!intelState.limitingActive) {
                      // Begrenzung einschalten: bei 750W
                      needsLimiting = Math.abs(measuredValue) > limit;
                  } else {
                      // Begrenzung ausschalten: erst bei 675W (75W Hysterese)
                      needsLimiting = Math.abs(measuredValue) >= (limit - hysteresis);
                  }
              } else {
                  needsLimiting = Math.abs(measuredValue) > limit;
              }
              
              // Status aktualisieren
              if (needsLimiting && !intelState.limitingActive) {
                  if (INTEL_CONFIG.LOG_INTELLIGENCE) {
                      console.log(`🔒 Intelligence: Begrenzung aktiviert bei ${Math.round(measuredValue)}W (Limit: ${limit}W)`);
                  }
                  intelState.limitingActive = true;
                  intelState.limitingActivations++;
              } else if (!needsLimiting && intelState.limitingActive) {
                  if (INTEL_CONFIG.LOG_INTELLIGENCE) {
                      console.log(`🔓 Intelligence: Begrenzung deaktiviert bei ${Math.round(measuredValue)}W`);
                  }
                  intelState.limitingActive = false;
              }
              
              if (intelState.limitingActive) {
                  intelState.totalLimitingTime += INTEL_CONFIG.UPDATE_INTERVAL;
              }
              
              // Wert begrenzen
              let limitedValue = measuredValue;
              if (needsLimiting) {
                  limitedValue = Math.max(-limit, Math.min(limit, measuredValue));
              }
              
              return limitedValue;
              
          } catch (error) {
              console.error('❌ Intelligence: Begrenzung Fehler:', error.message);
              return measuredValue;
          }
      }
      
      // ===================================================
      // THROTTLING (Sendepausen)
      // ===================================================
      
      function shouldThrottle() {
          const now = Date.now();
          const timeSinceLastSend = now - intelState.lastSendTime;
          
          if (timeSinceLastSend < INTEL_CONFIG.THROTTLE_INTERVAL) {
              return true; // Noch in Throttling-Phase
          }
          
          intelState.lastSendTime = now;
          return false;
      }
      
      function applyDeadZoneAndRateLimit(newValue) {
          const deadZone = INTEL_CONFIG.DEAD_ZONE_WATTS;
          const maxChange = INTEL_CONFIG.MAX_CHANGE_PER_CYCLE;
          
          // Dead-Zone prüfen
          const change = Math.abs(newValue - intelState.lastReportedPower);
          if (change < deadZone) {
              return intelState.lastReportedPower; // Keine Änderung
          }
          
          // Rate-Limiting
          const currentChange = newValue - intelState.lastReportedPower;
          if (Math.abs(currentChange) > maxChange) {
              const limitedChange = currentChange > 0 ? maxChange : -maxChange;
              return intelState.lastReportedPower + limitedChange;
          }
          
          return newValue;
      }
      
      // ===================================================
      // WOLKEN-ERKENNUNG (vereinfacht)
      // ===================================================
      
      function detectCloudMode() {
          if (!INTEL_CONFIG.CLOUD_SMOOTHING) return false;
          
          try {
              const now = Date.now();
              intelState.pvHistory.push({ time: now, value: intelState.tibberCurrent });
              
              // Nur letzte 60s behalten
              const sixtySecondsAgo = now - 60000;
              intelState.pvHistory = intelState.pvHistory.filter(h => h.time > sixtySecondsAgo);
              
              if (intelState.pvHistory.length < 6) return false;
              
              const recent = intelState.pvHistory.slice(-6);
              let rapidChanges = 0;
              
              for (let i = 1; i < recent.length; i++) {
                  const diff = Math.abs(recent[i].value - recent[i-1].value);
                  if (diff > 400) rapidChanges++;
              }
              
              const newCloudMode = rapidChanges >= 3;
              
              if (newCloudMode !== intelState.cloudModeActive) {
                  if (INTEL_CONFIG.LOG_INTELLIGENCE) {
                      console.log(`${newCloudMode ? '☁️ WOLKEN-MODUS' : '☀️ STABILER MODUS'} erkannt`);
                  }
                  intelState.cloudModeActive = newCloudMode;
                  safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'cloud_mode_active', newCloudMode);
              }
              
              return newCloudMode;
              
          } catch (error) {
              console.error('❌ Intelligence: Wolken-Erkennung Fehler:', error.message);
              return false;
          }
      }
      
      // ===================================================
      // TASMOTA REALITY-CHECK (nur Monitoring)
      // ===================================================
      
      function readTasmotaValues() {
          if (!INTEL_CONFIG.TASMOTA_REALITY_CHECK) return;
          
          try {
              intelState.tasmotaXXXXPower = getState(INTEL_CONFIG.tasmotaXXXX).val || 0;
              intelState.tasmotayyyyPower = getState(INTEL_CONFIG.tasmotayyyy).val || 0;
              
              safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'tasmota_power', Math.round(intelState.tasmotaXXXXPower));
              
              // Effizienz berechnen (nur Monitoring)
              const expectedPower = Math.abs(intelState.reportedPower);
              const actualPower = Math.abs(intelState.tasmotaXXXXPower);
              
              if (expectedPower > 50) {
                  const efficiency = Math.min(100, (actualPower / expectedPower) * 100);
                  const responds = efficiency > 40;
                  
                  intelState.storageEfficiency = efficiency;
                  
                  safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'storage_efficiency', Math.round(efficiency));
                  safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'storage_responds', responds);
                  
                  // Logging alle 60s
                  const now = Date.now();
                  if ((!intelState.lastEfficiencyLog || now - intelState.lastEfficiencyLog > 60000)) {
                      if (INTEL_CONFIG.LOG_INTELLIGENCE) {
                          const direction = intelState.reportedPower < 0 ? "Laden" : "Entladen";
                          const status = responds ? "✅" : "❌";
                          console.log(`📊 Intelligence: ${direction} Effizienz ${Math.round(expectedPower)}W → ${Math.round(actualPower)}W = ${Math.round(efficiency)}% ${status}`);
                      }
                      intelState.lastEfficiencyLog = now;
                  }
              }
              
          } catch (error) {
              console.error('❌ Intelligence: Tasmota-Lesefehler:', error.message);
          }
      }
      
      // ===================================================
      // 0W-METRIKEN & STATISTIKEN
      // ===================================================
      
      function updateZeroWattMetrics() {
          if (!INTEL_CONFIG.ZERO_WATT_FOCUS) return;
          
          try {
              const now = Date.now();
              const prefix = INTEL_CONFIG.INTEL_PREFIX;
              
              // Tagesreset prüfen
              const today = new Date().toDateString();
              const lastResetDay = new Date(intelState.lastMetricReset).toDateString();
              
              if (today !== lastResetDay) {
                  if (INTEL_CONFIG.LOG_INTELLIGENCE) {
                      console.log(`📊 Intelligence: Tages-Reset - Netzbezug gestern: ${intelState.dailyNetPurchase.toFixed(3)} kWh`);
                  }
                  
                  if (intelState.dailyNetPurchase < intelState.bestDailyResult) {
                      intelState.bestDailyResult = intelState.dailyNetPurchase;
                      safeSetState(prefix + 'best_daily_result', Math.round(intelState.bestDailyResult * 1000) / 1000);
                  }
                  
                  // Reset
                  intelState.dailyNetPurchase = 0;
                  intelState.dailyAdjustments = 0;
                  intelState.zeroWattTime = 0;
                  intelState.limitingActivations = 0;
                  intelState.totalLimitingTime = 0;
                  intelState.lastMetricReset = now;
              }
              
              // 0W-Zeit messen
              if (Math.abs(intelState.tibberCurrent) <= 30) {
                  intelState.zeroWattTime += INTEL_CONFIG.UPDATE_INTERVAL;
              }
              
              // Netzbezug summieren
              if (intelState.tibberCurrent > 0) {
                  const kWhIncrement = (intelState.tibberCurrent * INTEL_CONFIG.UPDATE_INTERVAL) / (1000 * 3600);
                  intelState.dailyNetPurchase += kWhIncrement;
              }
              
              intelState.dailyAdjustments++;
              
              // Datenpunkte aktualisieren (alle 60s)
              if (!intelState.lastMetricUpdate || now - intelState.lastMetricUpdate > 60000) {
                  const runtimeMs = now - intelState.lastMetricReset;
                  const zeroWattPercent = (intelState.zeroWattTime / runtimeMs) * 100;
                  const limitPercent = (intelState.totalLimitingTime / runtimeMs) * 100;
                  
                  safeSetState(prefix + 'zero_watt_time_percent', Math.round(zeroWattPercent * 10) / 10);
                  safeSetState(prefix + 'daily_net_purchase_kwh', Math.round(intelState.dailyNetPurchase * 1000) / 1000);
                  safeSetState(prefix + 'daily_adjustments', intelState.dailyAdjustments);
                  safeSetState(prefix + 'limiting_activations_today', intelState.limitingActivations);
                  safeSetState(prefix + 'limiting_time_percent', Math.round(limitPercent * 10) / 10);
                  
                  intelState.lastMetricUpdate = now;
              }
              
          } catch (error) {
              console.error('❌ Intelligence: Metriken-Update Fehler:', error.message);
          }
      }
      
      // ===================================================
      // ⭐ HAUPT-INTELLIGENCE-LOOP (NEUE LOGIK!) ⭐
      // ===================================================
      
      function runIntelligenceLoop() {
          try {
              // 1. Von Core lesen
              if (!readFromCore()) {
                  return;
              }
              
              if (!intelState.coreActive) {
                  if (INTEL_CONFIG.LOG_INTELLIGENCE) {
                      console.log('⚠️ Intelligence: Core nicht aktiv - warte...');
                  }
                  return;
              }
              
              // 2. Tasmota-Werte lesen (nur Monitoring)
              readTasmotaValues();
              
              // 3. Wolken-Erkennung
              detectCloudMode();
              
              // 4. ⭐ NEUE KERNLOGIK: Gemessenen Wert verarbeiten ⭐
              
              // 4a. Tibber-Wert glätten (Anti-Oszillation)
              const smoothedTibber = smoothTibberValue(intelState.tibberCurrent);
              
              // 4b. ⭐ KRITISCH: Intelligente Begrenzung anwenden (ZUERST!) ⭐
              const limitedValue = applyIntelligentLimiting(smoothedTibber);
              
              // 4c. SOC-Schutz anwenden (Werte-Manipulation)
              const socProtectedValue = applySocProtection(limitedValue);
              
              // 4d. Throttling & Dead-Zone
              if (shouldThrottle()) {
                  // Zu früh - nicht senden
                  return;
              }
              
              const finalValue = applyDeadZoneAndRateLimit(socProtectedValue);
              
              // 5. ⭐ KERNPRINZIP: Sende gemessenen/manipulierten Wert (NICHT Sollwert!) ⭐
              intelState.reportedPower = finalValue;
              intelState.lastReportedPower = finalValue;
              
              // 6. An Core senden
              sendToCore();
              
              // 7. Metriken aktualisieren
              updateZeroWattMetrics();
              
              // 8. Status-Updates
              const powerChange = finalValue - intelState.lastReportedPower;
              safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'tibber_raw', Math.round(intelState.tibberCurrent));
              safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'tibber_smoothed', Math.round(smoothedTibber));
              safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'reported_power', Math.round(finalValue));
              safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'power_change', Math.round(powerChange));
              safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'limiting_active', intelState.limitingActive);
              
              intelState.lastUpdate = Date.now();
              
              // Debug-Logging mit korrekter Reihenfolge
              if (INTEL_CONFIG.LOG_INTELLIGENCE && Math.abs(powerChange) > 50) {
                  console.log(`📤 Intelligence v2.0 FIX: Tibber ${Math.round(intelState.tibberCurrent)}W → Begrenzt ${Math.round(limitedValue)}W → SOC-Schutz ${Math.round(socProtectedValue)}W → Gesendet ${Math.round(finalValue)}W`);
              }
              
          } catch (error) {
              console.error('❌ Intelligence: Loop-Fehler:', error.message);
              // Fallback: Tibber-Wert direkt senden
              try {
                  intelState.reportedPower = intelState.tibberCurrent || 0;
                  sendToCore();
              } catch (fallbackError) {
                  console.error('❌ Intelligence: Auch Fallback fehlgeschlagen:', fallbackError.message);
              }
          }
      }
      
      // ===================================================
      // INTELLIGENCE START
      // ===================================================
      
      function startIntelligence() {
          console.log('🧠 MARSTEK-Intelligence v2.0 - KORREKTE REGELUNGSLOGIK\n');
          console.log('🎯 ZWECK: INTELLIGENTE 0W-REGELUNG');
          console.log('✅ KERNPRINZIP: Sendet gemessenen Netzbezug (nicht Sollwerte!)');
          console.log('✅ SOC-Intelligence (Werte-Manipulation für Schutz)');
          console.log('✅ Intelligente Begrenzung (des gemessenen Werts)');
          console.log('✅ Anti-Oszillations-Glättung (Tibber-Wert)');
          console.log('✅ Tasmota Reality-Check (Effizienz-Monitoring)');
          console.log('✅ 0W-Metriken & Tagesstatistiken');
          console.log('');
          console.log('🔗 KOMMUNIKATION:');
          console.log('   📥 Empfängt von Core: tibber_current (gemessener Netzbezug)');
          console.log('   📤 Sendet an Core: reported_power (manipulierter Messwert)');
          console.log('   🎯 MARSTEK regelt automatisch auf 0W');
          console.log('   ⚠️ Darf crashen ohne CT-Simulation zu stoppen!');
          console.log('=====================================');
          
          // Datenpunkte erstellen
          createIntelligenceDatapoints();
          
          // Status setzen
          safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'intel_active', true);
          
          // Haupt-Loop starten
          setInterval(runIntelligenceLoop, INTEL_CONFIG.UPDATE_INTERVAL);
          
          // Sofort starten
          setTimeout(runIntelligenceLoop, 2000);
          
          console.log('\n🧠 INTELLIGENCE v2.0 AKTIV!');
          console.log('💡 Neue Logik: Sendet Messwerte statt Sollwerte');
          console.log('🔧 Begrenzung: ±' + INTEL_CONFIG.POWER_LIMIT + 'W');
          console.log('🌊 Glättung: ' + (INTEL_CONFIG.SMOOTHING_ENABLED ? 'Aktiv (' + Math.round(INTEL_CONFIG.SMOOTH_FACTOR*100) + '%)' : 'Deaktiviert'));
          console.log('🔋 SOC-Schutz: ' + (INTEL_CONFIG.SOC_PROTECTION_ENABLED ? 'Aktiv' : 'Deaktiviert'));
          console.log('☁️ Wolken-Erkennung: ' + (INTEL_CONFIG.CLOUD_SMOOTHING ? 'Aktiv' : 'Deaktiviert'));
          console.log('📊 Reality-Check: ' + (INTEL_CONFIG.TASMOTA_REALITY_CHECK ? 'Aktiv' : 'Deaktiviert'));
          console.log('🎯 0W-Focus: ' + (INTEL_CONFIG.ZERO_WATT_FOCUS ? 'Aktiv' : 'Deaktiviert'));
          console.log('=====================================\n');
      }
      
      function stopIntelligence() {
          try {
              safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'intel_active', false);
              console.log('🛑 MARSTEK-Intelligence v2.0 beendet');
          } catch (error) {
              console.error('❌ Intelligence Stop-Fehler:', error.message);
          }
      }
      
      // ===================================================
      // SCRIPT START
      // ===================================================
      
      startIntelligence();
      
      onStop(() => {
          stopIntelligence();
      });
      
      // ===================================================
      // KONFIGURATIONSHINWEISE FÜR FORUM-NUTZER:
      // ===================================================
      /*
      WICHTIGE ANPASSUNGEN NÖTIG:
      
      1. TASMOTA-GERÄTE-PFADE ANPASSEN:
         Zeile 13: tasmotaXXXX: 'sonoff.0.TasmotaXXX-MSTXXXX.ENERGY_Power'
         Zeile 14: tasmotayyyy: 'sonoff.0.TasmotaXXX-MSTXXXX.ENERGY_Power'
         → Ersetze TasmotaXXX-MSTXXXX durch deine echten Tasmota-Geräte-Namen
         → Zweites Gerät ist optional - kann auch weggelassen werden
         
      2. PREFIXE ANPASSEN:
         Zeile 32: SHARED_PREFIX: '0_userdata.0.marstek_V-E.shared.'
         Zeile 33: INTEL_PREFIX: '0_userdata.0.marstek_V-E.intel.'
         → Passe die Prefixe an deine ioBroker-Struktur an
         
      3. MONITOR-PREFIX PRÜFEN:
         Zeile 189: const monitorPrefix = '0_userdata.0.marstek_V-E.monitor.';
         → Falls du ein Monitor-Script verwendest, passe den Pfad an
         
      4. TASMOTA-GERÄTE FINDEN:
         - In ioBroker: Objekte → sonoff.0 → TasmotaXXX-MSTXXXX → ENERGY_Power
         - Oder unter deinem Tasmota/MQTT-Adapter
         
      5. POWER_LIMIT ANPASSEN:
         Zeile 16: POWER_LIMIT: 750
         → Passe die Leistungsgrenze an deine Anlage an (in Watt)
         
      6. SOC-SCHWELLWERTE ANPASSEN:
         Zeile 26: SOC_HIGH_THRESHOLD: 95  (Ladeschutz ab X% SOC)
         Zeile 27: SOC_LOW_THRESHOLD: 10   (Entladeschutz ab X% SOC)
         → Passe an deine Batterie-Strategie an
      
      OPTIONAL FEATURES:
      - Wenn kein Tasmota vorhanden: TASMOTA_REALITY_CHECK: false setzen
      - Wenn kein SOC verfügbar: SOC_PROTECTION_ENABLED: false setzen
      - Logging reduzieren: LOG_INTELLIGENCE: false setzen
      */
      

      ioBroker auf: Lenovo ThinkCentre M910Q Tiny i5-7500T 16 GB mit proxmox in VM (Bookworm)

      G 1 Antwort Letzte Antwort
      0
      • G Gismoh

        @gismoh
        2-MARSTEK-Intelligence:

        // ===================================================
        // MARSTEK-Intelligence v2.0 - KORREKTE REGELUNGSLOGIK
        // ===================================================
        // 
        // 🧠 ZWECK: INTELLIGENTE 0W-REGELUNG (KORREKT IMPLEMENTIERT!)
        // ✅ GRUNDLEGENDE ÄNDERUNG: Sendet gemessenen Netzbezug statt Sollwerte
        // ✅ SOC-Intelligence (Werte-Manipulation statt falsche Berechnungen)
        // ✅ Intelligente Begrenzung (min/max des gemessenen Werts)
        // ✅ Anti-Oszillations-Glättung (des Tibber-Werts)
        // ✅ Tasmota Reality-Check für Effizienz-Monitoring
        // ✅ 0W-Metriken & Tagesstatistiken
        // 
        // 🔧 KERNPRINZIP: MARSTEK regelt selbst auf 0W - wir senden nur IST-Werte!
        // 
        // ===================================================
        
        // KONFIGURATION
        const INTEL_CONFIG = {
            // Hardware für Reality-Check - BITTE ANPASSEN!
            tasmotaXXXX: 'sonoff.0.TasmotaXXX-MSTXXXX.ENERGY_Power',  // ← Deine Tasmota-Geräte hier eintragen
            tasmotayyyy: 'sonoff.0.TasmotaXXX-MSTXXXX.ENERGY_Power',  // ← Optional: zweites Gerät
            
            // Intelligente Begrenzung (des gemessenen Werts)
            POWER_LIMIT: 750,              // Max Netzbezug/Einspeisung die gemeldet wird
            HYSTERESIS_ENABLED: true,      
            HYSTERESIS_OFFSET: 75,         // 750W→825W Grenze, 675W zurück
            
            // ⭐ ANTI-OSZILLATIONS-GLÄTTUNG (des Tibber-Werts) ⭐
            SMOOTHING_ENABLED: true,       // Glättung aktivieren
            SMOOTH_FACTOR: 0.3,            // Glättungsfaktor für Tibber-Wert
            THROTTLE_INTERVAL: 4000,       // 4s Sendepause (MARSTEK-Rhythmus)
            DEAD_ZONE_WATTS: 50,           // Kleine Änderungen ignorieren
            MAX_CHANGE_PER_CYCLE: 200,     // Max Änderung pro Zyklus
            
            // ⭐ SOC-INTELLIGENCE (Werte-Manipulation) ⭐
            SOC_PROTECTION_ENABLED: true,  // SOC-Schutz aktiv
            SOC_HIGH_THRESHOLD: 95,        // Ab 95% SOC Ladung verhindern
            SOC_LOW_THRESHOLD: 10,         // Ab 10% SOC Entladung reduzieren
            
            // Features
            CLOUD_SMOOTHING: true,         // Wolken-Glättung
            TASMOTA_REALITY_CHECK: true,   // Effizienz-Monitoring
            ZERO_WATT_FOCUS: true,         // 0W-Metriken
            
            // Timing
            UPDATE_INTERVAL: 3000,
            
            // Kommunikation - BITTE ANPASSEN!
            SHARED_PREFIX: '0_userdata.0.marstek_V-E.shared.',        // ← Dein Shared-Prefix hier eintragen
            INTEL_PREFIX: '0_userdata.0.marstek_V-E.intel.',          // ← Dein Intelligence-Prefix hier eintragen
            
            // Logging
            LOG_INTELLIGENCE: true,
            LOG_SOC_ACTIONS: true,
            LOG_SMOOTHING: false           // Reduziertes Logging
        };
        
        // INTELLIGENCE STATE
        let intelState = {
            // Von Core empfangen
            tibberCurrent: 0,
            tibberRaw: 0,
            shellyL1: 0,
            shellyL2: 0,
            shellyL3: 0,
            coreActive: false,
            
            // ⭐ NEUE LOGIK: Gemessener Wert (geglättet/manipuliert) ⭐
            reportedPower: 0,              // Was an MARSTEK gesendet wird
            lastReportedPower: 0,          // Letzter gesendeter Wert
            limitingActive: false,         // Begrenzung aktiv
            
            // Glättung
            smoothingHistory: [],          // Historie für Glättung
            smoothedTibber: 0,            // Geglätteter Tibber-Wert
            lastSendTime: 0,              // Letztes Senden (Throttling)
            
            // SOC-Intelligence
            deviceSoc: 0,                 // SOC vom Monitor
            socActionActive: false,       // SOC-Aktion aktiv
            lastSocReason: "",           // Grund der SOC-Aktion
            
            // Wolken-Erkennung
            cloudModeActive: false,
            pvHistory: [],
            lastCloudLog: 0,
            
            // Tasmota Reality-Check (nur Monitoring)
            tasmotaXXXXPower: 0,
            tasmotayyyyPower: 0,
            storageEfficiency: 0,
            lastEfficiencyLog: 0,
            
            // Metriken
            zeroWattTime: 0,
            dailyNetPurchase: 0,
            dailyAdjustments: 0,
            lastMetricReset: Date.now(),
            bestDailyResult: 999,
            lastMetricUpdate: 0,
            limitingActivations: 0,
            totalLimitingTime: 0,
            
            // Status
            intelActive: true,
            lastUpdate: 0
        };
        
        // ===================================================
        // ROBUSTER STATE-SETTER
        // ===================================================
        
        function safeSetState(id, value) {
            if (existsState(id)) {
                try {
                    setState(id, value);
                } catch (e) {
                    console.warn(`⚠️ Intelligence safeSetState: Fehler beim Setzen von ${id}: ${e.message}`);
                }
            }
        }
        
        // ===================================================
        // INTELLIGENCE DATENPUNKTE
        // ===================================================
        
        function createIntelligenceDatapoints() {
            const prefix = INTEL_CONFIG.INTEL_PREFIX;
            
            const datapoints = [
                // Konfiguration
                { name: 'power_limit', value: INTEL_CONFIG.POWER_LIMIT, desc: '⚡ Leistungsgrenze [W]' },
                { name: 'smoothing_enabled', value: INTEL_CONFIG.SMOOTHING_ENABLED, desc: '🌊 Glättung aktiv' },
                { name: 'soc_protection_enabled', value: INTEL_CONFIG.SOC_PROTECTION_ENABLED, desc: '🔋 SOC-Schutz aktiv' },
                
                // Status
                { name: 'intel_active', value: true, desc: '🧠 Intelligence läuft' },
                { name: 'limiting_active', value: false, desc: '🔒 Begrenzung aktiv' },
                { name: 'cloud_mode_active', value: false, desc: '☁️ Wolken-Modus aktiv' },
                { name: 'soc_action_active', value: false, desc: '🔋 SOC-Aktion aktiv' },
                
                // Berechnungen
                { name: 'tibber_raw', value: 0, desc: '📊 Roher Tibber-Wert [W]' },
                { name: 'tibber_smoothed', value: 0, desc: '🌊 Geglätteter Tibber [W]' },
                { name: 'reported_power', value: 0, desc: '📤 An MARSTEK gesendeter Wert [W]' },
                { name: 'power_change', value: 0, desc: '📈 Leistungsänderung [W]' },
                
                // SOC-Intelligence
                { name: 'device_soc', value: 0, desc: '🔋 Speicher SOC [%]' },
                { name: 'soc_reason', value: '', desc: '📝 SOC-Aktion Grund' },
                
                // Tasmota Reality-Check (Monitoring)
                { name: 'tasmota_power', value: 0, desc: '📊 Tasmota Messung [W]' },
                { name: 'storage_efficiency', value: 0, desc: '📈 Speicher-Effizienz [%]' },
                { name: 'storage_responds', value: false, desc: '✅ Speicher reagiert' },
                
                // Metriken
                { name: 'zero_watt_time_percent', value: 0, desc: '🎯 0W-Zeit [%]' },
                { name: 'daily_net_purchase_kwh', value: 0, desc: '⚡ Netzbezug [kWh]' },
                { name: 'daily_adjustments', value: 0, desc: '🔄 Regelzyklen' },
                { name: 'limiting_activations_today', value: 0, desc: '🔒 Begrenzungs-Aktivierungen' },
                { name: 'limiting_time_percent', value: 0, desc: '⏱️ Zeit mit Begrenzung [%]' },
                { name: 'best_daily_result', value: 999, desc: '🏆 Bester Tageswert [kWh]' }
            ];
            
            datapoints.forEach(dp => {
                try {
                    createState(prefix + dp.name, dp.value, {
                        name: dp.desc,
                        type: typeof dp.value,
                        read: true,
                        write: true,
                        desc: `MARSTEK Intelligence v2.0 - ${dp.desc}`
                    });
                } catch (error) {
                    // State existiert bereits
                }
            });
        }
        
        // ===================================================
        // KOMMUNIKATION MIT CORE
        // ===================================================
        
        function readFromCore() {
            try {
                const prefix = INTEL_CONFIG.SHARED_PREFIX;
                
                intelState.tibberCurrent = getState(prefix + 'tibber_current').val || 0;
                intelState.tibberRaw = getState(prefix + 'tibber_raw').val || 0;
                intelState.shellyL1 = getState(prefix + 'shelly_l1').val || 0;
                intelState.shellyL2 = getState(prefix + 'shelly_l2').val || 0;
                intelState.shellyL3 = getState(prefix + 'shelly_l3').val || 0;
                intelState.coreActive = getState(prefix + 'core_active').val || false;
                
                // SOC-Werte vom Monitor lesen
                try {
                    const monitorPrefix = '0_userdata.0.marstek_V-E.monitor.';  // ← ANPASSBAR
                    intelState.deviceSoc = getState(monitorPrefix + 'device_soc').val || 0;
                    safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'device_soc', intelState.deviceSoc);
                } catch (error) {
                    intelState.deviceSoc = 0;
                }
                
                return true;
            } catch (error) {
                console.error('❌ Intelligence: Fehler beim Lesen von Core:', error.message);
                return false;
            }
        }
        
        function sendToCore() {
            try {
                const prefix = INTEL_CONFIG.SHARED_PREFIX;
                
                // ⭐ KERNÄNDERUNG: Sende gemessenen/manipulierten Wert (nicht Sollwert!) ⭐
                safeSetState(prefix + 'target_power', intelState.reportedPower);
                safeSetState(prefix + 'correction_factor', 1); // Nicht mehr verwendet
                safeSetState(prefix + 'limiting_active', intelState.limitingActive);
                
                return true;
            } catch (error) {
                console.error('❌ Intelligence: Fehler beim Senden an Core:', error.message);
                return false;
            }
        }
        
        // ===================================================
        // ⭐ TIBBER-WERT GLÄTTUNG (ANTI-OSZILLATION) ⭐
        // ===================================================
        
        function smoothTibberValue(currentValue) {
            if (!INTEL_CONFIG.SMOOTHING_ENABLED) return currentValue;
            
            try {
                const now = Date.now();
                
                // History aktualisieren (letzte 30s)
                intelState.smoothingHistory.push({ time: now, value: currentValue });
                const thirtySecondsAgo = now - 30000;
                intelState.smoothingHistory = intelState.smoothingHistory.filter(h => h.time > thirtySecondsAgo);
                
                if (intelState.smoothingHistory.length < 2) {
                    intelState.smoothedTibber = currentValue;
                    return currentValue;
                }
                
                // Glättung anwenden
                const lastSmoothed = intelState.smoothedTibber || currentValue;
                const smoothed = lastSmoothed * (1 - INTEL_CONFIG.SMOOTH_FACTOR) + currentValue * INTEL_CONFIG.SMOOTH_FACTOR;
                
                intelState.smoothedTibber = smoothed;
                
                // Logging bei größeren Änderungen
                const change = Math.abs(currentValue - smoothed);
                if (INTEL_CONFIG.LOG_SMOOTHING && change > 100) {
                    console.log(`🌊 Intelligence: Tibber-Glättung ${Math.round(currentValue)}W → ${Math.round(smoothed)}W`);
                }
                
                return smoothed;
                
            } catch (error) {
                console.error('❌ Intelligence: Glättung Fehler:', error.message);
                return currentValue;
            }
        }
        
        // ===================================================
        // ⭐ SOC-INTELLIGENCE (WERTE-MANIPULATION) ⭐
        // ===================================================
        
        function applySocProtection(measuredValue) {
            if (!INTEL_CONFIG.SOC_PROTECTION_ENABLED) {
                intelState.socActionActive = false;
                return measuredValue;
            }
            
            try {
                const soc = intelState.deviceSoc;
                let manipulatedValue = measuredValue;
                let socReason = "";
                let socActive = false;
                
                // ⭐ SOC >95%: LADUNG VERHINDERN durch Werte-Manipulation ⭐
                if (soc >= INTEL_CONFIG.SOC_HIGH_THRESHOLD && measuredValue < 0) {
                    // Negative Werte (Einspeisung) → auf 0 setzen = keine Ladung
                    manipulatedValue = 0;
                    socReason = `SOC ${soc}% ≥${INTEL_CONFIG.SOC_HIGH_THRESHOLD}% - Einspeisung unterdrückt (Ladeschutz)`;
                    socActive = true;
                    
                } 
                // ⭐ SOC <10%: ENTLADUNG REDUZIEREN ⭐ 
                else if (soc <= INTEL_CONFIG.SOC_LOW_THRESHOLD && measuredValue > 0) {
                    // Positive Werte (Netzbezug) → reduzieren = weniger Entladung
                    manipulatedValue = measuredValue * 0.5; // 50% reduzieren
                    socReason = `SOC ${soc}% ≤${INTEL_CONFIG.SOC_LOW_THRESHOLD}% - Netzbezug reduziert (Entladeschutz)`;
                    socActive = true;
                    
                } else {
                    socReason = `SOC ${soc}% - normale Regelung`;
                    socActive = false;
                }
                
                // Status aktualisieren
                intelState.socActionActive = socActive;
                
                // Logging bei Zustandsänderung
                if (socReason !== intelState.lastSocReason) {
                    if (INTEL_CONFIG.LOG_SOC_ACTIONS && socActive) {
                        console.log(`🔋 Intelligence: ${socReason} - ${Math.round(measuredValue)}W → ${Math.round(manipulatedValue)}W`);
                    }
                    intelState.lastSocReason = socReason;
                }
                
                // Datenpunkte aktualisieren
                safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'soc_action_active', socActive);
                safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'soc_reason', socReason);
                
                return manipulatedValue;
                
            } catch (error) {
                console.error('❌ Intelligence: SOC-Schutz Fehler:', error.message);
                return measuredValue;
            }
        }
        
        // ===================================================
        // INTELLIGENTE BEGRENZUNG (des gemessenen Werts)
        // ===================================================
        
        function applyIntelligentLimiting(measuredValue) {
            try {
                const limit = INTEL_CONFIG.POWER_LIMIT;
                const hysteresis = INTEL_CONFIG.HYSTERESIS_OFFSET;
                const now = Date.now();
                
                // Begrenzung prüfen
                let needsLimiting = false;
                
                if (INTEL_CONFIG.HYSTERESIS_ENABLED) {
                    if (!intelState.limitingActive) {
                        // Begrenzung einschalten: bei 750W
                        needsLimiting = Math.abs(measuredValue) > limit;
                    } else {
                        // Begrenzung ausschalten: erst bei 675W (75W Hysterese)
                        needsLimiting = Math.abs(measuredValue) >= (limit - hysteresis);
                    }
                } else {
                    needsLimiting = Math.abs(measuredValue) > limit;
                }
                
                // Status aktualisieren
                if (needsLimiting && !intelState.limitingActive) {
                    if (INTEL_CONFIG.LOG_INTELLIGENCE) {
                        console.log(`🔒 Intelligence: Begrenzung aktiviert bei ${Math.round(measuredValue)}W (Limit: ${limit}W)`);
                    }
                    intelState.limitingActive = true;
                    intelState.limitingActivations++;
                } else if (!needsLimiting && intelState.limitingActive) {
                    if (INTEL_CONFIG.LOG_INTELLIGENCE) {
                        console.log(`🔓 Intelligence: Begrenzung deaktiviert bei ${Math.round(measuredValue)}W`);
                    }
                    intelState.limitingActive = false;
                }
                
                if (intelState.limitingActive) {
                    intelState.totalLimitingTime += INTEL_CONFIG.UPDATE_INTERVAL;
                }
                
                // Wert begrenzen
                let limitedValue = measuredValue;
                if (needsLimiting) {
                    limitedValue = Math.max(-limit, Math.min(limit, measuredValue));
                }
                
                return limitedValue;
                
            } catch (error) {
                console.error('❌ Intelligence: Begrenzung Fehler:', error.message);
                return measuredValue;
            }
        }
        
        // ===================================================
        // THROTTLING (Sendepausen)
        // ===================================================
        
        function shouldThrottle() {
            const now = Date.now();
            const timeSinceLastSend = now - intelState.lastSendTime;
            
            if (timeSinceLastSend < INTEL_CONFIG.THROTTLE_INTERVAL) {
                return true; // Noch in Throttling-Phase
            }
            
            intelState.lastSendTime = now;
            return false;
        }
        
        function applyDeadZoneAndRateLimit(newValue) {
            const deadZone = INTEL_CONFIG.DEAD_ZONE_WATTS;
            const maxChange = INTEL_CONFIG.MAX_CHANGE_PER_CYCLE;
            
            // Dead-Zone prüfen
            const change = Math.abs(newValue - intelState.lastReportedPower);
            if (change < deadZone) {
                return intelState.lastReportedPower; // Keine Änderung
            }
            
            // Rate-Limiting
            const currentChange = newValue - intelState.lastReportedPower;
            if (Math.abs(currentChange) > maxChange) {
                const limitedChange = currentChange > 0 ? maxChange : -maxChange;
                return intelState.lastReportedPower + limitedChange;
            }
            
            return newValue;
        }
        
        // ===================================================
        // WOLKEN-ERKENNUNG (vereinfacht)
        // ===================================================
        
        function detectCloudMode() {
            if (!INTEL_CONFIG.CLOUD_SMOOTHING) return false;
            
            try {
                const now = Date.now();
                intelState.pvHistory.push({ time: now, value: intelState.tibberCurrent });
                
                // Nur letzte 60s behalten
                const sixtySecondsAgo = now - 60000;
                intelState.pvHistory = intelState.pvHistory.filter(h => h.time > sixtySecondsAgo);
                
                if (intelState.pvHistory.length < 6) return false;
                
                const recent = intelState.pvHistory.slice(-6);
                let rapidChanges = 0;
                
                for (let i = 1; i < recent.length; i++) {
                    const diff = Math.abs(recent[i].value - recent[i-1].value);
                    if (diff > 400) rapidChanges++;
                }
                
                const newCloudMode = rapidChanges >= 3;
                
                if (newCloudMode !== intelState.cloudModeActive) {
                    if (INTEL_CONFIG.LOG_INTELLIGENCE) {
                        console.log(`${newCloudMode ? '☁️ WOLKEN-MODUS' : '☀️ STABILER MODUS'} erkannt`);
                    }
                    intelState.cloudModeActive = newCloudMode;
                    safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'cloud_mode_active', newCloudMode);
                }
                
                return newCloudMode;
                
            } catch (error) {
                console.error('❌ Intelligence: Wolken-Erkennung Fehler:', error.message);
                return false;
            }
        }
        
        // ===================================================
        // TASMOTA REALITY-CHECK (nur Monitoring)
        // ===================================================
        
        function readTasmotaValues() {
            if (!INTEL_CONFIG.TASMOTA_REALITY_CHECK) return;
            
            try {
                intelState.tasmotaXXXXPower = getState(INTEL_CONFIG.tasmotaXXXX).val || 0;
                intelState.tasmotayyyyPower = getState(INTEL_CONFIG.tasmotayyyy).val || 0;
                
                safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'tasmota_power', Math.round(intelState.tasmotaXXXXPower));
                
                // Effizienz berechnen (nur Monitoring)
                const expectedPower = Math.abs(intelState.reportedPower);
                const actualPower = Math.abs(intelState.tasmotaXXXXPower);
                
                if (expectedPower > 50) {
                    const efficiency = Math.min(100, (actualPower / expectedPower) * 100);
                    const responds = efficiency > 40;
                    
                    intelState.storageEfficiency = efficiency;
                    
                    safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'storage_efficiency', Math.round(efficiency));
                    safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'storage_responds', responds);
                    
                    // Logging alle 60s
                    const now = Date.now();
                    if ((!intelState.lastEfficiencyLog || now - intelState.lastEfficiencyLog > 60000)) {
                        if (INTEL_CONFIG.LOG_INTELLIGENCE) {
                            const direction = intelState.reportedPower < 0 ? "Laden" : "Entladen";
                            const status = responds ? "✅" : "❌";
                            console.log(`📊 Intelligence: ${direction} Effizienz ${Math.round(expectedPower)}W → ${Math.round(actualPower)}W = ${Math.round(efficiency)}% ${status}`);
                        }
                        intelState.lastEfficiencyLog = now;
                    }
                }
                
            } catch (error) {
                console.error('❌ Intelligence: Tasmota-Lesefehler:', error.message);
            }
        }
        
        // ===================================================
        // 0W-METRIKEN & STATISTIKEN
        // ===================================================
        
        function updateZeroWattMetrics() {
            if (!INTEL_CONFIG.ZERO_WATT_FOCUS) return;
            
            try {
                const now = Date.now();
                const prefix = INTEL_CONFIG.INTEL_PREFIX;
                
                // Tagesreset prüfen
                const today = new Date().toDateString();
                const lastResetDay = new Date(intelState.lastMetricReset).toDateString();
                
                if (today !== lastResetDay) {
                    if (INTEL_CONFIG.LOG_INTELLIGENCE) {
                        console.log(`📊 Intelligence: Tages-Reset - Netzbezug gestern: ${intelState.dailyNetPurchase.toFixed(3)} kWh`);
                    }
                    
                    if (intelState.dailyNetPurchase < intelState.bestDailyResult) {
                        intelState.bestDailyResult = intelState.dailyNetPurchase;
                        safeSetState(prefix + 'best_daily_result', Math.round(intelState.bestDailyResult * 1000) / 1000);
                    }
                    
                    // Reset
                    intelState.dailyNetPurchase = 0;
                    intelState.dailyAdjustments = 0;
                    intelState.zeroWattTime = 0;
                    intelState.limitingActivations = 0;
                    intelState.totalLimitingTime = 0;
                    intelState.lastMetricReset = now;
                }
                
                // 0W-Zeit messen
                if (Math.abs(intelState.tibberCurrent) <= 30) {
                    intelState.zeroWattTime += INTEL_CONFIG.UPDATE_INTERVAL;
                }
                
                // Netzbezug summieren
                if (intelState.tibberCurrent > 0) {
                    const kWhIncrement = (intelState.tibberCurrent * INTEL_CONFIG.UPDATE_INTERVAL) / (1000 * 3600);
                    intelState.dailyNetPurchase += kWhIncrement;
                }
                
                intelState.dailyAdjustments++;
                
                // Datenpunkte aktualisieren (alle 60s)
                if (!intelState.lastMetricUpdate || now - intelState.lastMetricUpdate > 60000) {
                    const runtimeMs = now - intelState.lastMetricReset;
                    const zeroWattPercent = (intelState.zeroWattTime / runtimeMs) * 100;
                    const limitPercent = (intelState.totalLimitingTime / runtimeMs) * 100;
                    
                    safeSetState(prefix + 'zero_watt_time_percent', Math.round(zeroWattPercent * 10) / 10);
                    safeSetState(prefix + 'daily_net_purchase_kwh', Math.round(intelState.dailyNetPurchase * 1000) / 1000);
                    safeSetState(prefix + 'daily_adjustments', intelState.dailyAdjustments);
                    safeSetState(prefix + 'limiting_activations_today', intelState.limitingActivations);
                    safeSetState(prefix + 'limiting_time_percent', Math.round(limitPercent * 10) / 10);
                    
                    intelState.lastMetricUpdate = now;
                }
                
            } catch (error) {
                console.error('❌ Intelligence: Metriken-Update Fehler:', error.message);
            }
        }
        
        // ===================================================
        // ⭐ HAUPT-INTELLIGENCE-LOOP (NEUE LOGIK!) ⭐
        // ===================================================
        
        function runIntelligenceLoop() {
            try {
                // 1. Von Core lesen
                if (!readFromCore()) {
                    return;
                }
                
                if (!intelState.coreActive) {
                    if (INTEL_CONFIG.LOG_INTELLIGENCE) {
                        console.log('⚠️ Intelligence: Core nicht aktiv - warte...');
                    }
                    return;
                }
                
                // 2. Tasmota-Werte lesen (nur Monitoring)
                readTasmotaValues();
                
                // 3. Wolken-Erkennung
                detectCloudMode();
                
                // 4. ⭐ NEUE KERNLOGIK: Gemessenen Wert verarbeiten ⭐
                
                // 4a. Tibber-Wert glätten (Anti-Oszillation)
                const smoothedTibber = smoothTibberValue(intelState.tibberCurrent);
                
                // 4b. ⭐ KRITISCH: Intelligente Begrenzung anwenden (ZUERST!) ⭐
                const limitedValue = applyIntelligentLimiting(smoothedTibber);
                
                // 4c. SOC-Schutz anwenden (Werte-Manipulation)
                const socProtectedValue = applySocProtection(limitedValue);
                
                // 4d. Throttling & Dead-Zone
                if (shouldThrottle()) {
                    // Zu früh - nicht senden
                    return;
                }
                
                const finalValue = applyDeadZoneAndRateLimit(socProtectedValue);
                
                // 5. ⭐ KERNPRINZIP: Sende gemessenen/manipulierten Wert (NICHT Sollwert!) ⭐
                intelState.reportedPower = finalValue;
                intelState.lastReportedPower = finalValue;
                
                // 6. An Core senden
                sendToCore();
                
                // 7. Metriken aktualisieren
                updateZeroWattMetrics();
                
                // 8. Status-Updates
                const powerChange = finalValue - intelState.lastReportedPower;
                safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'tibber_raw', Math.round(intelState.tibberCurrent));
                safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'tibber_smoothed', Math.round(smoothedTibber));
                safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'reported_power', Math.round(finalValue));
                safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'power_change', Math.round(powerChange));
                safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'limiting_active', intelState.limitingActive);
                
                intelState.lastUpdate = Date.now();
                
                // Debug-Logging mit korrekter Reihenfolge
                if (INTEL_CONFIG.LOG_INTELLIGENCE && Math.abs(powerChange) > 50) {
                    console.log(`📤 Intelligence v2.0 FIX: Tibber ${Math.round(intelState.tibberCurrent)}W → Begrenzt ${Math.round(limitedValue)}W → SOC-Schutz ${Math.round(socProtectedValue)}W → Gesendet ${Math.round(finalValue)}W`);
                }
                
            } catch (error) {
                console.error('❌ Intelligence: Loop-Fehler:', error.message);
                // Fallback: Tibber-Wert direkt senden
                try {
                    intelState.reportedPower = intelState.tibberCurrent || 0;
                    sendToCore();
                } catch (fallbackError) {
                    console.error('❌ Intelligence: Auch Fallback fehlgeschlagen:', fallbackError.message);
                }
            }
        }
        
        // ===================================================
        // INTELLIGENCE START
        // ===================================================
        
        function startIntelligence() {
            console.log('🧠 MARSTEK-Intelligence v2.0 - KORREKTE REGELUNGSLOGIK\n');
            console.log('🎯 ZWECK: INTELLIGENTE 0W-REGELUNG');
            console.log('✅ KERNPRINZIP: Sendet gemessenen Netzbezug (nicht Sollwerte!)');
            console.log('✅ SOC-Intelligence (Werte-Manipulation für Schutz)');
            console.log('✅ Intelligente Begrenzung (des gemessenen Werts)');
            console.log('✅ Anti-Oszillations-Glättung (Tibber-Wert)');
            console.log('✅ Tasmota Reality-Check (Effizienz-Monitoring)');
            console.log('✅ 0W-Metriken & Tagesstatistiken');
            console.log('');
            console.log('🔗 KOMMUNIKATION:');
            console.log('   📥 Empfängt von Core: tibber_current (gemessener Netzbezug)');
            console.log('   📤 Sendet an Core: reported_power (manipulierter Messwert)');
            console.log('   🎯 MARSTEK regelt automatisch auf 0W');
            console.log('   ⚠️ Darf crashen ohne CT-Simulation zu stoppen!');
            console.log('=====================================');
            
            // Datenpunkte erstellen
            createIntelligenceDatapoints();
            
            // Status setzen
            safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'intel_active', true);
            
            // Haupt-Loop starten
            setInterval(runIntelligenceLoop, INTEL_CONFIG.UPDATE_INTERVAL);
            
            // Sofort starten
            setTimeout(runIntelligenceLoop, 2000);
            
            console.log('\n🧠 INTELLIGENCE v2.0 AKTIV!');
            console.log('💡 Neue Logik: Sendet Messwerte statt Sollwerte');
            console.log('🔧 Begrenzung: ±' + INTEL_CONFIG.POWER_LIMIT + 'W');
            console.log('🌊 Glättung: ' + (INTEL_CONFIG.SMOOTHING_ENABLED ? 'Aktiv (' + Math.round(INTEL_CONFIG.SMOOTH_FACTOR*100) + '%)' : 'Deaktiviert'));
            console.log('🔋 SOC-Schutz: ' + (INTEL_CONFIG.SOC_PROTECTION_ENABLED ? 'Aktiv' : 'Deaktiviert'));
            console.log('☁️ Wolken-Erkennung: ' + (INTEL_CONFIG.CLOUD_SMOOTHING ? 'Aktiv' : 'Deaktiviert'));
            console.log('📊 Reality-Check: ' + (INTEL_CONFIG.TASMOTA_REALITY_CHECK ? 'Aktiv' : 'Deaktiviert'));
            console.log('🎯 0W-Focus: ' + (INTEL_CONFIG.ZERO_WATT_FOCUS ? 'Aktiv' : 'Deaktiviert'));
            console.log('=====================================\n');
        }
        
        function stopIntelligence() {
            try {
                safeSetState(INTEL_CONFIG.INTEL_PREFIX + 'intel_active', false);
                console.log('🛑 MARSTEK-Intelligence v2.0 beendet');
            } catch (error) {
                console.error('❌ Intelligence Stop-Fehler:', error.message);
            }
        }
        
        // ===================================================
        // SCRIPT START
        // ===================================================
        
        startIntelligence();
        
        onStop(() => {
            stopIntelligence();
        });
        
        // ===================================================
        // KONFIGURATIONSHINWEISE FÜR FORUM-NUTZER:
        // ===================================================
        /*
        WICHTIGE ANPASSUNGEN NÖTIG:
        
        1. TASMOTA-GERÄTE-PFADE ANPASSEN:
           Zeile 13: tasmotaXXXX: 'sonoff.0.TasmotaXXX-MSTXXXX.ENERGY_Power'
           Zeile 14: tasmotayyyy: 'sonoff.0.TasmotaXXX-MSTXXXX.ENERGY_Power'
           → Ersetze TasmotaXXX-MSTXXXX durch deine echten Tasmota-Geräte-Namen
           → Zweites Gerät ist optional - kann auch weggelassen werden
           
        2. PREFIXE ANPASSEN:
           Zeile 32: SHARED_PREFIX: '0_userdata.0.marstek_V-E.shared.'
           Zeile 33: INTEL_PREFIX: '0_userdata.0.marstek_V-E.intel.'
           → Passe die Prefixe an deine ioBroker-Struktur an
           
        3. MONITOR-PREFIX PRÜFEN:
           Zeile 189: const monitorPrefix = '0_userdata.0.marstek_V-E.monitor.';
           → Falls du ein Monitor-Script verwendest, passe den Pfad an
           
        4. TASMOTA-GERÄTE FINDEN:
           - In ioBroker: Objekte → sonoff.0 → TasmotaXXX-MSTXXXX → ENERGY_Power
           - Oder unter deinem Tasmota/MQTT-Adapter
           
        5. POWER_LIMIT ANPASSEN:
           Zeile 16: POWER_LIMIT: 750
           → Passe die Leistungsgrenze an deine Anlage an (in Watt)
           
        6. SOC-SCHWELLWERTE ANPASSEN:
           Zeile 26: SOC_HIGH_THRESHOLD: 95  (Ladeschutz ab X% SOC)
           Zeile 27: SOC_LOW_THRESHOLD: 10   (Entladeschutz ab X% SOC)
           → Passe an deine Batterie-Strategie an
        
        OPTIONAL FEATURES:
        - Wenn kein Tasmota vorhanden: TASMOTA_REALITY_CHECK: false setzen
        - Wenn kein SOC verfügbar: SOC_PROTECTION_ENABLED: false setzen
        - Logging reduzieren: LOG_INTELLIGENCE: false setzen
        */
        
        G Offline
        G Offline
        Gismoh
        schrieb am zuletzt editiert von Gismoh
        #19

        @gismoh

        3-MARSTEK-Monitor-Control:

        // ===================================================
        // MARSTEK-Monitor-Control v2.0 - ÜBERWACHUNG & STEUERUNG
        // ===================================================
        // 
        // 📊 ZWECK: ÜBERWACHUNG, DIAGNOSE & STEUERUNG
        // ✅ Steuerungsmodus-Erkennung (CT vs Manuell)
        // ✅ API-Integration + Smart-Timing
        // ✅ Diagnose-System + Datenpunkte-Verwaltung
        // ✅ Debug-Modi + Override-Funktionen
        // ✅ SOC-Daten für Intelligence-Script v2.0
        // ✅ v2.0: Kompatibel mit korrigierter Regelungslogik
        // 
        // ⚠️ DARF CRASHEN ohne Core/Intelligence zu stoppen!
        // 
        // ===================================================
        
        // KONFIGURATION
        const MONITOR_CONFIG = {
            // API-Zugangsdaten (werden aus Datenpunkten gelesen)
            API_ENABLED: true,
            API_INTERVAL: 300000,
            
            // Steuerungsmodus-Erkennung
            MODE_DETECTION_ENABLED: true,
            
            // Timing
            UPDATE_INTERVAL: 10000,  // Monitor läuft langsamer
            
            // Kommunikation - BITTE ANPASSEN!
            SHARED_PREFIX: '0_userdata.0.marstek_V-E.shared.',        // ← Dein Shared-Prefix hier eintragen
            INTEL_PREFIX: '0_userdata.0.marstek_V-E.intel.',          // ← Dein Intelligence-Prefix hier eintragen
            MONITOR_PREFIX: '0_userdata.0.marstek_V-E.monitor.',      // ← Dein Monitor-Prefix hier eintragen
            
            // Logging
            LOG_MONITOR: true,
            LOG_MODE_DETECTION: true,
            LOG_API: true
        };
        
        // MONITOR STATE
        let monitorState = {
            // Von Core/Intelligence empfangen
            coreActive: false,
            intelActive: false,
            tibberCurrent: 0,
            reportedPower: 0,          // v2.0: Neuer Name für gemeldeten Wert
            limitingActive: false,
            
            // API-Daten
            deviceSoc: 0,
            deviceCharge: 0,
            deviceDischarge: 0,
            lastReportTime: 0,
            
            // Steuerungsmodus-Erkennung
            controlMode: 'unbekannt',
            controlModeConfidence: 'niedrig',
            lastModeDetection: 0,
            modeDetectionHistory: [],
            apiModeData: {},
            behaviorModeData: {
                responseCount: 0,
                noResponseCount: 0,
                avgEfficiency: 0,
                lastBehaviorCheck: 0
            },
            
            // API-Timing
            apiState: {
                lastFetch: 0,
                lastActivity: Date.now(),
                nextFetchTime: 0
            },
            
            // Status & Diagnose
            monitorActive: true,
            lastUpdate: 0,
            systemStatus: 'starting',
            alarms: [],
            
            // Override-Modi
            overrideMode: '',
            manualModeOverride: ''
        };
        
        // ===================================================
        // MONITOR DATENPUNKTE
        // ===================================================
        
        function createMonitorDatapoints() {
            const prefix = MONITOR_CONFIG.MONITOR_PREFIX;
            
            const datapoints = [
                // API-Konfiguration - BITTE AUSFÜLLEN!
                { name: 'mailbox', value: '', desc: 'MARSTEK Mailbox (deine E-Mail)' },
                { name: 'token', value: '', desc: 'MARSTEK API Token (aus App)' },
                { name: 'deviceId', value: 'XXXX', desc: 'MARSTEK Device ID (z.B. 3456)' },      // ← ANPASSEN!
                { name: 'enable_second_storage', value: false, desc: '🔄 Zweiter Speicher (MSTYYYY)' },
                
                // Status
                { name: 'system_status', value: 'starting', desc: '🔧 System-Status (shared)', shared: true },
                { name: 'monitor_active', value: true, desc: '📊 Monitor läuft' },
                { name: 'api_connected', value: false, desc: '📡 API verbunden' },
                
                // Steuerungsmodus-Erkennung
                { name: 'control_mode_detected', value: 'unbekannt', desc: '🎮 Erkannter Steuerungsmodus' },
                { name: 'control_mode_confidence', value: 'niedrig', desc: '🎯 Erkennungs-Sicherheit' },
                { name: 'control_mode_method', value: 'keine', desc: '🔍 Erkennungsmethode' },
                { name: 'manual_mode_active', value: false, desc: '⚠️ Manueller Modus aktiv' },
                { name: 'regulation_possible', value: true, desc: '✅ Regelung möglich' },
                { name: 'check_mode_now', value: false, desc: '🔄 Sofort-Prüfung starten' },
                
                // API-Daten
                { name: 'device_charge', value: 0, desc: 'Speicher lädt [W]' },
                { name: 'device_discharge', value: 0, desc: 'Speicher entlädt [W]' },
                { name: 'device_soc', value: 0, desc: 'Speicher SOC [%]' },
                { name: 'api_delay', value: 0, desc: '📡 API Verzögerung [s]' },
                { name: 'last_api_fetch', value: 0, desc: '🕐 Letzte API-Abfrage' },
                { name: 'next_api_fetch', value: 0, desc: '⏰ Nächste API-Abfrage' },
                
                // Berechnete Werte
                { name: 'net_result', value: 0, desc: 'Resultat am Netz [W]' },
                { name: 'regulation_quality', value: 0, desc: '📈 Regelgüte [%]' },  // v2.0: Neu
                { name: 'current_efficiency', value: 0, desc: '📈 Aktuelle Effizienz [%]' },
                
                // Override & Debug
                { name: 'override_mode', value: '', desc: '🔧 Override-Modus (test/zero/normal)' },
                { name: 'manual_mode_override', value: '', desc: '🎮 Modus-Override (ct/manual/auto)' },
                { name: 'debug_mode', value: false, desc: '🔍 Debug-Modus aktiv' },
                
                // Diagnose
                { name: 'status', value: '', desc: 'Aktueller Status' },
                { name: 'timeline', value: '', desc: 'Timeline' },
                { name: 'alarms', value: '', desc: '🚨 Aktive Alarme' },
                
                // Statistiken (Überblick)
                { name: 'daily_summary', value: '', desc: '📊 Tages-Zusammenfassung' },
                { name: 'system_version', value: 'v2.0', desc: '🔧 System-Version' }  // v2.0: Neu
            ];
            
            datapoints.forEach(dp => {
                try {
                    const base = dp.shared ? MONITOR_CONFIG.SHARED_PREFIX : prefix;
                    createState(base + dp.name, dp.value, {
                        name: dp.desc,
                        type: typeof dp.value,
                        read: true,
                        write: true,
                        desc: `MARSTEK Monitor v2.0 - ${dp.desc}`
                    });
                } catch (error) {
                    // State existiert bereits
                }
            });
        }
        
        // ===================================================
        // KOMMUNIKATION MIT ANDEREN SCRIPTS
        // ===================================================
        
        function readFromOtherScripts() {
            try {
                const sharedPrefix = MONITOR_CONFIG.SHARED_PREFIX;
                const intelPrefix = MONITOR_CONFIG.INTEL_PREFIX;
                
                // Von Core
                monitorState.coreActive = getState(sharedPrefix + 'core_active').val || false;
                monitorState.tibberCurrent = getState(sharedPrefix + 'tibber_current').val || 0;
                
                // v2.0: Neuer Name für gemeldeten Wert
                monitorState.reportedPower = getState(sharedPrefix + 'target_power').val || 0;
                
                // Von Intelligence v2.0
                try {
                    monitorState.intelActive = getState(intelPrefix + 'intel_active').val || false;
                    monitorState.limitingActive = getState(intelPrefix + 'limiting_active').val || false;
                } catch (error) {
                    // Intelligence möglicherweise nicht gestartet
                    monitorState.intelActive = false;
                }
                
                return true;
            } catch (error) {
                console.error('❌ Monitor: Fehler beim Lesen von anderen Scripts:', error.message);
                return false;
            }
        }
        
        // ===================================================
        // ROBUSTER STATE-SETTER
        // ===================================================
        
        function safeSetState(id, value) {
            if (existsState(id)) {
                try {
                    setState(id, value);
                } catch (e) {
                    console.warn(`⚠️ Monitor safeSetState: Fehler beim Setzen von ${id}: ${e.message}`);
                }
            } else {
                console.warn(`⚠️ Monitor safeSetState: Datenpunkt ${id} existiert nicht.`);
            }
        }
        
        // ===================================================
        // KOMMUNIKATION MIT ANDEREN SCRIPTS (ROBUST)
        // ===================================================
        
        function sendToOtherScripts() {
            try {
                const sharedPrefix = MONITOR_CONFIG.SHARED_PREFIX;
                const monitorPrefix = MONITOR_CONFIG.MONITOR_PREFIX;
        
                // Override-Modus an alle
                safeSetState(sharedPrefix + 'override_mode', monitorState.overrideMode);
        
                // System-Status
                safeSetState(sharedPrefix + 'system_status', monitorState.systemStatus);
        
                // Steuerungsmodus-Info
                safeSetState(monitorPrefix + 'control_mode_detected', monitorState.controlMode);
                safeSetState(monitorPrefix + 'control_mode_confidence', monitorState.controlModeConfidence);
                safeSetState(monitorPrefix + 'manual_mode_active', monitorState.controlMode === 'manual');
                safeSetState(monitorPrefix + 'regulation_possible', monitorState.controlMode === 'ct');
        
                return true;
        
            } catch (error) {
                console.error('❌ Monitor: Fehler beim Senden an andere Scripts:', error.message);
                return false;
            }
        }
        
        // ===================================================
        // API-INTEGRATION (MARSTEK CLOUD)
        // ===================================================
        
        function fetchDeviceData() {
            if (!MONITOR_CONFIG.API_ENABLED) return;
            
            try {
                const prefix = MONITOR_CONFIG.MONITOR_PREFIX;
                const mailbox = getState(prefix + 'mailbox').val;
                const token = getState(prefix + 'token').val;
                const deviceId = getState(prefix + 'deviceId').val;
                
                if (!mailbox || !token || !deviceId) {
                    console.error("❌ Monitor: API-Zugangsdaten fehlen!");
                    return;
                }
                
                if (MONITOR_CONFIG.LOG_API) {
                    console.log("🔄 Monitor v2.0: API-Abfrage für Speicher " + deviceId);
                }
                
                const url = `https://eu.hamedata.com/ems/api/v1/getDeviceList?mailbox=${encodeURIComponent(mailbox)}&token=${token}`;
                
                httpGet(url, function(error, response) {
                    if (error) {
                        console.error("❌ Monitor: HTTP Fehler:", error);
                        return;
                    }
                    
                    try {
                        const result = JSON.parse(response.data);
                        
                        if (!result || result.code !== 1) {
                            console.log("❌ Monitor: API Error:", result?.msg || "Unknown");
                            return;
                        }
                        
                        const devices = result.data;
                        const targetDevice = devices.find(d => d.mac && d.mac.endsWith(deviceId));
                        
                        if (targetDevice) {
                            // Standard-Daten speichern
                            monitorState.deviceSoc = parseFloat(targetDevice.soc) || 0;
                            monitorState.deviceCharge = parseFloat(targetDevice.charge) || 0;
                            monitorState.deviceDischarge = parseFloat(targetDevice.discharge) || 0;
                            monitorState.lastReportTime = targetDevice.report_time;
                            
                            const prefix = MONITOR_CONFIG.MONITOR_PREFIX;
                            setState(prefix + 'device_charge', monitorState.deviceCharge);
                            setState(prefix + 'device_discharge', monitorState.deviceDischarge);
                            setState(prefix + 'device_soc', monitorState.deviceSoc);
                            setState(prefix + 'api_connected', true);
                            
                            // Steuerungsmodus-Erkennung
                            detectControlModeFromAPI(targetDevice);
                            
                            if (MONITOR_CONFIG.LOG_API) {
                                console.log(`✅ Monitor v2.0: API OK - SOC: ${monitorState.deviceSoc}%, Charge: ${monitorState.deviceCharge}W, Discharge: ${monitorState.deviceDischarge}W`);
                            }
                        }
                        
                    } catch (e) {
                        console.error("❌ Monitor: Parse Fehler:", e.message);
                    }
                });
                
            } catch (error) {
                console.error('❌ Monitor: API-Fetch Fehler:', error.message);
            }
        }
        
        function fetchDeviceDataSmart() {
            if (!MONITOR_CONFIG.API_ENABLED) return;
            
            const now = Date.now();
            
            if (now < monitorState.apiState.nextFetchTime) {
                return;
            }
            
            const currentPower = Math.abs(monitorState.tibberCurrent);
            const isActive = currentPower > 100;
            
            if (isActive) {
                monitorState.apiState.lastActivity = now;
            }
            
            // Modus-abhängige Intervalle
            let interval;
            if (monitorState.controlMode === 'manual' && monitorState.controlModeConfidence !== 'niedrig') {
                // MANUELLER MODUS: Häufiger prüfen (auf Umstellung warten)
                interval = 60000 + Math.random() * 30000; // 1-1.5 Minuten
            } else if (isActive) {
                // AKTIV: Normale Intervalle
                interval = 240000 + Math.random() * 120000; // 4-6 Minuten
            } else {
                // INAKTIV: Längere Intervalle
                interval = 600000 + Math.random() * 300000; // 10-15 Minuten
            }
            
            monitorState.apiState.nextFetchTime = now + interval;
            monitorState.apiState.lastFetch = now;
            
            // Timing-Info speichern
            const prefix = MONITOR_CONFIG.MONITOR_PREFIX;
            setState(prefix + 'last_api_fetch', monitorState.apiState.lastFetch);
            setState(prefix + 'next_api_fetch', monitorState.apiState.nextFetchTime);
            
            fetchDeviceData();
        }
        
        // ===================================================
        // STEUERUNGSMODUS-ERKENNUNG (UNVERÄNDERT)
        // ===================================================
        
        function detectControlModeFromAPI(deviceData) {
            if (!MONITOR_CONFIG.MODE_DETECTION_ENABLED || !deviceData) return 'unbekannt';
            
            let detectedMode = 'unbekannt';
            let confidence = 'niedrig';
            let reasons = [];
            
            // API-Feld-Analyse
            if (deviceData.status !== undefined) {
                if (deviceData.status === 0) {
                    detectedMode = 'ct';
                    confidence = 'mittel';
                    reasons.push('status=0 → CT-Modus vermutet');
                } else if (deviceData.status === 1) {
                    reasons.push('status=1 → Gerät online, Modus unklar');
                }
            }
            
            // Weitere Modus-Felder suchen
            const modeFields = ['mode', 'control_mode', 'work_mode', 'operation_mode', 'ct_mode', 'manual_mode'];
            for (const field of modeFields) {
                if (deviceData[field] !== undefined) {
                    const value = String(deviceData[field]).toLowerCase();
                    if (value.includes('manual')) {
                        detectedMode = 'manual';
                        confidence = 'hoch';
                        reasons.push(`${field}="${value}" → Manueller Modus`);
                        break;
                    } else if (value.includes('ct') || value.includes('auto') || value.includes('grid')) {
                        detectedMode = 'ct';
                        confidence = 'hoch';
                        reasons.push(`${field}="${value}" → CT-Modus`);
                        break;
                    }
                }
            }
            
            // API-Daten speichern
            monitorState.apiModeData = {
                access: deviceData.access,
                status: deviceData.status,
                detectedMode: detectedMode,
                confidence: confidence,
                reasons: reasons,
                lastUpdate: Date.now(),
                rawData: JSON.stringify(deviceData, null, 2)
            };
            
            return { mode: detectedMode, confidence: confidence, reasons: reasons };
        }
        
        function updateControlModeDetection() {
            if (!MONITOR_CONFIG.MODE_DETECTION_ENABLED) return;
            
            const now = Date.now();
            
            // API-basierte Erkennung
            let apiResult = { mode: 'unbekannt', confidence: 'niedrig', reasons: [] };
            if (monitorState.apiModeData && monitorState.apiModeData.lastUpdate && 
                (now - monitorState.apiModeData.lastUpdate) < 600000) {
                apiResult = {
                    mode: monitorState.apiModeData.detectedMode || 'unbekannt',
                    confidence: monitorState.apiModeData.confidence || 'niedrig',
                    reasons: monitorState.apiModeData.reasons || []
                };
            }
            
            // Intelligente Kombination
            let finalMode = 'unbekannt';
            let finalConfidence = 'niedrig';
            let detectionMethod = 'keine';
            
            if (apiResult.confidence === 'hoch') {
                finalMode = apiResult.mode;
                finalConfidence = 'hoch';
                detectionMethod = 'api';
            } else if (apiResult.confidence === 'mittel') {
                finalMode = apiResult.mode;
                finalConfidence = 'mittel';
                detectionMethod = 'api';
            } else {
                finalMode = 'unbekannt';
                finalConfidence = 'niedrig';
                detectionMethod = 'unclear';
            }
            
            // Update State
            const previousMode = monitorState.controlMode;
            monitorState.controlMode = finalMode;
            monitorState.controlModeConfidence = finalConfidence;
            monitorState.lastModeDetection = now;
            
            // History
            monitorState.modeDetectionHistory.push({
                time: now,
                mode: finalMode,
                confidence: finalConfidence,
                method: detectionMethod
            });
            if (monitorState.modeDetectionHistory.length > 20) {
                monitorState.modeDetectionHistory.shift();
            }
            
            // Logging bei Änderungen
            if (previousMode !== finalMode && MONITOR_CONFIG.LOG_MODE_DETECTION) {
                console.log(`🎮 Monitor v2.0: MODUS-ÄNDERUNG! ${previousMode.toUpperCase()} → ${finalMode.toUpperCase()}`);
                console.log(`   Sicherheit: ${finalConfidence}, Methode: ${detectionMethod}`);
                
                if (finalMode === 'manual' && finalConfidence !== 'niedrig') {
                    console.log(`⚠️ Monitor: KRITISCH - Wechsel zu MANUELLER STEUERUNG!`);
                    console.log(`   ❌ CT-Signale werden ignoriert`);
                    console.log(`   🔧 Scripts v2.0 können nicht mehr regeln`);
                    console.log(`   💡 LÖSUNG: In MARSTEK App auf CT-Modus umstellen`);
                    
                    // Alarm hinzufügen
                    monitorState.alarms.push({
                        time: now,
                        type: 'critical',
                        message: 'Manueller Modus erkannt - CT-Regelung deaktiviert'
                    });
                    
                } else if (finalMode === 'ct' && finalConfidence !== 'niedrig') {
                    console.log(`✅ Monitor: PERFEKT - Wechsel zu CT-STEUERUNG!`);
                    console.log(`   ✅ Scripts v2.0 können wieder regeln`);
                    console.log(`   🎯 Automatische 0W-Regelung aktiviert`);
                    
                    // Alarm entfernen wenn vorhanden
                    monitorState.alarms = monitorState.alarms.filter(a => a.type !== 'critical');
                }
            }
            
            // An andere Scripts senden
            sendToOtherScripts();
        }
        
        // ===================================================
        // v2.0: REGELGÜTE-BERECHNUNG
        // ===================================================
        
        function calculateRegulationQuality() {
            try {
                const netResult = Math.abs(monitorState.tibberCurrent);
                
                // Regelgüte in % (100% = perfekte 0W-Regelung)
                let quality = 100;
                
                if (netResult <= 20) {
                    quality = 100; // Exzellent
                } else if (netResult <= 50) {
                    quality = 95;  // Sehr gut
                } else if (netResult <= 100) {
                    quality = 85;  // Gut
                } else if (netResult <= 200) {
                    quality = 70;  // Befriedigend
                } else {
                    quality = Math.max(0, 50 - ((netResult - 200) / 20)); // Schlechter werdend
                }
                
                // Bei manueller Steuerung = 0%
                if (monitorState.controlMode === 'manual') {
                    quality = 0;
                }
                
                safeSetState(MONITOR_CONFIG.MONITOR_PREFIX + 'regulation_quality', Math.round(quality));
                
                return quality;
                
            } catch (error) {
                console.error('❌ Monitor: Regelgüte-Berechnung Fehler:', error.message);
                return 0;
            }
        }
        
        // ===================================================
        // DIAGNOSE & STATUS-UPDATES (v2.0)
        // ===================================================
        
        function updateDiagnoseAndStatus() {
            try {
                const prefix = MONITOR_CONFIG.MONITOR_PREFIX;
                
                // Netz-Resultat berechnen
                const netResult = monitorState.tibberCurrent - monitorState.deviceDischarge + monitorState.deviceCharge;
                setState(prefix + 'net_result', Math.round(netResult));
                
                // v2.0: Regelgüte berechnen
                const quality = calculateRegulationQuality();
                
                // Status-Text erstellen
                let status = "";
                const absNetResult = Math.abs(netResult);
                const modeInfo = monitorState.controlMode !== 'unbekannt' ? ` (${monitorState.controlMode.toUpperCase()}-Modus)` : '';
                
                if (monitorState.controlMode === 'manual' && monitorState.controlModeConfidence !== 'niedrig') {
                    status = `⚠️ MANUELLER MODUS AKTIV - CT-Regelung DEAKTIVIERT! In App auf CT-Modus umstellen.`;
                } else if (!monitorState.coreActive) {
                    status = `❌ CORE-ENGINE v2.0 NICHT AKTIV - CT-Simulation gestoppt!`;
                } else if (!monitorState.intelActive) {
                    status = `⚠️ Intelligence v2.0 nicht aktiv - nur Basis-CT`;
                } else if (monitorState.limitingActive) {
                    status = `🔒 Begrenzung aktiv${modeInfo} - System v2.0 funktioniert optimal`;
                } else if (absNetResult <= 20) {
                    status = `🏆 EXZELLENTE 0W-REGELUNG v2.0!${modeInfo} (${Math.round(quality)}% Güte)`;
                } else if (absNetResult <= 50) {
                    status = `✅ Gut geregelt v2.0${modeInfo} (${Math.round(quality)}% Güte)`;
                } else {
                    status = `🎯 Normale Regelung v2.0${modeInfo} - ${Math.round(netResult)}W Netz-Resultat (${Math.round(quality)}% Güte)`;
                }
                setState(prefix + 'status', status);
                
                // Timeline erstellen (v2.0)
                const now = new Date().toLocaleTimeString();
                const coreStatus = monitorState.coreActive ? '✅' : '❌';
                const intelStatus = monitorState.intelActive ? '✅' : '⚠️';
                const apiStatus = (Date.now() - monitorState.apiState.lastFetch) < 600000 ? '✅' : '⚠️';
                
                const timeline = [
                    `[${now}] 📊 MARSTEK MONITOR v2.0`,
                    `Core: ${coreStatus} | Intelligence: ${intelStatus} | API: ${apiStatus}`,
                    `Modus: ${monitorState.controlMode.toUpperCase()} (${monitorState.controlModeConfidence})`,
                    `SOC: ${monitorState.deviceSoc}% | Netz: ${Math.round(netResult)}W | Güte: ${Math.round(quality)}%`,
                    `Tibber: ${Math.round(monitorState.tibberCurrent)}W → Gemeldet: ${Math.round(monitorState.reportedPower)}W`,
                    `System: ${monitorState.systemStatus} v2.0`
                ].join(' | ');
                setState(prefix + 'timeline', timeline);
                
                // API-Timing
                if (monitorState.lastReportTime) {
                    const apiDelay = Math.round(Date.now()/1000 - monitorState.lastReportTime);
                    setState(prefix + 'api_delay', apiDelay);
                }
                
                // Alarme
                const alarmText = monitorState.alarms.map(a => `[${new Date(a.time).toLocaleTimeString()}] ${a.message}`).join(' | ');
                setState(prefix + 'alarms', alarmText);
                
                // v2.0: Erweiterte Tages-Zusammenfassung
                let dailySummary = `SOC: ${monitorState.deviceSoc}% | Netz: ${Math.round(netResult)}W | Modus: ${monitorState.controlMode} | Güte: ${Math.round(quality)}%`;
                if (monitorState.intelActive) {
                    // Daten von Intelligence v2.0 holen
                    try {
                        const dailyNetPurchase = getState(MONITOR_CONFIG.INTEL_PREFIX + 'daily_net_purchase_kwh').val || 0;
                        const zeroWattPercent = getState(MONITOR_CONFIG.INTEL_PREFIX + 'zero_watt_time_percent').val || 0;
                        dailySummary += ` | Bezug: ${dailyNetPurchase.toFixed(2)}kWh | 0W: ${zeroWattPercent.toFixed(1)}%`;
                    } catch (error) {
                        // Intelligence-Daten nicht verfügbar
                    }
                }
                setState(prefix + 'daily_summary', dailySummary);
                
            } catch (error) {
                console.error('❌ Monitor: Diagnose-Update Fehler:', error.message);
            }
        }
        
        // ===================================================
        // HAUPT-MONITOR-LOOP (v2.0)
        // ===================================================
        
        function runMonitorLoop() {
            try {
                // 1. Von anderen Scripts lesen
                readFromOtherScripts();
                
                // 2. Steuerungsmodus-Erkennung aktualisieren
                const shouldUpdateMode = !monitorState.lastModeDetection || 
                    (Date.now() - monitorState.lastModeDetection) > 60000 ||
                    (monitorState.controlMode === 'manual' && (Date.now() - monitorState.lastModeDetection) > 30000);
                
                if (shouldUpdateMode) {
                    updateControlModeDetection();
                }
                
                // 3. System-Status bewerten (v2.0)
                if (monitorState.coreActive && monitorState.intelActive) {
                    monitorState.systemStatus = 'optimal-v2.0';
                } else if (monitorState.coreActive) {
                    monitorState.systemStatus = 'basic-ct-v2.0';
                } else {
                    monitorState.systemStatus = 'critical';
                }
                
                // 4. Diagnose & Status aktualisieren
                updateDiagnoseAndStatus();
                
                // 5. An andere Scripts senden
                sendToOtherScripts();
                
                monitorState.lastUpdate = Date.now();
                
            } catch (error) {
                console.error('❌ Monitor: Loop-Fehler:', error.message);
                monitorState.systemStatus = 'error';
            }
        }
        
        // ===================================================
        // OVERRIDE & DEBUG FUNKTIONEN (UNVERÄNDERT)
        // ===================================================
        
        function handleOverrides() {
            try {
                const prefix = MONITOR_CONFIG.MONITOR_PREFIX;
                
                // Override-Modus prüfen
                const overrideMode = getState(prefix + 'override_mode').val || '';
                if (overrideMode !== monitorState.overrideMode) {
                    monitorState.overrideMode = overrideMode;
                    if (MONITOR_CONFIG.LOG_MONITOR) {
                        console.log(`🔧 Monitor v2.0: Override-Modus geändert: "${overrideMode}"`);
                    }
                }
                
                // Manueller Modus-Override
                const manualModeOverride = getState(prefix + 'manual_mode_override').val || '';
                if (manualModeOverride !== monitorState.manualModeOverride) {
                    monitorState.manualModeOverride = manualModeOverride;
                    if (manualModeOverride === 'ct') {
                        monitorState.controlMode = 'ct';
                        monitorState.controlModeConfidence = 'hoch';
                        console.log(`🔧 Monitor v2.0: Manueller Override - Modus auf CT gesetzt`);
                    } else if (manualModeOverride === 'manual') {
                        monitorState.controlMode = 'manual';
                        monitorState.controlModeConfidence = 'hoch';
                        console.log(`🔧 Monitor v2.0: Manueller Override - Modus auf MANUAL gesetzt`);
                    }
                }
                
                // Sofort-Prüfung
                const checkModeNow = getState(prefix + 'check_mode_now').val;
                if (checkModeNow === true) {
                    console.log('🔄 Monitor v2.0: Sofort-Prüfung gestartet...');
                    fetchDeviceData(); // Sofortige API-Abfrage
                    setState(prefix + 'check_mode_now', false); // Reset
                }
                
            } catch (error) {
                console.error('❌ Monitor: Override-Handling Fehler:', error.message);
            }
        }
        
        // ===================================================
        // MONITOR START (v2.0)
        // ===================================================
        
        function startMonitor() {
            console.log('📊 MARSTEK-Monitor-Control v2.0 - ÜBERWACHUNG & STEUERUNG\n');
            console.log('🎯 ZWECK: ÜBERWACHUNG, DIAGNOSE & STEUERUNG');
            console.log('✅ Steuerungsmodus-Erkennung (CT vs Manuell)');
            console.log('✅ API-Integration + Smart-Timing');
            console.log('✅ Diagnose-System + Datenpunkte-Verwaltung');
            console.log('✅ Debug-Modi + Override-Funktionen');
            console.log('✅ SOC-Intelligence (von API für Intelligence v2.0)');
            console.log('✅ v2.0: Regelgüte-Monitoring für korrekte Logik');
            console.log('');
            console.log('🔗 KOMMUNIKATION:');
            console.log('   📥 Überwacht: Core v2.0 + Intelligence v2.0 Status');
            console.log('   📡 API: MARSTEK Cloud-Integration');
            console.log('   🎮 Steuert: Override-Modi und Modus-Erkennung');
            console.log('   📈 Überwacht: Regelgüte der neuen 0W-Regelung');
            console.log('   ⚠️ Darf crashen ohne CT/Intelligence zu stoppen!');
            console.log('=====================================');
            
            // Datenpunkte erstellen
            createMonitorDatapoints();
                
            // Status setzen
            safeSetState(MONITOR_CONFIG.MONITOR_PREFIX + 'monitor_active', true);
            safeSetState(MONITOR_CONFIG.MONITOR_PREFIX + 'system_status', 'starting');
            safeSetState(MONITOR_CONFIG.SHARED_PREFIX + 'system_status', 'starting-v2.0');
            safeSetState(MONITOR_CONFIG.MONITOR_PREFIX + 'system_version', 'v2.0');
        
            
            // Loops starten
            setInterval(runMonitorLoop, MONITOR_CONFIG.UPDATE_INTERVAL);         // 10s Monitor-Loop
            setInterval(fetchDeviceDataSmart, 30000);                           // 30s API-Check
            setInterval(handleOverrides, 5000);                                 // 5s Override-Check
            
            // Sofort starten
            setTimeout(runMonitorLoop, 3000);
            setTimeout(fetchDeviceData, 5000);
            
            console.log('\n📊 MONITOR v2.0 AKTIV!');
            console.log('💡 Überwacht Core v2.0 + Intelligence v2.0');
            console.log('🎮 Modus-Erkennung: ' + (MONITOR_CONFIG.MODE_DETECTION_ENABLED ? 'Aktiv' : 'Deaktiviert'));
            console.log('📡 API-Integration: ' + (MONITOR_CONFIG.API_ENABLED ? 'Aktiv' : 'Deaktiviert'));
            console.log('🔋 SOC-Intelligence: Übertragen an Intelligence-Script v2.0');
            console.log('📈 Regelgüte-Monitoring: Aktiv');
            console.log('=====================================\n');
        }
        
        function stopMonitor() {
            try {
                safeSetState(MONITOR_CONFIG.MONITOR_PREFIX + 'monitor_active', false);
                safeSetState(MONITOR_CONFIG.MONITOR_PREFIX + 'system_status', 'stopped');
                console.log('🛑 MARSTEK-Monitor v2.0 beendet');
            } catch (error) {
                console.error('❌ Monitor Stop-Fehler:', error.message);
            }
        }
        
        // ===================================================
        // SCRIPT START
        // ===================================================
        
        startMonitor();
        
        // Event-Handler für Sofort-Prüfung
        on({id: MONITOR_CONFIG.MONITOR_PREFIX + 'check_mode_now', change: 'ne'}, function (obj) {
            if (obj.state.val === true) {
                fetchDeviceData();
                setTimeout(() => {
                    setState(MONITOR_CONFIG.MONITOR_PREFIX + 'check_mode_now', false);
                }, 1000);
            }
        });
        
        onStop(() => {
            stopMonitor();
        });
        
        // ===================================================
        // KONFIGURATIONSHINWEISE FÜR FORUM-NUTZER:
        // ===================================================
        /*
        WICHTIGE ANPASSUNGEN NÖTIG:
        
        1. PREFIXE ANPASSEN:
           Zeile 20: SHARED_PREFIX: '0_userdata.0.marstek_V-E.shared.'
           Zeile 21: INTEL_PREFIX: '0_userdata.0.marstek_V-E.intel.'
           Zeile 22: MONITOR_PREFIX: '0_userdata.0.marstek_V-E.monitor.'
           → Passe die Prefixe an deine ioBroker-Struktur an
        
        2. API-ZUGANGSDATEN AUSFÜLLEN:
           Nach dem Script-Start in ioBroker:
           - monitor.mailbox: Deine E-Mail-Adresse für MARSTEK-App
           - monitor.token: API-Token aus der MARSTEK-App
           - monitor.deviceId: Deine MARSTEK Speicher-ID (z.B. 3456, 4567, etc.)
           
        3. MARSTEK API-TOKEN ERHALTEN:
           - MARSTEK-App öffnen
           - Einstellungen → API oder Entwickler-Bereich
           - Token generieren und kopieren
           
        4. DEVICE-ID FINDEN:
           - In der MARSTEK-App: Geräteinfo
           - Oder MAC-Adresse → letzte 4 Stellen (z.B. ABCD3456 → 4567)
           
        5. ZWEITER SPEICHER (OPTIONAL):
           - enable_second_storage auf true setzen falls vorhanden
           - Zweite Device-ID entsprechend anpassen
        
        FEATURES DEAKTIVIEREN (OPTIONAL):
        - API_ENABLED: false → Deaktiviert Cloud-Integration
        - MODE_DETECTION_ENABLED: false → Deaktiviert Modus-Erkennung
        - Logging reduzieren: LOG_MONITOR/LOG_API: false setzen
        
        HINWEIS: 
        Das Monitor-Script ist optional! Core + Intelligence funktionieren auch ohne Monitor.
        Monitor bietet aber wertvolle Diagnose- und Überwachungsfunktionen.
        */
        

        Grundsätzlich läuft es mir, bin aber mit der Regelung noch nicht zufrieden.

        Edit:
        Ne, die Regelung ist noch nicht richtig, es Oszilliert zu viel hin und her bei der Entladung.

        ioBroker auf: Lenovo ThinkCentre M910Q Tiny i5-7500T 16 GB mit proxmox in VM (Bookworm)

        C 1 Antwort Letzte Antwort
        0
        • G Gismoh

          @gismoh

          3-MARSTEK-Monitor-Control:

          // ===================================================
          // MARSTEK-Monitor-Control v2.0 - ÜBERWACHUNG & STEUERUNG
          // ===================================================
          // 
          // 📊 ZWECK: ÜBERWACHUNG, DIAGNOSE & STEUERUNG
          // ✅ Steuerungsmodus-Erkennung (CT vs Manuell)
          // ✅ API-Integration + Smart-Timing
          // ✅ Diagnose-System + Datenpunkte-Verwaltung
          // ✅ Debug-Modi + Override-Funktionen
          // ✅ SOC-Daten für Intelligence-Script v2.0
          // ✅ v2.0: Kompatibel mit korrigierter Regelungslogik
          // 
          // ⚠️ DARF CRASHEN ohne Core/Intelligence zu stoppen!
          // 
          // ===================================================
          
          // KONFIGURATION
          const MONITOR_CONFIG = {
              // API-Zugangsdaten (werden aus Datenpunkten gelesen)
              API_ENABLED: true,
              API_INTERVAL: 300000,
              
              // Steuerungsmodus-Erkennung
              MODE_DETECTION_ENABLED: true,
              
              // Timing
              UPDATE_INTERVAL: 10000,  // Monitor läuft langsamer
              
              // Kommunikation - BITTE ANPASSEN!
              SHARED_PREFIX: '0_userdata.0.marstek_V-E.shared.',        // ← Dein Shared-Prefix hier eintragen
              INTEL_PREFIX: '0_userdata.0.marstek_V-E.intel.',          // ← Dein Intelligence-Prefix hier eintragen
              MONITOR_PREFIX: '0_userdata.0.marstek_V-E.monitor.',      // ← Dein Monitor-Prefix hier eintragen
              
              // Logging
              LOG_MONITOR: true,
              LOG_MODE_DETECTION: true,
              LOG_API: true
          };
          
          // MONITOR STATE
          let monitorState = {
              // Von Core/Intelligence empfangen
              coreActive: false,
              intelActive: false,
              tibberCurrent: 0,
              reportedPower: 0,          // v2.0: Neuer Name für gemeldeten Wert
              limitingActive: false,
              
              // API-Daten
              deviceSoc: 0,
              deviceCharge: 0,
              deviceDischarge: 0,
              lastReportTime: 0,
              
              // Steuerungsmodus-Erkennung
              controlMode: 'unbekannt',
              controlModeConfidence: 'niedrig',
              lastModeDetection: 0,
              modeDetectionHistory: [],
              apiModeData: {},
              behaviorModeData: {
                  responseCount: 0,
                  noResponseCount: 0,
                  avgEfficiency: 0,
                  lastBehaviorCheck: 0
              },
              
              // API-Timing
              apiState: {
                  lastFetch: 0,
                  lastActivity: Date.now(),
                  nextFetchTime: 0
              },
              
              // Status & Diagnose
              monitorActive: true,
              lastUpdate: 0,
              systemStatus: 'starting',
              alarms: [],
              
              // Override-Modi
              overrideMode: '',
              manualModeOverride: ''
          };
          
          // ===================================================
          // MONITOR DATENPUNKTE
          // ===================================================
          
          function createMonitorDatapoints() {
              const prefix = MONITOR_CONFIG.MONITOR_PREFIX;
              
              const datapoints = [
                  // API-Konfiguration - BITTE AUSFÜLLEN!
                  { name: 'mailbox', value: '', desc: 'MARSTEK Mailbox (deine E-Mail)' },
                  { name: 'token', value: '', desc: 'MARSTEK API Token (aus App)' },
                  { name: 'deviceId', value: 'XXXX', desc: 'MARSTEK Device ID (z.B. 3456)' },      // ← ANPASSEN!
                  { name: 'enable_second_storage', value: false, desc: '🔄 Zweiter Speicher (MSTYYYY)' },
                  
                  // Status
                  { name: 'system_status', value: 'starting', desc: '🔧 System-Status (shared)', shared: true },
                  { name: 'monitor_active', value: true, desc: '📊 Monitor läuft' },
                  { name: 'api_connected', value: false, desc: '📡 API verbunden' },
                  
                  // Steuerungsmodus-Erkennung
                  { name: 'control_mode_detected', value: 'unbekannt', desc: '🎮 Erkannter Steuerungsmodus' },
                  { name: 'control_mode_confidence', value: 'niedrig', desc: '🎯 Erkennungs-Sicherheit' },
                  { name: 'control_mode_method', value: 'keine', desc: '🔍 Erkennungsmethode' },
                  { name: 'manual_mode_active', value: false, desc: '⚠️ Manueller Modus aktiv' },
                  { name: 'regulation_possible', value: true, desc: '✅ Regelung möglich' },
                  { name: 'check_mode_now', value: false, desc: '🔄 Sofort-Prüfung starten' },
                  
                  // API-Daten
                  { name: 'device_charge', value: 0, desc: 'Speicher lädt [W]' },
                  { name: 'device_discharge', value: 0, desc: 'Speicher entlädt [W]' },
                  { name: 'device_soc', value: 0, desc: 'Speicher SOC [%]' },
                  { name: 'api_delay', value: 0, desc: '📡 API Verzögerung [s]' },
                  { name: 'last_api_fetch', value: 0, desc: '🕐 Letzte API-Abfrage' },
                  { name: 'next_api_fetch', value: 0, desc: '⏰ Nächste API-Abfrage' },
                  
                  // Berechnete Werte
                  { name: 'net_result', value: 0, desc: 'Resultat am Netz [W]' },
                  { name: 'regulation_quality', value: 0, desc: '📈 Regelgüte [%]' },  // v2.0: Neu
                  { name: 'current_efficiency', value: 0, desc: '📈 Aktuelle Effizienz [%]' },
                  
                  // Override & Debug
                  { name: 'override_mode', value: '', desc: '🔧 Override-Modus (test/zero/normal)' },
                  { name: 'manual_mode_override', value: '', desc: '🎮 Modus-Override (ct/manual/auto)' },
                  { name: 'debug_mode', value: false, desc: '🔍 Debug-Modus aktiv' },
                  
                  // Diagnose
                  { name: 'status', value: '', desc: 'Aktueller Status' },
                  { name: 'timeline', value: '', desc: 'Timeline' },
                  { name: 'alarms', value: '', desc: '🚨 Aktive Alarme' },
                  
                  // Statistiken (Überblick)
                  { name: 'daily_summary', value: '', desc: '📊 Tages-Zusammenfassung' },
                  { name: 'system_version', value: 'v2.0', desc: '🔧 System-Version' }  // v2.0: Neu
              ];
              
              datapoints.forEach(dp => {
                  try {
                      const base = dp.shared ? MONITOR_CONFIG.SHARED_PREFIX : prefix;
                      createState(base + dp.name, dp.value, {
                          name: dp.desc,
                          type: typeof dp.value,
                          read: true,
                          write: true,
                          desc: `MARSTEK Monitor v2.0 - ${dp.desc}`
                      });
                  } catch (error) {
                      // State existiert bereits
                  }
              });
          }
          
          // ===================================================
          // KOMMUNIKATION MIT ANDEREN SCRIPTS
          // ===================================================
          
          function readFromOtherScripts() {
              try {
                  const sharedPrefix = MONITOR_CONFIG.SHARED_PREFIX;
                  const intelPrefix = MONITOR_CONFIG.INTEL_PREFIX;
                  
                  // Von Core
                  monitorState.coreActive = getState(sharedPrefix + 'core_active').val || false;
                  monitorState.tibberCurrent = getState(sharedPrefix + 'tibber_current').val || 0;
                  
                  // v2.0: Neuer Name für gemeldeten Wert
                  monitorState.reportedPower = getState(sharedPrefix + 'target_power').val || 0;
                  
                  // Von Intelligence v2.0
                  try {
                      monitorState.intelActive = getState(intelPrefix + 'intel_active').val || false;
                      monitorState.limitingActive = getState(intelPrefix + 'limiting_active').val || false;
                  } catch (error) {
                      // Intelligence möglicherweise nicht gestartet
                      monitorState.intelActive = false;
                  }
                  
                  return true;
              } catch (error) {
                  console.error('❌ Monitor: Fehler beim Lesen von anderen Scripts:', error.message);
                  return false;
              }
          }
          
          // ===================================================
          // ROBUSTER STATE-SETTER
          // ===================================================
          
          function safeSetState(id, value) {
              if (existsState(id)) {
                  try {
                      setState(id, value);
                  } catch (e) {
                      console.warn(`⚠️ Monitor safeSetState: Fehler beim Setzen von ${id}: ${e.message}`);
                  }
              } else {
                  console.warn(`⚠️ Monitor safeSetState: Datenpunkt ${id} existiert nicht.`);
              }
          }
          
          // ===================================================
          // KOMMUNIKATION MIT ANDEREN SCRIPTS (ROBUST)
          // ===================================================
          
          function sendToOtherScripts() {
              try {
                  const sharedPrefix = MONITOR_CONFIG.SHARED_PREFIX;
                  const monitorPrefix = MONITOR_CONFIG.MONITOR_PREFIX;
          
                  // Override-Modus an alle
                  safeSetState(sharedPrefix + 'override_mode', monitorState.overrideMode);
          
                  // System-Status
                  safeSetState(sharedPrefix + 'system_status', monitorState.systemStatus);
          
                  // Steuerungsmodus-Info
                  safeSetState(monitorPrefix + 'control_mode_detected', monitorState.controlMode);
                  safeSetState(monitorPrefix + 'control_mode_confidence', monitorState.controlModeConfidence);
                  safeSetState(monitorPrefix + 'manual_mode_active', monitorState.controlMode === 'manual');
                  safeSetState(monitorPrefix + 'regulation_possible', monitorState.controlMode === 'ct');
          
                  return true;
          
              } catch (error) {
                  console.error('❌ Monitor: Fehler beim Senden an andere Scripts:', error.message);
                  return false;
              }
          }
          
          // ===================================================
          // API-INTEGRATION (MARSTEK CLOUD)
          // ===================================================
          
          function fetchDeviceData() {
              if (!MONITOR_CONFIG.API_ENABLED) return;
              
              try {
                  const prefix = MONITOR_CONFIG.MONITOR_PREFIX;
                  const mailbox = getState(prefix + 'mailbox').val;
                  const token = getState(prefix + 'token').val;
                  const deviceId = getState(prefix + 'deviceId').val;
                  
                  if (!mailbox || !token || !deviceId) {
                      console.error("❌ Monitor: API-Zugangsdaten fehlen!");
                      return;
                  }
                  
                  if (MONITOR_CONFIG.LOG_API) {
                      console.log("🔄 Monitor v2.0: API-Abfrage für Speicher " + deviceId);
                  }
                  
                  const url = `https://eu.hamedata.com/ems/api/v1/getDeviceList?mailbox=${encodeURIComponent(mailbox)}&token=${token}`;
                  
                  httpGet(url, function(error, response) {
                      if (error) {
                          console.error("❌ Monitor: HTTP Fehler:", error);
                          return;
                      }
                      
                      try {
                          const result = JSON.parse(response.data);
                          
                          if (!result || result.code !== 1) {
                              console.log("❌ Monitor: API Error:", result?.msg || "Unknown");
                              return;
                          }
                          
                          const devices = result.data;
                          const targetDevice = devices.find(d => d.mac && d.mac.endsWith(deviceId));
                          
                          if (targetDevice) {
                              // Standard-Daten speichern
                              monitorState.deviceSoc = parseFloat(targetDevice.soc) || 0;
                              monitorState.deviceCharge = parseFloat(targetDevice.charge) || 0;
                              monitorState.deviceDischarge = parseFloat(targetDevice.discharge) || 0;
                              monitorState.lastReportTime = targetDevice.report_time;
                              
                              const prefix = MONITOR_CONFIG.MONITOR_PREFIX;
                              setState(prefix + 'device_charge', monitorState.deviceCharge);
                              setState(prefix + 'device_discharge', monitorState.deviceDischarge);
                              setState(prefix + 'device_soc', monitorState.deviceSoc);
                              setState(prefix + 'api_connected', true);
                              
                              // Steuerungsmodus-Erkennung
                              detectControlModeFromAPI(targetDevice);
                              
                              if (MONITOR_CONFIG.LOG_API) {
                                  console.log(`✅ Monitor v2.0: API OK - SOC: ${monitorState.deviceSoc}%, Charge: ${monitorState.deviceCharge}W, Discharge: ${monitorState.deviceDischarge}W`);
                              }
                          }
                          
                      } catch (e) {
                          console.error("❌ Monitor: Parse Fehler:", e.message);
                      }
                  });
                  
              } catch (error) {
                  console.error('❌ Monitor: API-Fetch Fehler:', error.message);
              }
          }
          
          function fetchDeviceDataSmart() {
              if (!MONITOR_CONFIG.API_ENABLED) return;
              
              const now = Date.now();
              
              if (now < monitorState.apiState.nextFetchTime) {
                  return;
              }
              
              const currentPower = Math.abs(monitorState.tibberCurrent);
              const isActive = currentPower > 100;
              
              if (isActive) {
                  monitorState.apiState.lastActivity = now;
              }
              
              // Modus-abhängige Intervalle
              let interval;
              if (monitorState.controlMode === 'manual' && monitorState.controlModeConfidence !== 'niedrig') {
                  // MANUELLER MODUS: Häufiger prüfen (auf Umstellung warten)
                  interval = 60000 + Math.random() * 30000; // 1-1.5 Minuten
              } else if (isActive) {
                  // AKTIV: Normale Intervalle
                  interval = 240000 + Math.random() * 120000; // 4-6 Minuten
              } else {
                  // INAKTIV: Längere Intervalle
                  interval = 600000 + Math.random() * 300000; // 10-15 Minuten
              }
              
              monitorState.apiState.nextFetchTime = now + interval;
              monitorState.apiState.lastFetch = now;
              
              // Timing-Info speichern
              const prefix = MONITOR_CONFIG.MONITOR_PREFIX;
              setState(prefix + 'last_api_fetch', monitorState.apiState.lastFetch);
              setState(prefix + 'next_api_fetch', monitorState.apiState.nextFetchTime);
              
              fetchDeviceData();
          }
          
          // ===================================================
          // STEUERUNGSMODUS-ERKENNUNG (UNVERÄNDERT)
          // ===================================================
          
          function detectControlModeFromAPI(deviceData) {
              if (!MONITOR_CONFIG.MODE_DETECTION_ENABLED || !deviceData) return 'unbekannt';
              
              let detectedMode = 'unbekannt';
              let confidence = 'niedrig';
              let reasons = [];
              
              // API-Feld-Analyse
              if (deviceData.status !== undefined) {
                  if (deviceData.status === 0) {
                      detectedMode = 'ct';
                      confidence = 'mittel';
                      reasons.push('status=0 → CT-Modus vermutet');
                  } else if (deviceData.status === 1) {
                      reasons.push('status=1 → Gerät online, Modus unklar');
                  }
              }
              
              // Weitere Modus-Felder suchen
              const modeFields = ['mode', 'control_mode', 'work_mode', 'operation_mode', 'ct_mode', 'manual_mode'];
              for (const field of modeFields) {
                  if (deviceData[field] !== undefined) {
                      const value = String(deviceData[field]).toLowerCase();
                      if (value.includes('manual')) {
                          detectedMode = 'manual';
                          confidence = 'hoch';
                          reasons.push(`${field}="${value}" → Manueller Modus`);
                          break;
                      } else if (value.includes('ct') || value.includes('auto') || value.includes('grid')) {
                          detectedMode = 'ct';
                          confidence = 'hoch';
                          reasons.push(`${field}="${value}" → CT-Modus`);
                          break;
                      }
                  }
              }
              
              // API-Daten speichern
              monitorState.apiModeData = {
                  access: deviceData.access,
                  status: deviceData.status,
                  detectedMode: detectedMode,
                  confidence: confidence,
                  reasons: reasons,
                  lastUpdate: Date.now(),
                  rawData: JSON.stringify(deviceData, null, 2)
              };
              
              return { mode: detectedMode, confidence: confidence, reasons: reasons };
          }
          
          function updateControlModeDetection() {
              if (!MONITOR_CONFIG.MODE_DETECTION_ENABLED) return;
              
              const now = Date.now();
              
              // API-basierte Erkennung
              let apiResult = { mode: 'unbekannt', confidence: 'niedrig', reasons: [] };
              if (monitorState.apiModeData && monitorState.apiModeData.lastUpdate && 
                  (now - monitorState.apiModeData.lastUpdate) < 600000) {
                  apiResult = {
                      mode: monitorState.apiModeData.detectedMode || 'unbekannt',
                      confidence: monitorState.apiModeData.confidence || 'niedrig',
                      reasons: monitorState.apiModeData.reasons || []
                  };
              }
              
              // Intelligente Kombination
              let finalMode = 'unbekannt';
              let finalConfidence = 'niedrig';
              let detectionMethod = 'keine';
              
              if (apiResult.confidence === 'hoch') {
                  finalMode = apiResult.mode;
                  finalConfidence = 'hoch';
                  detectionMethod = 'api';
              } else if (apiResult.confidence === 'mittel') {
                  finalMode = apiResult.mode;
                  finalConfidence = 'mittel';
                  detectionMethod = 'api';
              } else {
                  finalMode = 'unbekannt';
                  finalConfidence = 'niedrig';
                  detectionMethod = 'unclear';
              }
              
              // Update State
              const previousMode = monitorState.controlMode;
              monitorState.controlMode = finalMode;
              monitorState.controlModeConfidence = finalConfidence;
              monitorState.lastModeDetection = now;
              
              // History
              monitorState.modeDetectionHistory.push({
                  time: now,
                  mode: finalMode,
                  confidence: finalConfidence,
                  method: detectionMethod
              });
              if (monitorState.modeDetectionHistory.length > 20) {
                  monitorState.modeDetectionHistory.shift();
              }
              
              // Logging bei Änderungen
              if (previousMode !== finalMode && MONITOR_CONFIG.LOG_MODE_DETECTION) {
                  console.log(`🎮 Monitor v2.0: MODUS-ÄNDERUNG! ${previousMode.toUpperCase()} → ${finalMode.toUpperCase()}`);
                  console.log(`   Sicherheit: ${finalConfidence}, Methode: ${detectionMethod}`);
                  
                  if (finalMode === 'manual' && finalConfidence !== 'niedrig') {
                      console.log(`⚠️ Monitor: KRITISCH - Wechsel zu MANUELLER STEUERUNG!`);
                      console.log(`   ❌ CT-Signale werden ignoriert`);
                      console.log(`   🔧 Scripts v2.0 können nicht mehr regeln`);
                      console.log(`   💡 LÖSUNG: In MARSTEK App auf CT-Modus umstellen`);
                      
                      // Alarm hinzufügen
                      monitorState.alarms.push({
                          time: now,
                          type: 'critical',
                          message: 'Manueller Modus erkannt - CT-Regelung deaktiviert'
                      });
                      
                  } else if (finalMode === 'ct' && finalConfidence !== 'niedrig') {
                      console.log(`✅ Monitor: PERFEKT - Wechsel zu CT-STEUERUNG!`);
                      console.log(`   ✅ Scripts v2.0 können wieder regeln`);
                      console.log(`   🎯 Automatische 0W-Regelung aktiviert`);
                      
                      // Alarm entfernen wenn vorhanden
                      monitorState.alarms = monitorState.alarms.filter(a => a.type !== 'critical');
                  }
              }
              
              // An andere Scripts senden
              sendToOtherScripts();
          }
          
          // ===================================================
          // v2.0: REGELGÜTE-BERECHNUNG
          // ===================================================
          
          function calculateRegulationQuality() {
              try {
                  const netResult = Math.abs(monitorState.tibberCurrent);
                  
                  // Regelgüte in % (100% = perfekte 0W-Regelung)
                  let quality = 100;
                  
                  if (netResult <= 20) {
                      quality = 100; // Exzellent
                  } else if (netResult <= 50) {
                      quality = 95;  // Sehr gut
                  } else if (netResult <= 100) {
                      quality = 85;  // Gut
                  } else if (netResult <= 200) {
                      quality = 70;  // Befriedigend
                  } else {
                      quality = Math.max(0, 50 - ((netResult - 200) / 20)); // Schlechter werdend
                  }
                  
                  // Bei manueller Steuerung = 0%
                  if (monitorState.controlMode === 'manual') {
                      quality = 0;
                  }
                  
                  safeSetState(MONITOR_CONFIG.MONITOR_PREFIX + 'regulation_quality', Math.round(quality));
                  
                  return quality;
                  
              } catch (error) {
                  console.error('❌ Monitor: Regelgüte-Berechnung Fehler:', error.message);
                  return 0;
              }
          }
          
          // ===================================================
          // DIAGNOSE & STATUS-UPDATES (v2.0)
          // ===================================================
          
          function updateDiagnoseAndStatus() {
              try {
                  const prefix = MONITOR_CONFIG.MONITOR_PREFIX;
                  
                  // Netz-Resultat berechnen
                  const netResult = monitorState.tibberCurrent - monitorState.deviceDischarge + monitorState.deviceCharge;
                  setState(prefix + 'net_result', Math.round(netResult));
                  
                  // v2.0: Regelgüte berechnen
                  const quality = calculateRegulationQuality();
                  
                  // Status-Text erstellen
                  let status = "";
                  const absNetResult = Math.abs(netResult);
                  const modeInfo = monitorState.controlMode !== 'unbekannt' ? ` (${monitorState.controlMode.toUpperCase()}-Modus)` : '';
                  
                  if (monitorState.controlMode === 'manual' && monitorState.controlModeConfidence !== 'niedrig') {
                      status = `⚠️ MANUELLER MODUS AKTIV - CT-Regelung DEAKTIVIERT! In App auf CT-Modus umstellen.`;
                  } else if (!monitorState.coreActive) {
                      status = `❌ CORE-ENGINE v2.0 NICHT AKTIV - CT-Simulation gestoppt!`;
                  } else if (!monitorState.intelActive) {
                      status = `⚠️ Intelligence v2.0 nicht aktiv - nur Basis-CT`;
                  } else if (monitorState.limitingActive) {
                      status = `🔒 Begrenzung aktiv${modeInfo} - System v2.0 funktioniert optimal`;
                  } else if (absNetResult <= 20) {
                      status = `🏆 EXZELLENTE 0W-REGELUNG v2.0!${modeInfo} (${Math.round(quality)}% Güte)`;
                  } else if (absNetResult <= 50) {
                      status = `✅ Gut geregelt v2.0${modeInfo} (${Math.round(quality)}% Güte)`;
                  } else {
                      status = `🎯 Normale Regelung v2.0${modeInfo} - ${Math.round(netResult)}W Netz-Resultat (${Math.round(quality)}% Güte)`;
                  }
                  setState(prefix + 'status', status);
                  
                  // Timeline erstellen (v2.0)
                  const now = new Date().toLocaleTimeString();
                  const coreStatus = monitorState.coreActive ? '✅' : '❌';
                  const intelStatus = monitorState.intelActive ? '✅' : '⚠️';
                  const apiStatus = (Date.now() - monitorState.apiState.lastFetch) < 600000 ? '✅' : '⚠️';
                  
                  const timeline = [
                      `[${now}] 📊 MARSTEK MONITOR v2.0`,
                      `Core: ${coreStatus} | Intelligence: ${intelStatus} | API: ${apiStatus}`,
                      `Modus: ${monitorState.controlMode.toUpperCase()} (${monitorState.controlModeConfidence})`,
                      `SOC: ${monitorState.deviceSoc}% | Netz: ${Math.round(netResult)}W | Güte: ${Math.round(quality)}%`,
                      `Tibber: ${Math.round(monitorState.tibberCurrent)}W → Gemeldet: ${Math.round(monitorState.reportedPower)}W`,
                      `System: ${monitorState.systemStatus} v2.0`
                  ].join(' | ');
                  setState(prefix + 'timeline', timeline);
                  
                  // API-Timing
                  if (monitorState.lastReportTime) {
                      const apiDelay = Math.round(Date.now()/1000 - monitorState.lastReportTime);
                      setState(prefix + 'api_delay', apiDelay);
                  }
                  
                  // Alarme
                  const alarmText = monitorState.alarms.map(a => `[${new Date(a.time).toLocaleTimeString()}] ${a.message}`).join(' | ');
                  setState(prefix + 'alarms', alarmText);
                  
                  // v2.0: Erweiterte Tages-Zusammenfassung
                  let dailySummary = `SOC: ${monitorState.deviceSoc}% | Netz: ${Math.round(netResult)}W | Modus: ${monitorState.controlMode} | Güte: ${Math.round(quality)}%`;
                  if (monitorState.intelActive) {
                      // Daten von Intelligence v2.0 holen
                      try {
                          const dailyNetPurchase = getState(MONITOR_CONFIG.INTEL_PREFIX + 'daily_net_purchase_kwh').val || 0;
                          const zeroWattPercent = getState(MONITOR_CONFIG.INTEL_PREFIX + 'zero_watt_time_percent').val || 0;
                          dailySummary += ` | Bezug: ${dailyNetPurchase.toFixed(2)}kWh | 0W: ${zeroWattPercent.toFixed(1)}%`;
                      } catch (error) {
                          // Intelligence-Daten nicht verfügbar
                      }
                  }
                  setState(prefix + 'daily_summary', dailySummary);
                  
              } catch (error) {
                  console.error('❌ Monitor: Diagnose-Update Fehler:', error.message);
              }
          }
          
          // ===================================================
          // HAUPT-MONITOR-LOOP (v2.0)
          // ===================================================
          
          function runMonitorLoop() {
              try {
                  // 1. Von anderen Scripts lesen
                  readFromOtherScripts();
                  
                  // 2. Steuerungsmodus-Erkennung aktualisieren
                  const shouldUpdateMode = !monitorState.lastModeDetection || 
                      (Date.now() - monitorState.lastModeDetection) > 60000 ||
                      (monitorState.controlMode === 'manual' && (Date.now() - monitorState.lastModeDetection) > 30000);
                  
                  if (shouldUpdateMode) {
                      updateControlModeDetection();
                  }
                  
                  // 3. System-Status bewerten (v2.0)
                  if (monitorState.coreActive && monitorState.intelActive) {
                      monitorState.systemStatus = 'optimal-v2.0';
                  } else if (monitorState.coreActive) {
                      monitorState.systemStatus = 'basic-ct-v2.0';
                  } else {
                      monitorState.systemStatus = 'critical';
                  }
                  
                  // 4. Diagnose & Status aktualisieren
                  updateDiagnoseAndStatus();
                  
                  // 5. An andere Scripts senden
                  sendToOtherScripts();
                  
                  monitorState.lastUpdate = Date.now();
                  
              } catch (error) {
                  console.error('❌ Monitor: Loop-Fehler:', error.message);
                  monitorState.systemStatus = 'error';
              }
          }
          
          // ===================================================
          // OVERRIDE & DEBUG FUNKTIONEN (UNVERÄNDERT)
          // ===================================================
          
          function handleOverrides() {
              try {
                  const prefix = MONITOR_CONFIG.MONITOR_PREFIX;
                  
                  // Override-Modus prüfen
                  const overrideMode = getState(prefix + 'override_mode').val || '';
                  if (overrideMode !== monitorState.overrideMode) {
                      monitorState.overrideMode = overrideMode;
                      if (MONITOR_CONFIG.LOG_MONITOR) {
                          console.log(`🔧 Monitor v2.0: Override-Modus geändert: "${overrideMode}"`);
                      }
                  }
                  
                  // Manueller Modus-Override
                  const manualModeOverride = getState(prefix + 'manual_mode_override').val || '';
                  if (manualModeOverride !== monitorState.manualModeOverride) {
                      monitorState.manualModeOverride = manualModeOverride;
                      if (manualModeOverride === 'ct') {
                          monitorState.controlMode = 'ct';
                          monitorState.controlModeConfidence = 'hoch';
                          console.log(`🔧 Monitor v2.0: Manueller Override - Modus auf CT gesetzt`);
                      } else if (manualModeOverride === 'manual') {
                          monitorState.controlMode = 'manual';
                          monitorState.controlModeConfidence = 'hoch';
                          console.log(`🔧 Monitor v2.0: Manueller Override - Modus auf MANUAL gesetzt`);
                      }
                  }
                  
                  // Sofort-Prüfung
                  const checkModeNow = getState(prefix + 'check_mode_now').val;
                  if (checkModeNow === true) {
                      console.log('🔄 Monitor v2.0: Sofort-Prüfung gestartet...');
                      fetchDeviceData(); // Sofortige API-Abfrage
                      setState(prefix + 'check_mode_now', false); // Reset
                  }
                  
              } catch (error) {
                  console.error('❌ Monitor: Override-Handling Fehler:', error.message);
              }
          }
          
          // ===================================================
          // MONITOR START (v2.0)
          // ===================================================
          
          function startMonitor() {
              console.log('📊 MARSTEK-Monitor-Control v2.0 - ÜBERWACHUNG & STEUERUNG\n');
              console.log('🎯 ZWECK: ÜBERWACHUNG, DIAGNOSE & STEUERUNG');
              console.log('✅ Steuerungsmodus-Erkennung (CT vs Manuell)');
              console.log('✅ API-Integration + Smart-Timing');
              console.log('✅ Diagnose-System + Datenpunkte-Verwaltung');
              console.log('✅ Debug-Modi + Override-Funktionen');
              console.log('✅ SOC-Intelligence (von API für Intelligence v2.0)');
              console.log('✅ v2.0: Regelgüte-Monitoring für korrekte Logik');
              console.log('');
              console.log('🔗 KOMMUNIKATION:');
              console.log('   📥 Überwacht: Core v2.0 + Intelligence v2.0 Status');
              console.log('   📡 API: MARSTEK Cloud-Integration');
              console.log('   🎮 Steuert: Override-Modi und Modus-Erkennung');
              console.log('   📈 Überwacht: Regelgüte der neuen 0W-Regelung');
              console.log('   ⚠️ Darf crashen ohne CT/Intelligence zu stoppen!');
              console.log('=====================================');
              
              // Datenpunkte erstellen
              createMonitorDatapoints();
                  
              // Status setzen
              safeSetState(MONITOR_CONFIG.MONITOR_PREFIX + 'monitor_active', true);
              safeSetState(MONITOR_CONFIG.MONITOR_PREFIX + 'system_status', 'starting');
              safeSetState(MONITOR_CONFIG.SHARED_PREFIX + 'system_status', 'starting-v2.0');
              safeSetState(MONITOR_CONFIG.MONITOR_PREFIX + 'system_version', 'v2.0');
          
              
              // Loops starten
              setInterval(runMonitorLoop, MONITOR_CONFIG.UPDATE_INTERVAL);         // 10s Monitor-Loop
              setInterval(fetchDeviceDataSmart, 30000);                           // 30s API-Check
              setInterval(handleOverrides, 5000);                                 // 5s Override-Check
              
              // Sofort starten
              setTimeout(runMonitorLoop, 3000);
              setTimeout(fetchDeviceData, 5000);
              
              console.log('\n📊 MONITOR v2.0 AKTIV!');
              console.log('💡 Überwacht Core v2.0 + Intelligence v2.0');
              console.log('🎮 Modus-Erkennung: ' + (MONITOR_CONFIG.MODE_DETECTION_ENABLED ? 'Aktiv' : 'Deaktiviert'));
              console.log('📡 API-Integration: ' + (MONITOR_CONFIG.API_ENABLED ? 'Aktiv' : 'Deaktiviert'));
              console.log('🔋 SOC-Intelligence: Übertragen an Intelligence-Script v2.0');
              console.log('📈 Regelgüte-Monitoring: Aktiv');
              console.log('=====================================\n');
          }
          
          function stopMonitor() {
              try {
                  safeSetState(MONITOR_CONFIG.MONITOR_PREFIX + 'monitor_active', false);
                  safeSetState(MONITOR_CONFIG.MONITOR_PREFIX + 'system_status', 'stopped');
                  console.log('🛑 MARSTEK-Monitor v2.0 beendet');
              } catch (error) {
                  console.error('❌ Monitor Stop-Fehler:', error.message);
              }
          }
          
          // ===================================================
          // SCRIPT START
          // ===================================================
          
          startMonitor();
          
          // Event-Handler für Sofort-Prüfung
          on({id: MONITOR_CONFIG.MONITOR_PREFIX + 'check_mode_now', change: 'ne'}, function (obj) {
              if (obj.state.val === true) {
                  fetchDeviceData();
                  setTimeout(() => {
                      setState(MONITOR_CONFIG.MONITOR_PREFIX + 'check_mode_now', false);
                  }, 1000);
              }
          });
          
          onStop(() => {
              stopMonitor();
          });
          
          // ===================================================
          // KONFIGURATIONSHINWEISE FÜR FORUM-NUTZER:
          // ===================================================
          /*
          WICHTIGE ANPASSUNGEN NÖTIG:
          
          1. PREFIXE ANPASSEN:
             Zeile 20: SHARED_PREFIX: '0_userdata.0.marstek_V-E.shared.'
             Zeile 21: INTEL_PREFIX: '0_userdata.0.marstek_V-E.intel.'
             Zeile 22: MONITOR_PREFIX: '0_userdata.0.marstek_V-E.monitor.'
             → Passe die Prefixe an deine ioBroker-Struktur an
          
          2. API-ZUGANGSDATEN AUSFÜLLEN:
             Nach dem Script-Start in ioBroker:
             - monitor.mailbox: Deine E-Mail-Adresse für MARSTEK-App
             - monitor.token: API-Token aus der MARSTEK-App
             - monitor.deviceId: Deine MARSTEK Speicher-ID (z.B. 3456, 4567, etc.)
             
          3. MARSTEK API-TOKEN ERHALTEN:
             - MARSTEK-App öffnen
             - Einstellungen → API oder Entwickler-Bereich
             - Token generieren und kopieren
             
          4. DEVICE-ID FINDEN:
             - In der MARSTEK-App: Geräteinfo
             - Oder MAC-Adresse → letzte 4 Stellen (z.B. ABCD3456 → 4567)
             
          5. ZWEITER SPEICHER (OPTIONAL):
             - enable_second_storage auf true setzen falls vorhanden
             - Zweite Device-ID entsprechend anpassen
          
          FEATURES DEAKTIVIEREN (OPTIONAL):
          - API_ENABLED: false → Deaktiviert Cloud-Integration
          - MODE_DETECTION_ENABLED: false → Deaktiviert Modus-Erkennung
          - Logging reduzieren: LOG_MONITOR/LOG_API: false setzen
          
          HINWEIS: 
          Das Monitor-Script ist optional! Core + Intelligence funktionieren auch ohne Monitor.
          Monitor bietet aber wertvolle Diagnose- und Überwachungsfunktionen.
          */
          

          Grundsätzlich läuft es mir, bin aber mit der Regelung noch nicht zufrieden.

          Edit:
          Ne, die Regelung ist noch nicht richtig, es Oszilliert zu viel hin und her bei der Entladung.

          C Offline
          C Offline
          cwa
          schrieb am zuletzt editiert von
          #20

          @gismoh
          Vielen Dank!
          Werde ich nach dem Urlaub direkt ausprobieren.

          G 1 Antwort Letzte Antwort
          0
          • C cwa

            @gismoh
            Vielen Dank!
            Werde ich nach dem Urlaub direkt ausprobieren.

            G Offline
            G Offline
            Gismoh
            schrieb am zuletzt editiert von
            #21

            @cwa
            Gerne ;)

            Evtl. bin ich dann auch schon weiter mit dem Regelverhalten.

            ioBroker auf: Lenovo ThinkCentre M910Q Tiny i5-7500T 16 GB mit proxmox in VM (Bookworm)

            S 1 Antwort Letzte Antwort
            0
            • G Gismoh

              @cwa
              Gerne ;)

              Evtl. bin ich dann auch schon weiter mit dem Regelverhalten.

              S Offline
              S Offline
              Steffen 5
              schrieb am zuletzt editiert von
              #22

              Hallo @gismoh,
              ich habe auch einen neuen Marstek Speicher und freu mich über Deine Lösungsidee.
              Ich hab Deine Skripte gelesen und würde mit Dir gerne über die oszillierende Regelung diskutieren.
              :-) Nur wenn Du willst natürlich.
              Meiner Meinung nach darfst Du keine "ANTI-OSZILLATIONS-GLÄTTUNG (des Tibber-Werts)" machen, denn das erzeugt schnell einen instabilen (=oszillierenden) Regelkreis.

              Wenn der B2500 auch ohne Glättung des Tibber-Werts noch viel oszilliert, kann es helfen, wenn der 'currentValue' mit einem konstanten Faktor x (0< x< 1) multipliziert wird, bevor er an den B2500 gemeldet wird.

              Kurze Erklärung:
              Im Haus wird der Strom verbraucht, den der Stromspeicher und der Netzanschluss liefert.
              Die Aufgabe des Stromspeichers ist soviel Strom zu liefern, dass der Netzanschluss 0kW liefert.

              (Vereinfachte) Funktion der Regelschleife mit Glättung:
              t0: Stromspeicher bekommt gemeldet, dass der Netzanschluss 100W liefert --> Leistungsabgabe des Stromspeichers steigt um 100W
              t1: Netzanschluss liefert 0W, wegen der Glättungsfunktion wird dem Stromspeicher nicht 0W, sondern 70W gemeldet. --> Leistungsabgabe des Stromzählers wird weiter erhöht. (Es entsteht eine Oszillation...)

              (Vereinfachte) Funktion der Regelschleife mit Dämpfung:
              Beispiel mit Dämpfungsfaktor x = 0.8
              t0: Netzanschluss liefert 100W --> Stromspeicher bekommt gemeldet, dass 80W an Leistung fehlen --> Leistungsabgabe des Stromspeichers steigt um 80W
              t1: Netzanschluss liefert 20W --> Stromspeicher bekommt gemeldet, dass 16W an Leistung fehlen --> Leistungsabgabe des Stromspeichers steigt um 16W
              t2: Netzanschluss liefert 4W --> Stromspeicher bekommt gemeldet, dass 3.2W an Leistung fehlen --> Leistungsabgabe des Stromspeichers steigt um 3,2W
              (Nach ein paar Zyklen stimmt die Leistungsabgabe des Stromspeichers perfekt)

              Viele Grüße,
              Steffen

              G 1 Antwort Letzte Antwort
              0
              • S Steffen 5

                Hallo @gismoh,
                ich habe auch einen neuen Marstek Speicher und freu mich über Deine Lösungsidee.
                Ich hab Deine Skripte gelesen und würde mit Dir gerne über die oszillierende Regelung diskutieren.
                :-) Nur wenn Du willst natürlich.
                Meiner Meinung nach darfst Du keine "ANTI-OSZILLATIONS-GLÄTTUNG (des Tibber-Werts)" machen, denn das erzeugt schnell einen instabilen (=oszillierenden) Regelkreis.

                Wenn der B2500 auch ohne Glättung des Tibber-Werts noch viel oszilliert, kann es helfen, wenn der 'currentValue' mit einem konstanten Faktor x (0< x< 1) multipliziert wird, bevor er an den B2500 gemeldet wird.

                Kurze Erklärung:
                Im Haus wird der Strom verbraucht, den der Stromspeicher und der Netzanschluss liefert.
                Die Aufgabe des Stromspeichers ist soviel Strom zu liefern, dass der Netzanschluss 0kW liefert.

                (Vereinfachte) Funktion der Regelschleife mit Glättung:
                t0: Stromspeicher bekommt gemeldet, dass der Netzanschluss 100W liefert --> Leistungsabgabe des Stromspeichers steigt um 100W
                t1: Netzanschluss liefert 0W, wegen der Glättungsfunktion wird dem Stromspeicher nicht 0W, sondern 70W gemeldet. --> Leistungsabgabe des Stromzählers wird weiter erhöht. (Es entsteht eine Oszillation...)

                (Vereinfachte) Funktion der Regelschleife mit Dämpfung:
                Beispiel mit Dämpfungsfaktor x = 0.8
                t0: Netzanschluss liefert 100W --> Stromspeicher bekommt gemeldet, dass 80W an Leistung fehlen --> Leistungsabgabe des Stromspeichers steigt um 80W
                t1: Netzanschluss liefert 20W --> Stromspeicher bekommt gemeldet, dass 16W an Leistung fehlen --> Leistungsabgabe des Stromspeichers steigt um 16W
                t2: Netzanschluss liefert 4W --> Stromspeicher bekommt gemeldet, dass 3.2W an Leistung fehlen --> Leistungsabgabe des Stromspeichers steigt um 3,2W
                (Nach ein paar Zyklen stimmt die Leistungsabgabe des Stromspeichers perfekt)

                Viele Grüße,
                Steffen

                G Offline
                G Offline
                Gismoh
                schrieb am zuletzt editiert von
                #23

                Moin @steffen-5
                , besten Dank und sehr gerne.
                Bin gerade leider etwas im Streß, und sehe mir später deinen Kommentar noch mal an.
                Aktuell sind meine Scripte eh bereits etwas anders - hatte noch einen "Blöden" Fehler bei mir gehabt.

                ioBroker auf: Lenovo ThinkCentre M910Q Tiny i5-7500T 16 GB mit proxmox in VM (Bookworm)

                1 Antwort Letzte Antwort
                0
                • O Offline
                  O Offline
                  ottelo
                  schrieb am zuletzt editiert von ottelo
                  #24

                  Hi zusammen. Ich komme aus dem Tasmota Bereich und habe ein Blog bzgl. Stromzähler auslesen mit Wifi Lesekopf und Tasmota. Zusammen mit ein paar anderen Usern und einem Entwickler von Tasmota (Script) haben wir es geschafft, den Shelly 3EM mit Tasmota zu emulieren, damit man keine extra Hardware benötigt. Also gleicher Ansatz wie hier beschrieben, aber mit eine Standalone Lösung, die nur einen WiFi Tasmota Lesekopf für den Stromzähler und den Marstek Akku (Jupiter, Venus, B2500) benötigt.

                  Bzgl. Oszillation hatten wir auch so unsere Probleme, die wir aber nun gemeinsam lösen konnten. Bei Interesse gerne mal hier vorbeischauen oder auf meinem Blog. Ein Austausch untereinander ist für die Community immer sinnvoll. Gruß :)

                  G 1 Antwort Letzte Antwort
                  1
                  • O ottelo

                    Hi zusammen. Ich komme aus dem Tasmota Bereich und habe ein Blog bzgl. Stromzähler auslesen mit Wifi Lesekopf und Tasmota. Zusammen mit ein paar anderen Usern und einem Entwickler von Tasmota (Script) haben wir es geschafft, den Shelly 3EM mit Tasmota zu emulieren, damit man keine extra Hardware benötigt. Also gleicher Ansatz wie hier beschrieben, aber mit eine Standalone Lösung, die nur einen WiFi Tasmota Lesekopf für den Stromzähler und den Marstek Akku (Jupiter, Venus, B2500) benötigt.

                    Bzgl. Oszillation hatten wir auch so unsere Probleme, die wir aber nun gemeinsam lösen konnten. Bei Interesse gerne mal hier vorbeischauen oder auf meinem Blog. Ein Austausch untereinander ist für die Community immer sinnvoll. Gruß :)

                    G Offline
                    G Offline
                    Gismoh
                    schrieb am zuletzt editiert von Gismoh
                    #25

                    @ottelo @steffen-5

                    danke für eure Rückmeldungen.

                    Ich bin da aktuell noch mitten in der Umsetzung.
                    Grundsätzlich funktioniert die reine Skriptlösung – man braucht also keinen zusätzlichen Docker oder andere externe Tools. JS-Skripte im ioBroker reichen völlig aus.

                    Derzeit arbeite ich eher an der Steuerung und Logik. Ziel ist u.a. eine SoC-Berücksichtigung, die Marstek selbst nicht vorsieht. Also z.B.: Akku nur bis XX % laden oder nur bis XX % entladen – frei im Skript einstellbar.

                    Außerdem möchte ich eine regelbare Lade-/Entladeleistung integrieren.
                    In der App kann man zwar Grenzen setzen (z.B. max. 800 W oder 2.500 W), aber:

                    Bei der Entladung halten sich die Speicher an die eingestellte Begrenzung (u.a. wegen Leitungs-/Brandschutz).

                    Beim Laden leider nicht – selbst wenn man 800 W vorgibt, ziehen die Speicher problemlos 2.500 W. Für die Leitungen macht es aber keinen Unterschied, ob der Strom „+“ oder „–“ ist (Laden/Entladen) – belastet werden sie gleich stark.

                    Da ich selbst nicht programmieren kann, nutze ich KI zur Unterstützung. Allerdings stoße ich dabei immer wieder (trotz bezahlter Tarife) auf Sperren und Timeouts, was das Ganze ziemlich ausbremst.

                    Als Nächstes möchte ich eine Mehr-Speicher-Lösung sauber umsetzen. Erste Ansätze habe ich bereits bei mir integriert. Auch der API-Abruf läuft momentan noch in einem separaten Skript – den würde ich dann einarbeiten, sobald die Basis stabil läuft.

                    ioBroker auf: Lenovo ThinkCentre M910Q Tiny i5-7500T 16 GB mit proxmox in VM (Bookworm)

                    S 1 Antwort Letzte Antwort
                    0
                    • LukyLukeL Offline
                      LukyLukeL Offline
                      LukyLuke
                      schrieb am zuletzt editiert von
                      #26

                      Hallo, ich möchte mich hier mit einklinken.

                      Seit einer Woche besitze ich einen Marstek venus E V3.0. Im Haus läuft ein SMA Home Manager 2 an der PV Anlage inkl. Speicher.
                      Nun würde ich gerne die Venus über iobroker steuern, also nur die PV-Überproduktion speichern und nach Bedarf bzw. nachts wieder abgeben.

                      Mein Problem: Wie installiere ich unimeter in Docker auf meiner Synology 7.2?
                      Könnt ihr mir da weiterhelfen? Den Container habe ich soweit am Laufen, aber die Venus findet nix. Vermutlich habe ich das ganze falsch konfiguriert. Kennt jemand ein how2 für unimeter unter Docker?

                      Vielen Dank vorab
                      Gruß Luky

                      1 Antwort Letzte Antwort
                      0
                      Antworten
                      • In einem neuen Thema antworten
                      Anmelden zum Antworten
                      • Älteste zuerst
                      • Neuste zuerst
                      • Meiste Stimmen


                      Support us

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

                      832

                      Online

                      32.6k

                      Benutzer

                      81.9k

                      Themen

                      1.3m

                      Beiträge
                      Community
                      Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
                      ioBroker Community 2014-2025
                      logo
                      • Anmelden

                      • Du hast noch kein Konto? Registrieren

                      • Anmelden oder registrieren, um zu suchen
                      • Erster Beitrag
                        Letzter Beitrag
                      0
                      • Home
                      • Aktuell
                      • Tags
                      • Ungelesen 0
                      • Kategorien
                      • Unreplied
                      • Beliebt
                      • GitHub
                      • Docu
                      • Hilfe