Astro

ioBroker Astro-Tageszeit abfragen und in Datenpunkt eintragen

Artikel wurde zuletzt am 05.06.2020 um 19:26 Uhr aktualisiert

In ioBroker kannst Du mit den Astro Funktionen eine ganze Menge abfragen. Aber jede Astrozeit immer in jedem Skript abzufragen ist lästig, oder? Richtig! Mit diesem Skript kannst du global alle Werte der Astro Funktion abfragen und in passenden Datenpunkten abspeichern. Das Skript erstellt beim ersten Aufruf automatisch die benötigten Datenpunkte und sollte im common Bereich erstellt werden. Der Aufruf des Skripts geschieht alle 30 Minuten automatisch und kann in der letzten Zeile angepasst werden.
Hier kann es natürlich vorkommen, das die ein oder andere Tageszeit übersprungen wir, da sie nur 2-5 Minuten (gerade im Sommer: Sonnenauf- und untergang innerhalb von 5 Minuten) auseinander liegen. Zusätzlich gibt es 6 Variablen, die den aktuellen Astro – Zustand anzeigen (tageszeitAstro, naechsteTageszeitAstro, tageszeitLesbar, naechsteTageszeitLesbar, aktuelleAstroZeit, Tag). Die Variable Tag steht zwischen Sonnenauf- und untergang auf Tag.

Extra: Bei jedem Durchlauf des Skriptes wird überprüft, ob die eingetragene Uhrzeit bereits vergangen ist. Wenn ja, wird hier schon der Wert für die nächste Zeit dieses Ereignisses gespeichert. Auch bekommst du im Log immer eine Übersicht, wie der aktuelle Durchlauf des Skriptes abgelaufen ist.

Screenshot der verfügbaren Variablen

Screenshot der verfügbaren Variablen
Screenshot der verfügbaren Variablen

Ausgabe im Log

Log-Ausgabe
Log-Ausgabe

Skript

// Astro Zeiten erstellen
// Datenpunkte neu erstellen
var ueberschreiben = false;

// Hauptdatenpunkt unterhalb javascript
var datenpunkt = "Astro.";

// Lesbare Zeiten
const lesbare_zeiten = ["Früher Morgen","Frühe Dämmerung","Morgendämmerung","Sonnenaufgang","Vormittag","später Vormittag","Mittag",
                    "früher Abend","Abend","Sonnenuntergang","Abenddämmerung","später Abend","Nacht","Mitternacht"];

// Objekte der Astro Zeiten
const objekt = ["nightEnd","nauticalDawn","dawn","sunrise","sunriseEnd","goldenHourEnd","solarNoon","goldenHour",
            "sunsetStart","sunset","dusk","nauticalDusk","night","nadir","tageszeitAstro","naechsteTageszeitAstro",
            "tageszeitLesbar","naechsteTageszeitLesbar","aktuelleAstroZeit","Tag"];

// Zustände der Astro-Zeiten
const beschreibung = ["00 - Ende der Nacht","01 - nautische Morgendämmerung","02 - Morgendämmerung","03 - Sonnenaufgang",
            "04 - Ende des Sonnenaufgangs","05 - Ende der goldenen Stunde VM","06 - Mittag", "07 - goldene Abendstunde",
            "08 - Start des Sonnenuntergangs","09 - Sonnenuntergang","10 - Dämmerung Abends","11 - nautische Dämmerung abends",
            "12 - Start der Nacht","13 - Mitternacht","Aktuelle Tageszeit (Astro)","Nächste Tageszeit (Astro)", 
            "Aktuelle Tageszeit (lesbar)","Nächste Tageszeit (lesbar)","aktuelle Astrozeit","Solange die Sonne scheint, ist Tag"];

// Erstelle die benötigten Datenpunkte
function datenpunkte_erstellen() {
    for(var i = 0; i < objekt.length; i++) {
        createState(datenpunkt+objekt[i], "", ueberschreiben, {
        name: beschreibung[i],
        desc: beschreibung[i],
        type: "string",
        role: "value",
        unit: ""
        });
    }
    log("Astro: Datenpunkte erstellt!");
}

// Datenpunkte mit erstem Inhalt füllen
function datenpunkte_fuellen() {
    for (var i = 0; i < objekt.length-6; i++) {
        var datum = new Date();
        var astro_zeit = zeit_formatieren(getAstroDate(objekt[i], datum));
        if (astro_zeit=="Invalid Date") {
            astro_zeit = "00:00";
        }
        setState(datenpunkt+objekt[i], astro_zeit);
    }
    log("Astro: Erste Datenpunkte gefüllt!");
}

// Haupt-Skript
function update_astro_zeiten() {
    var datum = new Date();
    var uhrzeit = zeit_formatieren(datum);

    // Zustand der Daten
    var aktuell = 0;
    var aktualisiert = 0;
    var keine_aktualisierung = 0;
    var astro_index = 0;

    // Aktuellen Tagesabschnitt bestimmen
    var ergebnis = -1;
    var naechste_element = false;

    // Aktuelle & kommende Tageszeit
    var aktuelle_tageszeit = 0;
    var kommende_tageszeit = 0;

    // Tag
    var astroTag = "Nacht";
    
    for (var i = 0; i < objekt.length-6; i++) {
        // Temporäre Zahl
        var tmp_ergebnis = 0;

        // Hole Uhrzeit aus aktuellem Datenpunkt
        var dp_zeit = getState(datenpunkt+objekt[i]).val;
        
        // Hole Index aktuelle Tageszeit
        var tmp_time_uhr = Date.parse('1970-01-01 '+uhrzeit+':00');
        var tmp_time_dp = Date.parse('1970-01-01 '+dp_zeit+':00');
        
        // Aktuelle Zeit ist kleiner als DP
        if (tmp_time_uhr<tmp_time_dp) {
            tmp_ergebnis = tmp_time_dp-tmp_time_uhr;
            if (tmp_ergebnis<=ergebnis || ergebnis==-1) {
                ergebnis = tmp_ergebnis;
                astro_index = i;
                naechste_element = true;
            }
        // Aktuelle Zeit ist größer als DP
        } else {
            tmp_ergebnis = tmp_time_uhr-tmp_time_dp;
            if (tmp_ergebnis<=ergebnis || ergebnis==-1) {
                ergebnis = tmp_ergebnis;
                astro_index = i;
                naechste_element = false;
            }
        }
        // Datenpunkt ist kleiner als aktuelle Uhrzeit. Update!
        if (dp_zeit<uhrzeit) {
            // Neue Astro-Zeit für den nächsten Tag generieren
            var morgen = new Date();
            morgen.setDate(morgen.getDate() + 1);
            var astro_zeit = zeit_formatieren(getAstroDate(objekt[i], morgen));
            // Datenpunkt und Astro Zeit sind gleich. Kein Update!
            if (dp_zeit==astro_zeit) {
                keine_aktualisierung++;
            } else {
                if (astro_zeit=="Invalid Date") {
                    astro_zeit = "00:00";
                }                
                setState(datenpunkt+objekt[i], astro_zeit);
                aktualisiert++;
            }
        } else {
            // Zeit kommt noch! Kein Update!
            aktuell++;
        }
    }
    // Wenn wahr, ist der Abstand zum nächsten Zeitpunkt kleiner. Also -1 um aktuellen Index zu erhalten.
    if (naechste_element) {
        astro_index--;
    }
    
    // Navigiere zum richtigen Index
    if (astro_index>12) {
        aktuelle_tageszeit = 13;
        kommende_tageszeit = 0;
    } else if (astro_index<0) {
        aktuelle_tageszeit = 0;
        kommende_tageszeit = 1;
    }else {
        aktuelle_tageszeit = astro_index;
        kommende_tageszeit = astro_index+1;
    }

    // Prüfe, ob aktuelle Uhrzeit zwischen Sonnenauf- und untergang liegt
    if (astro_index>2 && astro_index<10) {
        astroTag = "Tag";
    }

    // Update aktuelle Tageszeit Astro (Text)
    setState(datenpunkt+objekt[14],text_formatieren(beschreibung[aktuelle_tageszeit]));
    
    // Update kommende Tageszeit Astro (Text)
    setState(datenpunkt+objekt[15],text_formatieren(beschreibung[kommende_tageszeit]));

    // Update aktuelle Tageszeit lesbar (Text)
    setState(datenpunkt+objekt[16],lesbare_zeiten[aktuelle_tageszeit]);

    // Update kommende Tageszeit lesbar (Text)
    setState(datenpunkt+objekt[17],lesbare_zeiten[kommende_tageszeit]);

    // Update aktuelle AstroZeit
    setState(datenpunkt+objekt[18],objekt[aktuelle_tageszeit]);

    // Setze die Variable "Tag" auf "Tag", wenn Uhrzeit zwischen Sonnenauf- und untergang
    setState(datenpunkt+objekt[19],astroTag);
        
    var ausgabe = "Astro: Gültige Zeiten: [aktueller Tag: "+aktuell+"] | [nächster Tag: " +keine_aktualisierung+"] | [Aktualisiert: "+ aktualisiert+
                "] | Aktuelle Tageszeit: "+lesbare_zeiten[aktuelle_tageszeit]+" | Kommende Tageszeit: "+lesbare_zeiten[kommende_tageszeit];
    log (ausgabe);
}

// Funktion, um die Zeit in HH:MM zu formatieren
function zeit_formatieren(zeit) {
    return zeit.toLocaleTimeString('de-DE',{ hour12: false, hour:'2-digit', minute:'2-digit' });
}

// Funktion, um den Text zu formatieren. "Mittag" statt "6 - Mittag"
function text_formatieren(text) {
    text = text.split("-")[1];
    text = text.substr(1, text.length);
    return text;
}

// Erster Start des Skripts und anlegen der Datenpunkte
function update_astro_zeiten_erster_start() {
    log ("Astro: Erster Start des Skriptes!")
    // Datenpunkte werden erstellt
    datenpunkte_erstellen();

    // erstes Füllen der Datenpunkte um 3 Sek. verzögert
    setTimeout(datenpunkte_fuellen,3000);

    // Das Update der Zeiten ist um 5 Sek. verzögert
    setTimeout(update_astro_zeiten,5000);
}

// Erster Start und Initialisierung
update_astro_zeiten_erster_start();

// Alle 60 Minunten das Hauptskript ausführen
schedule('*/30 * * * *', update_astro_zeiten);

Einbindung in VIS

Um nun die aktuelle Tageszeit in VIS anzeigen zu können, kannst Du einfach ein String Widget auf deine View ziehen und den Datenpunkt verknüpfen.

String Widget
String Widget auf der View platzieren

Folgender Datenpunkt wird dem String zugewiesen:

javascript.0.Astro.tageszeitLesbar
Datenpunkt der Tageszeit

8 Gedanken zu „ioBroker Astro-Tageszeit abfragen und in Datenpunkt eintragen

  1. EA

    Hallo,

    erstmal vielen Dank für diese Library, war ich gewohnt von openhab und etwas erstaunt, dass es das in iobroker nicht von Haus aus gibt.

    Habe aber ( wahrscheinlich ) einen kleinen Fehler gefunden:
    In Zeile 102,103,104 benutzt du eine
    1) nicht initialisierte Variable morgen ( ist ja nicht soooo schlimm 😉 )
    2) morgen als Number Objekt obwohl es ein Datum ist

    bin mir nicht sicher, wie du dir das gedacht hast, wollte nur darauf hinweisen

    grüße

    Antworten
    1. Stephan Beitragsautor

      Hallo Edgar,
      danke für Deinen Kommentar. Ich habe die Variable nun initialisiert. War wohl ein Flüchtigkeitsfehler 😉
      Dem Objekt wird eine 1 addiert, da ein Tag hinzugefügt wird.
      Zusätzlich habe ich eine Fehlerkontrolle in Zeile 43 und 111 eingebaut, weil ab und an kein “night” oder “nightEnd” per Astro gefunden werden kann.

      Antworten
  2. EA

    Hallo Stephan,

    danke schon mal für die Erklärung und den “Fix” 😉

    Hast du Dein Script auf github?

    Ich denke, da könnte man durchaus noch Sachen hinzufügen.

    Mein erster Gedanke ist, eine “Kompromierte” Tageszeit einzubauen mit weniger verschiedenen Werten, da man für eine Lichtsteuerung nicht so granular sein muß.

    Falls es dich interessiert, gib Bescheid, ich baue es schon mal bei mir ein.

    grüße

    Antworten
      1. EA

        Ja, das habe ich auch schon gemacht.

        Aber für z.b. Flur und Bad haben viele mehrere Stufen des Lichts.

        also abends bis 22 Uhr zum Beispiel 80% und ab 22Uhr zb. 40% Helligkeit.

        Damit man auf dem Weg in Klo nicht gegen Wände läuft aber auch nicht gleich wach wird vom Licht. 😉

        Eigentlich ist es auch nur eine weitere Variable im Sinne von:

        // komprimierte Werte für Tageszeit, um Beleuchtung zu steuern
        // “sinnvolle” Werte : Nacht, Morgen, Tag, Abend, später Abend
        const komprimierte_zeiten = [“Nacht”,”Nacht”,”Morgen”,”Morgen”,”Tag”,”Tag”,”Tag”,
        “Tag”,”Abend”,”Abend”,”Abend”,”später Abend”,”Nacht”,”Nacht”];

        und

        setState(datenpunkt+objekt[20],komprimierte_zeiten[aktuelle_tageszeit]);

        Dann ist der switch in den Scripten nicht so lange.

        grüße

        Antworten
        1. Stephan Beitragsautor

          Hier geht es ja primär um die Beschreibung der Datenpunkte anhand der Astrozeiten. Das Skript kann ja jeder so erweitern, wie er es benötigt. Da die Benutzer bei der Helligkeit des Lichts unterschiedliche Vorlieben haben, sind fast alle meine Skripte “allgemein” gehalten und dienen als Grundlage bzw. Starthilfe 😉

          Antworten
  3. EA

    Noch ein Nachtrag,

    ich habe das neue Script kopiert und habe dabei eine Fehlermeldung gefunden die vielleicht schon vorher da war.

    4:30:29.096 error javascript.0 (6173) at zeit_formatieren (script.js.common.astro3:178:17)
    14:30:29.097 error javascript.0 (6173) at Object.datenpunkte_fuellen (script.js.common.astro3:46:26)

    hier schimpft der JS Adapter dass datum KEINE Number ist, was ja auch stimmt.

    var datum = new Date();
    var astro_zeit = zeit_formatieren(getAstroDate(objekt[i], datum));

    ich finde leider die getAstroDate Funktion gerade nicht, vielleicht kannst du schneller was damit anfangen.

    grüße

    Antworten
    1. Stephan Beitragsautor

      Hallo Edgar,
      der Adapter meldet bei mir keinen Fehler, konvertiert aber trotzdem brav die Variable 😉
      Ich denke, dies ist nur eine Warnung.

      Antworten

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.