Weiter zum Inhalt
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • GitHub
  • Docu
  • Hilfe
Skins
  • Hell
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dunkel
  • 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. Skripten / Logik
  4. [Vorlage] Anwesenheitssimulation mit dauerhaftem Lernen

NEWS

  • Monatsrückblick Januar/Februar 2026 ist online!
    BluefoxB
    Bluefox
    18
    1
    643

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    18
    1
    5.7k

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

[Vorlage] Anwesenheitssimulation mit dauerhaftem Lernen

Geplant Angeheftet Gesperrt Verschoben Skripten / Logik
javascripttemplatesecurity
11 Beiträge 6 Kommentatoren 401 Aufrufe 14 Beobachtet
  • Ä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.
  • David G.D Offline
    David G.D Offline
    David G.
    schrieb am zuletzt editiert von David G.
    #2

    Finde den Ansatz sehr cool und praktisch.
    Werde es evtl mal testen.

    Im Moment basiert meine Simulation auf dem Sonnenuntergang mit einen willkürlichem Offset der plus oder minus sein kann und dann dem schalten der relevanten Lampen in einer willkürlichen Reihenfolge mit willkürlichem offset.
    Das bildet natürlich keine Gewohnheiten ab. Das einzig wirklich Variable ist bei mir aber aicu nur das Klo 🚽 🪠🤣.

    Ich fände es praktisch, wenn man die Lampen über eine Funktion der DPs vergeben kann.
    So mache ich es.

    Zeigt eure Lovelace-Visualisierung klick
    (Auch ideal um sich Anregungen zu holen)

    Meine Tabellen für eure Visualisierung klick

    1 Antwort Letzte Antwort
    0
    • M Offline
      M Offline
      mrMuppet
      schrieb am zuletzt editiert von mrMuppet
      #3

      Hier ist ein kleines Update:

      1. Enum-/Aufzählungs-Support: Du kannst Lampen jetzt optional über eine ioBroker-Funktion (z.B. enum.functions.anwesenheitssimulation) verwalten. Das Skript kombiniert die Einträge aus der Liste LIGHTS und dem Enum automatisch. Du kannst sogar ganze Kanäle in das Enum ziehen – das Skript sucht sich den richtigen Datenpunkt (.STATE oder .ON) selbst.
      2. Helligkeits-Tracking: Das Skript sucht automatisch nach passenden Helligkeits-Datenpunkten im selben Kanal (z.B. .LEVEL, .ACTUAL, .BRIGHTNESS) und speichert den Dimmwert ab.
      3. Auto-Migration: Falls du das Skript startest und noch alte "Foto"-Daten in der Datenbank hast (die nur An/Aus kannten), stürzt das Skript nicht ab, sondern verarbeitet diese nahtlos weiter, bis sie nach 5 Tagen aus dem Gedächtnis rotieren.

      // =====================================================================
      // TITEL: Smart Presence Simulation (KI-Ghost-Mode) - v2
      // =====================================================================
      
      // === 1. KONFIGURATION ===
      const DP_PRESENCE: string = '0_userdata.0.Anwesenheit'; 
      
      // NEU: Optional Lampen über ioBroker "Aufzählungen" (Enums) laden. 
      // Leer lassen (''), falls nicht gewünscht.
      const ENUM_FUNKTION: string = 'enum.functions.anwesenheitssimulation'; 
      
      // Hier können Lampen weiterhin manuell eingetragen werden (Kombination mit Enum ist möglich)
      const LIGHTS: string[] = [
            'alias.0.Licht.Flur.STATE',        // <-- Trage hier alle Lampen ein, die 
            'alias.0.Licht.Wohnzimmer.STATE',  //     von der Straße aus sichtbar sind.
            'alias.0.Licht.Kueche.STATE',
            'alias.0.Licht.Bad.STATE'
      ];
      
      
      // === 2. EXPERTEN-EINSTELLUNGEN ===
      const MAX_SNAPSHOTS: number = 5;           
      const MAX_SAMPLING_DELAY: number = 300000; 
      const MAX_PLAYBACK_DELAY: number = 840000; 
      
      const DP_STORAGE: string = '0_userdata.0.Simulation.Snapshot_DB';
      
      // ============================================================
      // === TYPEN & INTERFACES ===
      // ============================================================
      interface LightStateData {
          on: boolean;
          bri?: number; // Optionaler Helligkeitswert
      }
      
      interface LightSnapshot {
          // Unterstützt sowohl das neue Format (LightStateData) als auch das alte (boolean) für reibungslose Migration
          [baseId: string]: LightStateData | boolean; 
      }
      
      interface SnapshotDatabase {
          [slotIndex: number]: LightSnapshot[];
      }
      
      interface ParsedLight {
          baseId: string;
          powerId: string;
          briId: string | null;
      }
      
      // ============================================================
      // === HILFSFUNKTIONEN ===
      // ============================================================
      function getSlotIndex(): number {
          const now = new Date();
          return Math.floor((now.getHours() * 60 + now.getMinutes()) / 15);
      }
      
      function getSafeBoolean(oid: string, fallback: boolean = false): boolean {
          if (oid && existsState(oid)) {
              const val = getState(oid).val;
              return (val === true || val === 'true' || val === 1);
          }
          return fallback;
      }
      
      // NEU: Sammelt dynamisch alle Lampen aus dem Array und dem Enum
      function getActiveLights(): ParsedLight[] {
          let rawIds: string[] = [...LIGHTS];
          
          if (ENUM_FUNKTION && existsObject(ENUM_FUNKTION)) {
              const enumObj = getObject(ENUM_FUNKTION);
              if (enumObj && enumObj.common && enumObj.common.members) {
                  rawIds = rawIds.concat(enumObj.common.members);
              }
          }
          
          // Duplikate entfernen
          rawIds = [...new Set(rawIds)];
          
          const result: ParsedLight[] = [];
          
          for (const id of rawIds) {
              if (!existsObject(id)) continue;
              
              let powerId = id;
              const obj = getObject(id);
              
              // Falls der Nutzer einen ganzen Kanal ins Enum gezogen hat, suchen wir den STATE
              if (obj && obj.type === 'channel') {
                  if (existsState(`${id}.STATE`)) powerId = `${id}.STATE`;
                  else if (existsState(`${id}.ON`)) powerId = `${id}.ON`;
              }
      
              // Helligkeits-Datenpunkt dynamisch im selben Kanal suchen
              const parts = powerId.split('.');
              parts.pop(); 
              const channel = parts.join('.');
              
              let briId: string | null = null;
              const briCandidates = ['LEVEL', 'ACTUAL', 'BRIGHTNESS', 'DIMMER', 'SET'];
              
              for (const candidate of briCandidates) {
                  if (existsState(`${channel}.${candidate}`)) {
                      briId = `${channel}.${candidate}`;
                      break;
                  }
              }
              
              result.push({ baseId: powerId, powerId, briId });
          }
          
          return result;
      }
      
      // ==========================================
      // 1. LERN-MODUS (Datenbank füttern)
      // ==========================================
      function runLearning(db: SnapshotDatabase, currentSlot: number): void {
          let snapshot: LightSnapshot = {};
          const activeLights = getActiveLights();
          
          // Aktuellen Zustand inkl. Helligkeit aller Lampen einfrieren
          for (const light of activeLights) {
              const isOn = getSafeBoolean(light.powerId, false);
              const stateData: LightStateData = { on: isOn };
              
              if (isOn && light.briId && existsState(light.briId)) {
                  const briVal = getState(light.briId).val;
                  if (typeof briVal === 'number') stateData.bri = briVal;
              }
              
              snapshot[light.baseId] = stateData;
          }
      
          if (!db[currentSlot]) db[currentSlot] = [];
          
          db[currentSlot].push(snapshot);
          if (db[currentSlot].length > MAX_SNAPSHOTS) {
              db[currentSlot].shift();
          }
      
          setState(DP_STORAGE, JSON.stringify(db), true);
          log(`[Simulation LERNEN] Block ${currentSlot} gespeichert. (${db[currentSlot].length}/${MAX_SNAPSHOTS} Snapshots)`, 'debug');
      }
      
      // ==========================================
      // 2. GHOST-MODUS (Berechnen & Abspielen)
      // ==========================================
      function runSimulation(db: SnapshotDatabase, currentSlot: number): void {
          const activeLights = getActiveLights();
      
          if (!db[currentSlot] || db[currentSlot].length === 0) {
              log(`[Simulation GHOST] Keine Daten für Block ${currentSlot}. Schalte Lichter aus.`, 'debug');
              for (const light of activeLights) {
                  if (getSafeBoolean(light.powerId, false) === true) setState(light.powerId, false, false);
              }
              return;
          }
      
          const slotSnapshots: LightSnapshot[] = db[currentSlot];
          
          const uniqueCount = new Set(slotSnapshots.map(s => JSON.stringify(s))).size;
          const chaosFactor = uniqueCount / slotSnapshots.length; 
          
          const dynamicMaxDelay = Math.floor(chaosFactor * MAX_PLAYBACK_DELAY);
          const randomDelayMs = Math.floor(Math.random() * dynamicMaxDelay);
          
          log(`[Simulation GHOST] Block ${currentSlot} | Chaos-Faktor: ${Math.round(chaosFactor*100)}% | Geplanter Delay: ${Math.round(randomDelayMs/1000)}s`, 'info');
      
          // --- ABSPIELEN MIT BERECHNETER VERZÖGERUNG ---
          setTimeout(() => {
              const randomIndex = Math.floor(Math.random() * slotSnapshots.length);
              const chosenSnapshot = slotSnapshots[randomIndex];
              
              for (const light of activeLights) {
                  const targetRaw = chosenSnapshot[light.baseId];
                  if (targetRaw === undefined) continue;
      
                  // Migration: Kompatibilität zu alten Boolean-Werten aus V1
                  let targetOn = false;
                  let targetBri: number | undefined = undefined;
                  
                  if (typeof targetRaw === 'boolean') {
                      targetOn = targetRaw;
                  } else {
                      targetOn = targetRaw.on;
                      targetBri = targetRaw.bri;
                  }
      
                  const currentOn = getSafeBoolean(light.powerId, false);
                  
                  if (targetOn) {
                      // Wenn Lampe an sein soll: Zuerst (optional) dimmen, dann einschalten
                      if (targetBri !== undefined && light.briId) {
                          const currentBri = getState(light.briId).val;
                          if (currentBri !== targetBri) setState(light.briId, targetBri, false);
                      }
                      if (!currentOn) setState(light.powerId, true, false);
                  } else {
                      // Wenn Lampe aus sein soll
                      if (currentOn) setState(light.powerId, false, false);
                  }
              }
          }, randomDelayMs);
      }
      
      // === INIT & CRONJOB ===
      createState(DP_STORAGE, JSON.stringify({}), { type: 'string', name: 'Snapshot Datenbank (JSON)', role: 'json' }, () => {
          
          schedule("*/15 * * * *", () => {
              const isPresent = getSafeBoolean(DP_PRESENCE, true);
              const currentSlot = getSlotIndex(); 
              
              let db: SnapshotDatabase = {};
              try {
                  const raw = getState(DP_STORAGE).val as string;
                  if (raw) db = JSON.parse(raw) as SnapshotDatabase;
              } catch (e) {
                  log('[Simulation] Fehler beim Lesen der Datenbank, starte mit leerer DB neu.', 'warn');
              }
      
              if (isPresent) {
                  const samplingDelayMs = Math.floor(Math.random() * MAX_SAMPLING_DELAY); 
                  log(`[Simulation LERNEN] Block ${currentSlot} ausgelöst. Mache das Foto in ${Math.round(samplingDelayMs/1000)}s...`, 'debug');
                  
                  setTimeout(() => {
                      runLearning(db, currentSlot);
                  }, samplingDelayMs);
      
              } else {
                  runSimulation(db, currentSlot);
              }
          });
      
          log('[Simulation] KI-Snapshot-Engine gestartet. (V2: Enums & Helligkeit integriert)');
      });
      
      

      ioBroker auf NUC (Celeron mit Ubuntu-Server)

      Homematic, HMIP, Hue, Unifi, Plex, Nest, Roborock, Google Assistant

      1 Antwort Letzte Antwort
      2
      • C Offline
        C Offline
        Chrille1507
        schrieb am zuletzt editiert von
        #4

        Hallo,
        eine tolle Idee, die gleich mal testen werde.

        Eine kurze Frage, sind

        "0_userdata.0.Anwesenheitssimulation_Snapshots" und "0_userdata.0.Simulation.Snapshot_DB" nicht die gleichen Datenpunkte?

        M 1 Antwort Letzte Antwort
        0
        • M mrMuppet

          Hallo zusammen,

          ich möchte euch heute ein Projekt vorstellen, das das Thema Anwesenheitssimulation einmal anders angeht. Anstatt starrer Pläne oder durchschaubarer Zufallsschaltungen nutzt dieses Skript einen Snapshot-Ansatz, der sich vollautomatisch eurem echten Leben anpasst.

          Das Konzept: Ein System, das mitdenkt

          Das Skript erstellt alle 15 Minuten einen "Snapshot" eurer Lichter (oder anderer Geräte) – aber nur, wenn ihr wirklich zu Hause seid. Im Abwesenheitsmodus (Urlaub) spielt es diese Aufzeichnungen zeitversetzt wieder ab.

          Die Highlights:

          • Absolut wartungsfrei: Einmal eingerichtet, müsst ihr nie wieder eingreifen. Keine Sommer-/Winterzeit-Umstellung, kein Nachjustieren bei neuen Gewohnheiten.
          • Ganzjährig nutzbar: Da das Skript kontinuierlich lernt und alte Snapshots nach 5 Tagen automatisch überschreibt (Ringspeicher), "weiß" es im Dezember von selbst, dass das Licht früher brennen muss als im Juli.
          • Natürliches Verhalten: Es spiegelt euer echtes Leben. Werden die Tage kürzer oder ändert sich euer Rhythmus, lernt die Simulation das einfach mit.
          • Intelligente Variation: Aus den Snapshots der letzten Tage wird per Zufall gewählt und mit einem "Jitter" (zufällige Verzögerung) geschaltet. Das wirkt für Außenstehende absolut menschlich.

          Neu in V2:

          • Enum-/Aufzählungs-Support: Du kannst Lampen jetzt optional über eine ioBroker-Funktion (z.B. enum.functions.anwesenheitssimulation) verwalten. Das Skript kombiniert die Einträge aus der Liste LIGHTS und dem Enum automatisch. Du kannst sogar ganze Kanäle in das Enum ziehen – das Skript sucht sich den richtigen Datenpunkt (.STATE oder .ON) selbst.
          • Helligkeits-Tracking: Das Skript sucht automatisch nach passenden Helligkeits-Datenpunkten im selben Kanal (z.B. .LEVEL, .ACTUAL, .BRIGHTNESS) und speichert den Dimmwert ab.
          • Auto-Migration: Falls du das Skript startest und noch alte "Foto"-Daten in der Datenbank hast (die nur An/Aus kannten), stürzt das Skript nicht ab, sondern verarbeitet diese nahtlos weiter, bis sie nach 5 Tagen aus dem Gedächtnis rotieren.

          Einrichtung & Installation

          1. Datenpunkte 0_userdata.0.Anwesenheit (Urlaubs-Trigger) und 0_userdata.0.Anwesenheitssimulation_Snapshots_DB (JSON-Speicher) anlegen.
          2. Eure Geräte-IDs im devices-Array eintragen. Fertig.

          Das Skript (TypeScript):

          // TITEL: Smart Presence Simulation (KI-Ghost-Mode) - v2
          // =====================================================================
          
          // === 1. KONFIGURATION ===
          const DP_PRESENCE: string = '0_userdata.0.Anwesenheit'; 
          
          // NEU: Optional Lampen über ioBroker "Aufzählungen" (Enums) laden. 
          // Leer lassen (''), falls nicht gewünscht.
          const ENUM_FUNKTION: string = 'enum.functions.anwesenheitssimulation'; 
          
          // Hier können Lampen weiterhin manuell eingetragen werden (Kombination mit Enum ist möglich)
          const LIGHTS: string[] = [
                'alias.0.Licht.Flur.STATE',        // <-- Trage hier alle Lampen ein, die 
                'alias.0.Licht.Wohnzimmer.STATE',  //     von der Straße aus sichtbar sind.
                'alias.0.Licht.Kueche.STATE',
                'alias.0.Licht.Bad.STATE'
          ];
          
          
          // === 2. EXPERTEN-EINSTELLUNGEN ===
          const MAX_SNAPSHOTS: number = 5;           
          const MAX_SAMPLING_DELAY: number = 300000; 
          const MAX_PLAYBACK_DELAY: number = 840000; 
          
          const DP_STORAGE: string = '0_userdata.0.Simulation.Snapshot_DB';
          
          // ============================================================
          // === TYPEN & INTERFACES ===
          // ============================================================
          interface LightStateData {
              on: boolean;
              bri?: number; // Optionaler Helligkeitswert
          }
          
          interface LightSnapshot {
              // Unterstützt sowohl das neue Format (LightStateData) als auch das alte (boolean) für reibungslose Migration
              [baseId: string]: LightStateData | boolean; 
          }
          
          interface SnapshotDatabase {
              [slotIndex: number]: LightSnapshot[];
          }
          
          interface ParsedLight {
              baseId: string;
              powerId: string;
              briId: string | null;
          }
          
          // ============================================================
          // === HILFSFUNKTIONEN ===
          // ============================================================
          function getSlotIndex(): number {
              const now = new Date();
              return Math.floor((now.getHours() * 60 + now.getMinutes()) / 15);
          }
          
          function getSafeBoolean(oid: string, fallback: boolean = false): boolean {
              if (oid && existsState(oid)) {
                  const val = getState(oid).val;
                  return (val === true || val === 'true' || val === 1);
              }
              return fallback;
          }
          
          // NEU: Sammelt dynamisch alle Lampen aus dem Array und dem Enum
          function getActiveLights(): ParsedLight[] {
              let rawIds: string[] = [...LIGHTS];
              
              if (ENUM_FUNKTION && existsObject(ENUM_FUNKTION)) {
                  const enumObj = getObject(ENUM_FUNKTION);
                  if (enumObj && enumObj.common && enumObj.common.members) {
                      rawIds = rawIds.concat(enumObj.common.members);
                  }
              }
              
              // Duplikate entfernen
              rawIds = [...new Set(rawIds)];
              
              const result: ParsedLight[] = [];
              
              for (const id of rawIds) {
                  if (!existsObject(id)) continue;
                  
                  let powerId = id;
                  const obj = getObject(id);
                  
                  // Falls der Nutzer einen ganzen Kanal ins Enum gezogen hat, suchen wir den STATE
                  if (obj && obj.type === 'channel') {
                      if (existsState(`${id}.STATE`)) powerId = `${id}.STATE`;
                      else if (existsState(`${id}.ON`)) powerId = `${id}.ON`;
                  }
          
                  // Helligkeits-Datenpunkt dynamisch im selben Kanal suchen
                  const parts = powerId.split('.');
                  parts.pop(); 
                  const channel = parts.join('.');
                  
                  let briId: string | null = null;
                  const briCandidates = ['LEVEL', 'ACTUAL', 'BRIGHTNESS', 'DIMMER', 'SET'];
                  
                  for (const candidate of briCandidates) {
                      if (existsState(`${channel}.${candidate}`)) {
                          briId = `${channel}.${candidate}`;
                          break;
                      }
                  }
                  
                  result.push({ baseId: powerId, powerId, briId });
              }
              
              return result;
          }
          
          // ==========================================
          // 1. LERN-MODUS (Datenbank füttern)
          // ==========================================
          function runLearning(db: SnapshotDatabase, currentSlot: number): void {
              let snapshot: LightSnapshot = {};
              const activeLights = getActiveLights();
              
              // Aktuellen Zustand inkl. Helligkeit aller Lampen einfrieren
              for (const light of activeLights) {
                  const isOn = getSafeBoolean(light.powerId, false);
                  const stateData: LightStateData = { on: isOn };
                  
                  if (isOn && light.briId && existsState(light.briId)) {
                      const briVal = getState(light.briId).val;
                      if (typeof briVal === 'number') stateData.bri = briVal;
                  }
                  
                  snapshot[light.baseId] = stateData;
              }
          
              if (!db[currentSlot]) db[currentSlot] = [];
              
              db[currentSlot].push(snapshot);
              if (db[currentSlot].length > MAX_SNAPSHOTS) {
                  db[currentSlot].shift();
              }
          
              setState(DP_STORAGE, JSON.stringify(db), true);
              log(`[Simulation LERNEN] Block ${currentSlot} gespeichert. (${db[currentSlot].length}/${MAX_SNAPSHOTS} Snapshots)`, 'debug');
          }
          
          // ==========================================
          // 2. GHOST-MODUS (Berechnen & Abspielen)
          // ==========================================
          function runSimulation(db: SnapshotDatabase, currentSlot: number): void {
              const activeLights = getActiveLights();
          
              if (!db[currentSlot] || db[currentSlot].length === 0) {
                  log(`[Simulation GHOST] Keine Daten für Block ${currentSlot}. Schalte Lichter aus.`, 'debug');
                  for (const light of activeLights) {
                      if (getSafeBoolean(light.powerId, false) === true) setState(light.powerId, false, false);
                  }
                  return;
              }
          
              const slotSnapshots: LightSnapshot[] = db[currentSlot];
              
              const uniqueCount = new Set(slotSnapshots.map(s => JSON.stringify(s))).size;
              const chaosFactor = uniqueCount / slotSnapshots.length; 
              
              const dynamicMaxDelay = Math.floor(chaosFactor * MAX_PLAYBACK_DELAY);
              const randomDelayMs = Math.floor(Math.random() * dynamicMaxDelay);
              
              log(`[Simulation GHOST] Block ${currentSlot} | Chaos-Faktor: ${Math.round(chaosFactor*100)}% | Geplanter Delay: ${Math.round(randomDelayMs/1000)}s`, 'info');
          
              // --- ABSPIELEN MIT BERECHNETER VERZÖGERUNG ---
              setTimeout(() => {
                  const randomIndex = Math.floor(Math.random() * slotSnapshots.length);
                  const chosenSnapshot = slotSnapshots[randomIndex];
                  
                  for (const light of activeLights) {
                      const targetRaw = chosenSnapshot[light.baseId];
                      if (targetRaw === undefined) continue;
          
                      // Migration: Kompatibilität zu alten Boolean-Werten aus V1
                      let targetOn = false;
                      let targetBri: number | undefined = undefined;
                      
                      if (typeof targetRaw === 'boolean') {
                          targetOn = targetRaw;
                      } else {
                          targetOn = targetRaw.on;
                          targetBri = targetRaw.bri;
                      }
          
                      const currentOn = getSafeBoolean(light.powerId, false);
                      
                      if (targetOn) {
                          // Wenn Lampe an sein soll: Zuerst (optional) dimmen, dann einschalten
                          if (targetBri !== undefined && light.briId) {
                              const currentBri = getState(light.briId).val;
                              if (currentBri !== targetBri) setState(light.briId, targetBri, false);
                          }
                          if (!currentOn) setState(light.powerId, true, false);
                      } else {
                          // Wenn Lampe aus sein soll
                          if (currentOn) setState(light.powerId, false, false);
                      }
                  }
              }, randomDelayMs);
          }
          
          // === INIT & CRONJOB ===
          createState(DP_STORAGE, JSON.stringify({}), { type: 'string', name: 'Snapshot Datenbank (JSON)', role: 'json' }, () => {
              
              schedule("*/15 * * * *", () => {
                  const isPresent = getSafeBoolean(DP_PRESENCE, true);
                  const currentSlot = getSlotIndex(); 
                  
                  let db: SnapshotDatabase = {};
                  try {
                      const raw = getState(DP_STORAGE).val as string;
                      if (raw) db = JSON.parse(raw) as SnapshotDatabase;
                  } catch (e) {
                      log('[Simulation] Fehler beim Lesen der Datenbank, starte mit leerer DB neu.', 'warn');
                  }
          
                  if (isPresent) {
                      const samplingDelayMs = Math.floor(Math.random() * MAX_SAMPLING_DELAY); 
                      log(`[Simulation LERNEN] Block ${currentSlot} ausgelöst. Mache das Foto in ${Math.round(samplingDelayMs/1000)}s...`, 'debug');
                      
                      setTimeout(() => {
                          runLearning(db, currentSlot);
                      }, samplingDelayMs);
          
                  } else {
                      runSimulation(db, currentSlot);
                  }
              });
          
              log('[Simulation] KI-Snapshot-Engine gestartet. (V2: Enums & Helligkeit integriert)');
          });
          
          

          Fazit

          Für mich war wichtig, dass ich mich vor dem Urlaub nicht um die Simulation kümmern muss. Durch den lernenden Charakter ist das System das ganze Jahr über "scharf" und bildet immer den aktuellen Lebensstil ab.

          Ich freue mich auf euer Feedback!

          Edit 18.03.2026: Ich habe hier in Post 1 auch die V2 eingefügt und die Anleitung entsprechend ergänzt. Der Datenpunkt "0_userdata.0.Anwesenheitssimulation_Snapshots" wurde in "0_userdata.0.Simulation.Snapshot_DB" umbenannt.

          NegaleinN Offline
          NegaleinN Offline
          Negalein
          Global Moderator
          schrieb am zuletzt editiert von
          #5

          @mrMuppet sagte in [Vorlage] Anwesenheitssimulation mit dauerhaftem Lernen:

          Ich freue mich auf euer Feedback!

          Hallo

          Ich war so frei und hab dein Script in die Sammlung aufgenommen. :)

          ° Node.js & System Update ---> sudo apt update, iob stop, sudo apt full-upgrade
          ° Node.js Fixer ---> iob nodejs-update
          ° Fixer ---> iob fix

          1 Antwort Letzte Antwort
          1
          • C Chrille1507

            Hallo,
            eine tolle Idee, die gleich mal testen werde.

            Eine kurze Frage, sind

            "0_userdata.0.Anwesenheitssimulation_Snapshots" und "0_userdata.0.Simulation.Snapshot_DB" nicht die gleichen Datenpunkte?

            M Offline
            M Offline
            mrMuppet
            schrieb am zuletzt editiert von mrMuppet
            #6

            @Chrille1507 sagte in [Vorlage] Anwesenheitssimulation mit dauerhaftem Lernen:

            Eine kurze Frage, sind

            "0_userdata.0.Anwesenheitssimulation_Snapshots" und "0_userdata.0.Simulation.Snapshot_DB" nicht die gleichen Datenpunkte?

            Stimmt. Das sollte der gleiche Datenpunkt sein.

            ioBroker auf NUC (Celeron mit Ubuntu-Server)

            Homematic, HMIP, Hue, Unifi, Plex, Nest, Roborock, Google Assistant

            1 Antwort Letzte Antwort
            0
            • M Offline
              M Offline
              mrMuppet
              schrieb am zuletzt editiert von
              #7

              Ich habe in Post 1 auch die V2 eingefügt und die Anleitung entsprechend ergänzt. Der Datenpunkt "0_userdata.0.Anwesenheitssimulation_Snapshots" wurde in "0_userdata.0.Simulation.Snapshot_DB" umbenannt.

              Wer das Skript schon nutzt und updaten möchte: Kopiert euch einfach den neuen Code aus dem ersten Beitrag und löscht den alten Datenpunkt einmal händisch aus euren Objekten. Danach läuft alles wie gewohnt!

              ioBroker auf NUC (Celeron mit Ubuntu-Server)

              Homematic, HMIP, Hue, Unifi, Plex, Nest, Roborock, Google Assistant

              1 Antwort Letzte Antwort
              0
              • E Offline
                E Offline
                emil70
                schrieb am zuletzt editiert von emil70
                #8

                @mrmuppet

                ich bekomme bei deinem script ein

                SyntaxError: Missing initializer in const declaration
                

                Log

                javascript.0
                	2026-03-19 19:24:22.602	info	script.js.common.Anwesenheit.Skript_1: Stopping script
                javascript.0
                	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: at async JavaScript.onObjectChange (/opt/iobroker/node_modules/iobroker.javascript/build/main.js:564:25)
                javascript.0
                	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
                javascript.0
                	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: at JavaScript.prepareScript (/opt/iobroker/node_modules/iobroker.javascript/build/main.js:2096:44)
                javascript.0
                	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: at JavaScript.createVM (/opt/iobroker/node_modules/iobroker.javascript/build/main.js:1829:25)
                javascript.0
                	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: at new Script (node:vm:117:7)
                javascript.0
                	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: SyntaxError: Missing initializer in const declaration
                javascript.0
                	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: ^^^^^^^^^^^
                javascript.0
                	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: const DP_PRESENCE: string = '0_userdata.0.Anwesenheit_Familie.Anwesenheit';
                javascript.0
                	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: compile failed at: script.js.common.Anwesenheit.Skript_1:6
                

                Wenn ich dann

                //const DP_PRESENCE: string = '0_userdata.0.Anwesenheit_Familie.Anwesenheit'; 
                

                kommt

                Log

                	javascript.0
                	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: at async JavaScript.onObjectChange (/opt/iobroker/node_modules/iobroker.javascript/build/main.js:564:25)
                javascript.0
                	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
                javascript.0
                	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: at JavaScript.prepareScript (/opt/iobroker/node_modules/iobroker.javascript/build/main.js:2096:44)
                javascript.0
                	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: at JavaScript.createVM (/opt/iobroker/node_modules/iobroker.javascript/build/main.js:1829:25)
                javascript.0
                	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: at new Script (node:vm:117:7)
                javascript.0
                	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: SyntaxError: Missing initializer in const declaration
                javascript.0
                	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: ^^^^^^^^^^^^^
                javascript.0
                	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: const ENUM_FUNKTION: string = '';
                javascript.0
                	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: compile failed at: script.js.common.Anwesenheit.Skript_1:11
                

                usw

                Woran liegt das? Fehlt da iregndo win Zeichen im Script?

                EdiT: die Fehlermeldung kommt auch, wenn ich dein orginal script nehme

                gruss emil70

                iobroker,pihole,homematic,motioneys,solaranlage laufen auf Proxmox (16 x AMD Ryzen 7 6800H with Radeon Graphics )

                M 1 Antwort Letzte Antwort
                0
                • E emil70

                  @mrmuppet

                  ich bekomme bei deinem script ein

                  SyntaxError: Missing initializer in const declaration
                  

                  Log

                  javascript.0
                  	2026-03-19 19:24:22.602	info	script.js.common.Anwesenheit.Skript_1: Stopping script
                  javascript.0
                  	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: at async JavaScript.onObjectChange (/opt/iobroker/node_modules/iobroker.javascript/build/main.js:564:25)
                  javascript.0
                  	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
                  javascript.0
                  	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: at JavaScript.prepareScript (/opt/iobroker/node_modules/iobroker.javascript/build/main.js:2096:44)
                  javascript.0
                  	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: at JavaScript.createVM (/opt/iobroker/node_modules/iobroker.javascript/build/main.js:1829:25)
                  javascript.0
                  	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: at new Script (node:vm:117:7)
                  javascript.0
                  	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: SyntaxError: Missing initializer in const declaration
                  javascript.0
                  	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: ^^^^^^^^^^^
                  javascript.0
                  	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: const DP_PRESENCE: string = '0_userdata.0.Anwesenheit_Familie.Anwesenheit';
                  javascript.0
                  	2026-03-19 19:24:20.058	error	script.js.common.Anwesenheit.Skript_1: compile failed at: script.js.common.Anwesenheit.Skript_1:6
                  

                  Wenn ich dann

                  //const DP_PRESENCE: string = '0_userdata.0.Anwesenheit_Familie.Anwesenheit'; 
                  

                  kommt

                  Log

                  	javascript.0
                  	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: at async JavaScript.onObjectChange (/opt/iobroker/node_modules/iobroker.javascript/build/main.js:564:25)
                  javascript.0
                  	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
                  javascript.0
                  	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: at JavaScript.prepareScript (/opt/iobroker/node_modules/iobroker.javascript/build/main.js:2096:44)
                  javascript.0
                  	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: at JavaScript.createVM (/opt/iobroker/node_modules/iobroker.javascript/build/main.js:1829:25)
                  javascript.0
                  	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: at new Script (node:vm:117:7)
                  javascript.0
                  	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: SyntaxError: Missing initializer in const declaration
                  javascript.0
                  	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: ^^^^^^^^^^^^^
                  javascript.0
                  	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: const ENUM_FUNKTION: string = '';
                  javascript.0
                  	2026-03-19 19:26:08.872	error	script.js.common.Anwesenheit.Skript_1: compile failed at: script.js.common.Anwesenheit.Skript_1:11
                  

                  usw

                  Woran liegt das? Fehlt da iregndo win Zeichen im Script?

                  EdiT: die Fehlermeldung kommt auch, wenn ich dein orginal script nehme

                  M Offline
                  M Offline
                  mrMuppet
                  schrieb am zuletzt editiert von
                  #9

                  @emil70 Das Problem ist sehr einfach zu beheben: Du hast das Skript als JavaScript angelegt. Es ist aber in TypeScript geschrieben. Einfach noch mal neu anlegen und reinkopieren. Dann klappts!

                  ioBroker auf NUC (Celeron mit Ubuntu-Server)

                  Homematic, HMIP, Hue, Unifi, Plex, Nest, Roborock, Google Assistant

                  1 Antwort Letzte Antwort
                  1
                  • J Online
                    J Online
                    Joel
                    schrieb am zuletzt editiert von
                    #10

                    Wow, super.
                    Ich teste das mal gerade, bin aber nicht so fit, daher die Fragen...

                    3 Sachen für mich, dass ich es auch richtig verstehe:
                    Den DP Anwesenheit muss ich selbst durch einen Trigger setzten (z.B. über ein Mobilephone) oder wird der DP vom skript gesetzt?
                    Der DP Anwesenheitssimulation_Snapshots_DB (JSON-Speicher) habe ich richtig verstanden ist Zustandstyp=jason?
                    Gibt es evtl. eine kleine Anleitung wegen den Enums wie man das macht?

                    Danke und Grüße
                    Joel

                    1 Antwort Letzte Antwort
                    0
                    • J Online
                      J Online
                      Joel
                      schrieb zuletzt editiert von Joel
                      #11

                      Und dann sehe ich auch z.B. das in dem DB Datenpunkt:

                      "95": [
                          {
                            "alias.0.Bad.Deckenlampe_Bad.ON": {
                              "on": true,
                              "bri": 100
                            },
                            "alias.0.Büro.Deckenlampe_Büro.ON": {
                              "on": false
                            },
                            "alias.0.Esszimmer.Deckenlampe_Esszimmer_1.ON": {
                              "on": false
                            },
                            "alias.0.Flur.Hue1_Decke.ON": {
                              "on": true,
                              "bri": 50
                            },
                            "alias.0.Küche.Deckenlampe_Küche.ON": {
                              "on": false
                            },
                            "alias.0.Schlafzimmer.Deckenlampe_Schlafzimmer.ON": {
                              "on": false
                            },
                            "alias.0.Wohnzimmer.Deckenlampe_Wohnzimmer.ON": {
                              "on": false
                            },
                            "alias.0.Wohnzimmer.Ikea_Stehlampe.ON": {
                              "on": false
                            },
                            "hue.0.Hue_Esszimmer_1": {
                              "on": false
                            },
                            "hue.0.Hue_Flur_1": {
                              "on": false
                            },
                            "hue.0.Hue_Küche": {
                              "on": false
                            },
                            "hue.0.Hue_Schlafzimmer": {
                              "on": false
                            },
                            "hue.0.Hue_Wohnzimmer": {
                              "on": false
                            },
                            "hue.0.Hue_go_Wohnzimmer_links": {
                              "on": false
                            },
                            "hue.0.Hue_go_Wohnzimmer_rechts": {
                              "on": false
                            },
                            "hue.0.Ikea_Stehlampe": {
                              "on": false
                            },
                            "hue.0.Hue_Bad": {
                              "on": false
                            },
                            "hue.0.Hue_Büro": {
                              "on": false
                            }
                          }
                        ]
                      }
                      

                      Hier der Teil meiner Konfig:

                      const LIGHTS: string[] = [
                            'alias.0.Bad.Deckenlampe_Bad.ON',        // <-- Trage hier alle Lampen ein, die 
                            'alias.0.Büro.Deckenlampe_Büro.ON',  //     von der Straße aus sichtbar sind.
                            'alias.0.Esszimmer.Deckenlampe_Esszimmer_1.ON',
                            'alias.0.Flur.Hue1_Decke.ON',
                            'alias.0.Küche.Deckenlampe_Küche.ON',
                            'alias.0.Schlafzimmer.Deckenlampe_Schlafzimmer.ON',
                            'alias.0.Wohnzimmer.Deckenlampe_Wohnzimmer.ON',
                            'alias.0.Wohnzimmer.Ikea_Stehlampe.ON'
                      ];
                      

                      Es ist aber so, dass zum Zeitpunkt des Schreibens in den DP das Licht in der Küche und im Esszimmer an war. Dennoch sagen die Daten im DP etwas anderes.
                      Liegt es an einer falschen Konfig von mir?
                      Danke!

                      1 Antwort Letzte Antwort
                      0

                      Hey! Du scheinst an dieser Unterhaltung interessiert zu sein, hast aber noch kein Konto.

                      Hast du es satt, bei jedem Besuch durch die gleichen Beiträge zu scrollen? Wenn du dich für ein Konto anmeldest, kommst du immer genau dorthin zurück, wo du zuvor warst, und kannst dich über neue Antworten benachrichtigen lassen (entweder per E-Mail oder Push-Benachrichtigung). Du kannst auch Lesezeichen speichern und Beiträge positiv bewerten, um anderen Community-Mitgliedern deine Wertschätzung zu zeigen.

                      Mit deinem Input könnte dieser Beitrag noch besser werden 💗

                      Registrieren Anmelden
                      Antworten
                      • In einem neuen Thema antworten
                      Anmelden zum Antworten
                      • Älteste zuerst
                      • Neuste zuerst
                      • Meiste Stimmen


                      Support us

                      ioBroker
                      Community Adapters
                      Donate

                      193

                      Online

                      32.7k

                      Benutzer

                      82.6k

                      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