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. Skripten / Logik
  4. JavaScript
  5. [solved] Objekte im Array dynamisch vom Skript aktualisieren

NEWS

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

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

  • Weihnachtsangebot 2025! 🎄
    BluefoxB
    Bluefox
    25
    1
    2.1k

[solved] Objekte im Array dynamisch vom Skript aktualisieren

Geplant Angeheftet Gesperrt Verschoben JavaScript
5 Beiträge 2 Kommentatoren 92 Aufrufe 2 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.
  • W Offline
    W Offline
    WurstDLX
    schrieb am zuletzt editiert von WurstDLX
    #1

    Hallo,

    ich stehe vor einem Problem, bei welchem ich vielleicht nur eine Bestätigung suche.
    Ich habe eine Rolladensteuerung implementiert, bei der der vis-Nutzer zwei Zeiten für eine Automatik editieren kann:
    b53236e3-23ac-458a-8fe3-208c47f16a3a-grafik.png
    Tippt man auf die Kachel, öffnet sich eine view:
    bfe133ac-a9f2-4f8f-bc18-a0640c75a775-grafik.png
    In dieser View kann man erstens je Rollo Hoch- und Runterfahren aktivieren und jeweils die Position bestimmen. Zu allen Informationen habe ich Datenpunkte erstellt (bspw. AutoTiming1_DG für ja/nein Hochfahren, AutoTiming2_DG für Herunterfahren; PositionHoch_DG; PositionRunter_DG...)

    Im Skript habe ich mir das wie folgt überlegt:
    Ich erstelle ein Array mit den Objekten und Eigenschaften jedes Rollos:

    const idAutoModeEnabled='0_userdata.0.Rollo.ShutterAutoTiming';
    const idAutoModeOnce='0_userdata.0.Rollo.ShutterAutoTimingOnce';
    const rollos= [
        {
            enabled1:getState('0_userdata.0.Rollo.AutoTiming1_DG').val,
            enabled2:getState('0_userdata.0.Rollo.AutoTiming2_DG').val,
            posDP:'alias.0.DG_Zimmer.Fenster.RolloPositionSoll',
            position1:getState('0_userdata.0.Rollo.PositionHoch_DG').val,
            position2:getState('0_userdata.0.Rollo.PositionRunter_DG').val,
            wait1_ms:60*1000,
            wait2_ms:60*1000
        },
    

    Ändert sich die Zeit, erstellt er ein schedule mit einem foreach:

    const idTime1 = '0_userdata.0.Rollo.AutoTiming1_time';  // Zeit als String "hh:mm"
    const idTime2 = '0_userdata.0.Rollo.AutoTiming2_time';  // Zeit als String "hh:mm"
    
    on(idTime1, function(dp) {
       var h=getState(idTime1_h).val;
       var min=getState(idTime1_min).val;
       clearSchedule(timer1);
       log('neuer Timer1 gesetzt');
       timer1 = schedule(min + ' ' + h + ' * * *', function() {
           if (getState(idAutoModeEnabled).val)
            {
                rollos.forEach(rollo =>{
                    if(rollo.enabled1){          // für jedes Rollo bestimmbar
                        setState(rollo.posDP,rollo.position1);
                        //log('Rollo '+ rollo.posDP + ' auf '+rollo.position1 + ' bei Zeit ' + idTime1+' gefahren.');
                    }
                });
            }
       });
    });
    // schedule 2
    on(idTime2, function(dp) {
       var h=getState(idTime2_h).val;
       var min=getState(idTime2_min).val;
       clearSchedule(timer2);
       log('neuer Timer2 gesetzt');
       timer2 = schedule(min + ' ' + h + ' * * *', function() {
            if (getState(idAutoModeEnabled).val)
            {
                rollos.forEach(rollo =>{
                    log(rollo.posDP + '='+ rollo.enabled2);
                    var timeout=null;
                    timeout=setTimeout(function(){
                        if (rollo.enabled2){
                            setState(rollo.posDP,rollo.position2);
                            log('Rollo '+ rollo.posDP + ' auf '+rollo.position2 + ' bei Zeit ' + getState(idTime2).val+'('+ rollo.wait2_ms/1000+') gefahren ('+rollo.enabled2+')');
                        }
                    clearTimeout(timeout);
                    timeout=null;
                    },rollo.wait2_ms);
                });
            }
            if (getState(idAutoModeOnce).val)   // reset wenn nur einmalig
            {
                setState(idAutoModeEnabled,false);
                setState(idAutoModeOnce,false);
            }
       });
    });
    
    //#######################  INIT  ################################
    // init first time:
    var h=getState(idTime1_h).val;
    var min=getState(idTime1_min).val;
    clearSchedule(timer1);
    timer1 = schedule(min + ' ' + h + ' * * *', function() {
        if (getState(idAutoModeEnabled).val)
        {rollos.forEach(rollo =>{if(rollo.enabled1){ setState(rollo.posDP,rollo.position1);}});}});
    var h=getState(idTime2_h).val;
    var min=getState(idTime2_min).val;
    clearSchedule(timer2);
    timer2 = schedule(min + ' ' + h + ' * * *', function() {
        if (getState(idAutoModeEnabled).val)
            {rollos.forEach(rollo =>{if (rollo.enabled2){setState(rollo.posDP,rollo.position2); }});}});
    

    Jetzt beschleicht mich das Gefühl, dass er vermutlich das Array nur ein einziges Mal beim Starten des Skripts einliest, oder?
    Denn aktiviere ich nach Starten des Skripts andere Rollos und ändere auch zum "Aktualisieren" die Zeiten kurz (damit er die schedules einliest) verhalten sich die Rollos nicht, wie ich es mir denke.
    Liege ich mit dem Auslesen der Datenpunkte richtig?
    Dann wäre die Konsequenz, dass sobald sich etwas ändert, das Array Neu initialisiert werden muss.
    Oder gäbe es eine elegantere Lösung für solche dynamischen "settings"

    Danke und ein frohes Neues Jahr!

    PS: das timeout habe ich nachträglich implementiert, um zu verhindern, dass alle aktivierten Rollos gleichzeitig starten, sondern es eher aussieht "jemand schließt die Rollos händisch nacheinander". Funktioniert auch alles soweit.

    1 Antwort Letzte Antwort
    0
    • W Offline
      W Offline
      WurstDLX
      schrieb am zuletzt editiert von
      #2

      Jetzt wo ich mir das anschaue, wäre es eventuell von Vorteil, das Array in die "on"s zu packen anstatt "const"?
      Oder ich müsste noch listener auf einen der vielen Datenpunkte packen, damit er bei Änderung jedes Mal den schedule neu erstellt. Und nicht nur auf "time1" und "time2", aber dann habe ich das Problem ja, dass ich in jedem listener das Array definieren muss und somit bei Änderungen alle anfassen muss.

      Gibt es eine Möglichkeit, das Array neu einlesen zu lassen während der runtime, ohne dass ich es in jeder Funktion deklariere?

      1 Antwort Letzte Antwort
      0
      • AsgothianA Offline
        AsgothianA Offline
        Asgothian
        Developer
        schrieb am zuletzt editiert von Asgothian
        #3

        Was genau willst du denn im Array zur Laufzeit ändern ? Du kannst relativ einfach (obwohl das als const definiert ist) ändern, via

        rollos[idx].enabled1 = getState('0_userdata.0.Rollo.AutoTiming1_DG').val;
        rollos[idx].enabled1 = getState('0_userdata.0.Rollo.AutoTiming2_DG').val;
        rollos[idx].position1 = getState('0_userdata.0.Rollo.PositionHoch_DG').val;
        rollos[idx].position2 = getState('0_userdata.0.Rollo.PositionRunter_DG').val;
        

        Das ganze lässt sich noch weiiter 'generalisieren' - dazu müsste ich aber wissen wie die DP's der Rollos wirklich heissen.

        Schlüssel ist dabei:

        • an Stelle eines Array wird ein Objekt genutzt, bei dem ein Teil des DP Namens als 'property Name' benutzt wird. { rollo1: {}, rollo2: {} }
        • zum lesen der Daten machst du dann eine Funktion, der du den 'property namen' und die Rollos mitgibst:
        function readDynamicRolloData(key, room, storage) {
                const robj = storage[key];
                robj.enabled1=getState(`0_userdata.0.${key}.AutoTiming1_DG`).val;
                robj.enabled2=getState(`0_userdata.0.${key}.AutoTiming2_DG`).val;
                robj.position1:getState(`0_userdata.0.${key}.PositionHoch_DG'`.val;
                position2:getState(`0_userdata.0.${key}.PositionRunter_DG`).val;
                return robj;
        }
        

        an stelle vom

        rollos.forEach(rollo ...
        

        kannst du dann mit

        Object.keys(rollos).foreach (key) => {
            const rollo = readDynamicRolloData(key, rollos);
            ....
        

        Der rest der foreach Funktion kann so bleiben wie sie ist.

        A.

        1. Nachtrag: wenn die Alias Struktur entsprechend aufgebaut ist kannst du ggf. dann sogar mit einem einzigen 'on' alles erlegen. Das hier zu beschreiben ist aber dann doch etwas.. langatmig.

        2. Nachtrag: in deinem Rollo-Array hast du 2 Arten von Informationen: Dynamische aus Datenpuntkten und statische (fest im Skript stehende). Warum legst du dafür nicht auch Datenpunkte im userdata Bereich an - neben den dynamischen, so das du da die eigentlichen Werte definieren kannst. Dann ist das Skript mit Ausnahme des key für alle Rollos gleich und du hast im Skript nur die Keys zu definieren die existieren.

        ioBroker auf RPi4 - Hardware soweit wie möglich via Zigbee.
        "Shit don't work" ist keine Fehlermeldung, sondern ein Fluch.

        1 Antwort Letzte Antwort
        0
        • W Offline
          W Offline
          WurstDLX
          schrieb am zuletzt editiert von
          #4

          Danke für deinen Input und die Zeit, mein Problem zu verstehen.
          Mit keys habe ich noch nicht gearbeitet, das werde ich mir mal anschauen und ja, hier soll mir keiner die gesamte Lösung präsentieren, eine Richtung, insbesondere zu generalisieren, ist von großem Vorteil.

          Ich würde jetzt nicht alle DP posten, aber grundsätzlich habe ich jedem Rollo (8x) folgende DP (userdata) zugeordnet:

          • time1 (hochfahren) enabled?
          • time2 (herunterfahren) enabled?
          • ZielpositionHoch (bei time1)
          • ZielpositionRunter (bei time2)

          im Array wie du bereits bemerkt hast, habe ich statische Werte:

          • Verzögerung time1
          • Verzögerung time2
          • Alias DP für die Rolloposition (der lässt das Rollo bewegen)

          Hatte mir gedacht, ich spare mir "statische" Werte als DP anzulegen, könnte ich aber natürlich machen. Ich tue mich immer so schwer mit dem Anlegen von DP (da ich es noch mit Maus mache, sollte mir langsam das per Skript machen aneignen).

          878ebce2-355f-4438-b967-604b433a681e-grafik.png

          Nach "_" kommt immer Zimmername als Abkürzung (DG,AZ,SZ,Kueche,Essen,WZli,WZre,Zimmer).

          Ich merke gerade du wolltest auf die aliase hin: Da habe ich immer die Struktur

          alias.[Zimmername].Fenster.RolloPositionSoll
          

          Okay, Mist eine Ausnahme bildet WZ:

          alias.WZ.Fenster.RolloLinksPositionSoll
          alias.WZ.Fenster.RolloRechtsPositionSoll
          

          Die brauche ich, um die Rollos Befehle zu versenden.

          Das mit dem einem einzigen "on" erledigen habe ich tatsächlich bereits in mehreren Fällen für "Batteriestatus abfragen", "Sind Fenster offen" oder "fahre alle Rollos mit einem Klick hoch" gemacht. Die Erklärung müsste also nicht vollständig sein.

          1 Antwort Letzte Antwort
          0
          • W Offline
            W Offline
            WurstDLX
            schrieb am zuletzt editiert von WurstDLX
            #5

            @asgothian
            Habe es im ersten Schritt so gelöst, dass ich das Array neu einlesen lasse und statisch Werte erstmal im Skript lasse. Dafür habe ich ein Array erstellt für die key-Worte, welche in der gleichen Reihenfolge sein müssen:

            const room=['DG','SZ','AZ','Zimmer','Kueche','Essen','WZli','WZre'];
            const rollos= [
                {
                    posDP:'alias.0.DG_Zimmer.Fenster.RolloPositionSoll',
                    wait1_ms:60*1000,
                    wait2_ms:60*1000
                },
                {
                    posDP:'alias.0.OG_SZ.Fenster.RolloPositionSoll',
                    wait1_ms:40*1000,
                    wait2_ms:40*1000
                },
            ...
            

            Mit der Funktion

            function readArray(key,room,storage){
                const robj =storage[key];
                robj.enabled1=getState(`0_userdata.0.Rollo.AutoTiming1_`+room).val;
                robj.enabled2=getState(`0_userdata.0.Rollo.AutoTiming2_`+room).val;
                robj.position1=getState(`0_userdata.0.Rollo.PositionHoch_`+room).val;
                robj.position2=getState(`0_userdata.0.Rollo.PositionRunter_`+room).val;  
                return robj;
            }
            

            erweitere ich dynamisch das Array mit aktuellen Werten. Mit den SetTimer Funktionen

            function setTimer1(){
                var h=getState(idTime1_h).val;
                var min=getState(idTime1_min).val;
                clearSchedule(timer1);
                log('neuer Timer1 gesetzt');
                timer1 = schedule(min + ' ' + h + ' * * *', function() {
                    if (getState(idAutoModeEnabled).val)
                    {
                        Object.keys(room).forEach (id =>
                        {
                            const rollo = readArray(id,room[id],rollos);
                            var timeout1=null;
                            timeout1=setTimeout(function()
                            {
                                if(rollo.enabled1)
                                {   // für jedes Rollo bestimmbar
                                    setState(rollo.posDP,rollo.position1);
                                    //log('Rollo '+ rollo.posDP + ' auf '+rollo.position1 + ' bei Zeit ' + idTime1+' gefahren.');
                                }
                            clearTimeout(timeout1);
                            timeout1=null;
                            },rollo.wait1_ms);
                        });
                    }
               });
            }
            

            und dem Listener auf alles was im Ordner "Rollo" ist:

            $('state[id=0_userdata*Rollo*]').on(function(obj){
                //log('sth changed');
                setTimer1();
                setTimer2();
            });
            

            werden die Timer bei jeder Änderung neu erstellt. Noch nicht ganz schön sauber, aber es klappt. Erster Funktionstest steht aus. Die Grundfrage aber, ob ein Array mit DP als Objekte dynamisch angepasst werden kann, ist gelöst.

            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

            532

            Online

            32.6k

            Benutzer

            82.1k

            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