1+ /********************************************************************************
2+ * Script: Astro Szenen Steuerung
3+ * Description: Steuert Smart Home Szenen (Tag, Nacht, Aus) basierend auf
4+ * dem Astro-Status und der aktuellen Uhrzeit.
5+ * Version: 1.0.0
6+ * Author: Sanweb
7+ * Datum: 2026-03-09
8+ * * Changelog:
9+ * 1.1.1 - Eindeutiger Log-Prefix hinzugefügt für bessere Übersicht im ioBroker-Log.
10+ * 1.1.0 - Konfiguration in ein zentrales CONFIG-Objekt ausgelagert (Refactoring).
11+ * 1.0.0 - Initiale Version (Portierung aus Node-RED)
12+ * inkl. RBE (Report By Exception) und robuster Fehlerprüfung.
13+ ********************************************************************************/
14+
15+ ( function ( ) {
16+ "use strict" ;
17+
18+ // ==========================================
19+ // Konfiguration
20+ // ==========================================
21+ const CONFIG = {
22+ LOG_PREFIX : "[Astro-Szenen] " , // Eindeutige Bezeichnung für das Logbuch
23+ ASTRO_ID : "0_userdata.0.System.Astro.TagNacht" ,
24+ SCENES : {
25+ TAG : "scene.0.Automatisches Licht.Astro_Tag" ,
26+ NACHT : "scene.0.Automatisches Licht.Astro_Nacht" ,
27+ AUS : "scene.0.Automatisches Licht.Astro_Aus"
28+ } ,
29+ TIMES : {
30+ NIGHT_OFF : "22:30" , // Ende Abendlicht
31+ EARLIEST_START : 12 // Früheste Stunde für Abendlicht
32+ }
33+ } ;
34+
35+ // ==========================================
36+ // Initialisierung & RBE (Report By Exception)
37+ // ==========================================
38+ let lastScene = "none" ;
39+
40+ // Verbesserte Initialisierung mit Priorität
41+ function initializeLastScene ( ) {
42+ if ( existsState ( CONFIG . SCENES . TAG ) && getState ( CONFIG . SCENES . TAG ) . val ) {
43+ lastScene = "Tag" ;
44+ } else if ( existsState ( CONFIG . SCENES . NACHT ) && getState ( CONFIG . SCENES . NACHT ) . val ) {
45+ lastScene = "Nacht" ;
46+ } else if ( existsState ( CONFIG . SCENES . AUS ) && getState ( CONFIG . SCENES . AUS ) . val ) {
47+ lastScene = "Alles Aus" ;
48+ } else {
49+ lastScene = "none" ;
50+ }
51+ log ( `${ CONFIG . LOG_PREFIX } Initialisiert: lastScene = ${ lastScene } ` , "debug" ) ;
52+ }
53+
54+ // Dann aufrufen:
55+ initializeLastScene ( ) ;
56+
57+ // ==========================================
58+ // Hauptlogik
59+ // ==========================================
60+ function checkAstroScene ( ) {
61+ // Input lesen und auf Existenz prüfen
62+ if ( ! existsState ( CONFIG . ASTRO_ID ) ) {
63+ log ( `${ CONFIG . LOG_PREFIX } Astro-Datenpunkt existiert nicht: ${ CONFIG . ASTRO_ID } ` , "warn" ) ;
64+ return ;
65+ }
66+
67+ const astroState = getState ( CONFIG . ASTRO_ID ) ;
68+ if ( ! astroState || astroState . val === null ) {
69+ log ( `${ CONFIG . LOG_PREFIX } Konnte Astro-Status nicht lesen oder Status ist null` , "warn" ) ;
70+ return ;
71+ }
72+
73+ // Typensicherheit: Explizit als String behandeln
74+ const astroStatus = String ( astroState . val ) ;
75+
76+ // Aktuelle Zeit ermitteln
77+ const now = new Date ( ) ;
78+ const currentHours = now . getHours ( ) ;
79+ const currentMinutes = now . getMinutes ( ) ;
80+ const currentTimeVal = currentHours * 60 + currentMinutes ;
81+
82+ // Endzeit in Minuten umrechnen
83+ const [ endH , endM ] = CONFIG . TIMES . NIGHT_OFF . split ( ':' ) . map ( Number ) ;
84+ const endTimeVal = endH * 60 + endM ;
85+ const startTimeVal = CONFIG . TIMES . EARLIEST_START * 60 ;
86+
87+ // Variablen für die 3 Ausgänge (Standard: false)
88+ let valTag = false ;
89+ let valNacht = false ;
90+ let valAus = false ;
91+ let currentSceneName = "" ;
92+
93+ // --- LOGIK ---
94+ if ( astroStatus === "Tag" ) {
95+ // Es ist Tag -> Szene Tag aktivieren
96+ valTag = true ;
97+ currentSceneName = "Tag" ;
98+
99+ } else if ( astroStatus === "Nacht" ) {
100+ // Es ist Nacht -> Prüfen ob vor oder nach 22:30
101+ if ( currentTimeVal >= startTimeVal && currentTimeVal < endTimeVal ) {
102+ // Abend (Dunkel & vor 22:30) -> Szene Nacht aktivieren
103+ valNacht = true ;
104+ currentSceneName = "Nacht" ;
105+ } else {
106+ // Spät (Dunkel & nach 22:30 oder morgens vor 12) -> Szene Aus aktivieren
107+ valAus = true ;
108+ currentSceneName = "Alles Aus" ;
109+ }
110+ } else {
111+ log ( `${ CONFIG . LOG_PREFIX } Unbekannter Astro Status: ${ astroStatus } ` , "warn" ) ;
112+ return ; // Abbruch, wenn der Status ungültig ist
113+ }
114+
115+ // Debug-Logging für bessere Fehlersuche
116+ log ( `${ CONFIG . LOG_PREFIX } Prüfung: Astro=${ astroStatus } , Zeit=${ currentHours } :${ currentMinutes } , Aktuelle Szene=${ currentSceneName } , Letzte Szene=${ lastScene } ` , "debug" ) ;
117+
118+ // --- RBE (Report By Exception) ---
119+ // Wir senden nur Befehle, wenn sich die aktive Szene ändert
120+ if ( currentSceneName !== lastScene ) {
121+ lastScene = currentSceneName ;
122+ log ( `${ CONFIG . LOG_PREFIX } Status-Änderung erkannt: Aktiviere Szene -> ${ currentSceneName } ` ) ;
123+
124+ // Ausgänge schalten (ack: false explizit gesetzt für Steuerbefehle)
125+ setState ( CONFIG . SCENES . TAG , valTag , false ) ;
126+ setState ( CONFIG . SCENES . NACHT , valNacht , false ) ;
127+ setState ( CONFIG . SCENES . AUS , valAus , false ) ;
128+ }
129+ }
130+
131+ // ==========================================
132+ // Trigger
133+ // ==========================================
134+
135+ // 1. Trigger: Bei jeder Änderung des Astro-Datenpunkts (entspricht "ioBroker in" Node)
136+ on ( { id : CONFIG . ASTRO_ID , change : "ne" } , function ( obj ) {
137+ checkAstroScene ( ) ;
138+ } ) ;
139+
140+ // 2. Trigger: Zeitplan alle 5 Minuten (entspricht "inject" Node mit repeat: 300)
141+ // Dieser Intervall-Check stellt sicher, dass zeitbasierte Wechsel (z.B. um 22:30 Uhr)
142+ // zuverlässig ausgelöst werden, auch wenn der Astro-Status ("Nacht") sich nicht ändert.
143+ schedule ( "*/5 * * * *" , function ( ) {
144+ checkAstroScene ( ) ;
145+ } ) ;
146+
147+ // 3. Beim Starten des Skripts einmalig prüfen (entspricht fireOnStart)
148+ checkAstroScene ( ) ;
149+
150+ } ) ( ) ;
0 commit comments