Ankündigung

Einklappen
Keine Ankündigung bisher.

Grundsatzfrage zum Bau eines eigenen Widgets

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    #16
    Hallo zusammen,

    es ist vollbracht Danke eurer Erläuterungen habe ich es recht kurzer Zeit geschaft mein Widget zu bauen. Das CSS ist sicher noch nicht fertig, aber das kann ich noch machen, nachdem die Funktionalitätt jetzt gegegben ist.

    Ich erläutere hier mal wie ich es umgesetzt habe und würde mich über eine Feedback freuen. Mir ist wichtig, mich nicht zu weit von der Idee der CV zu entfernen, um zukünftige Inkompatibilitäten so klein wie möglich zu halten. Im Anhang findet Ihr die gesamten Dateien.

    Ausschnitt im Config XML zur GA
    Code:
                    <switch_jal mapping="fts_shutter_duoswitch" styling="GreyGrey" format="%.0f %%" align="center" infoPosition="middle" downValue="1">            
                        <layout colspan="12"/>
                        <label>Jalousie-Switch</label>
                        <address transform="DPT:1.008" variant="long">3/2/12</address>
                        <address transform="DPT:1.001" variant="short">3/2/52</address>
                        <address transform="DPT:1.001" variant="state_button0">3/2/172</address>
                        <address transform="DPT:1.001" variant="state_button1">3/2/132</address>
                        <address transform="DPT:5.001" variant="position">3/2/92</address>
                    </switch_jal>
    Auswertung der spezifischen Funktion der GA über den Variant Parameter structure_custom_jal.js
    Code:
            getAddressFunction: function (ga) {
                // Die Funktion der aktuellen GA aus den zum Widget gehörigen
                // Gruppenadressen(property Variant) herausfiltern
                for (var curAddr in this.getAddress()) {
                    if (curAddr === ga) {
                        return this.getAddress()[ga][2];
                        break;
                    }
                }
                return 0;
            },
    Ausschnitt im Config XML zum Mapping, es gibt ein Icon für UP/DOWN jeweils für Button aktiv/inaktiv
    Code:
                <mapping name="fts_shutter_duoswitch">
                    <entry value="0">
                        <icon name="fts_shutter_down" color="white"/>
                    </entry>
                    <entry value="2">
                        <icon name="fts_shutter_up" color="white"/>
                    </entry>
                    <entry value="1">
                        <icon name="fts_shutter_down" color="grey"/>
                    </entry>
                    <entry value="3">
                        <icon name="fts_shutter_up" color="grey"/>
                    </entry>
    Es gibt folgende Darstellungen
    1. ) Der Rolladen steht nicht in den Anschlägen
    shutter-mid.png

    2.) Der Rolladen ist ganz oben
    shutter-up.png

    3.) Der Rolladen ist ganz unten
    shutter-down.png

    Der Zustand der Button wird über die GA "state_button0/1" gesteuert, welche vom BUS die Info bekommen Rolladen ganz unten/oben bekommen. Um mit einem Mapping beide Button zu bespielen, haben ich 4 Icons dort hinterlegt. Um dann beim valueHandling das richtige Icon auf den Button0/1 zu bekommen, wird zu der "data" von der GA "state_button1" ein Offset von 2 addiert (s.u. defaultValueHandling)


    Der Tastendruck wird kurz/lang ausgewertet structure_custom_jal.js


    Code:
    // Aktion die bei langem Tastendruck ausgeführt wird
            _onLongTap: function (event) {
                this.__action(false, qx.bom.element.Class.has(event.getCurrentTarget(), 'actor_jal_down'));
            },
            // Aktion die bei kurzem Tastendruck ausgeführt wird
            _action: function (event) {
                this.__action(true, qx.bom.element.Class.has(event.getCurrentTarget(), 'actor_jal_down'));
            },
            // generische Aktion die in Abhängigkeit der Länge des
            // Tastendrucks auszuführen ist
            __action: function (isShort, isDown) {
                var value;
                if (isShort) {
                    // wenn ein kurzer Tastendruck ausgeführt wird
                    value = isDown ? this.getShortDownValue() : this.getShortUpValue();
                } else {
                    // Wenn ein langer Tastendruck ausgeführt wird
                    var x = this.getDownValue();
                    var y = this.getUpValue();
                    value = isDown ? this.getDownValue() : this.getUpValue();
                }
    
                // Berechnung der Bitmaske für short/long
                var bitMask = (isShort ? 1 : 2);
    
                var list = this.getAddress();
                for (var id in list) {
                    if (list.hasOwnProperty(id)) {
                        var address = list[id];
                        //kurzer Testendruck
                        if ((address[2] === 0) && (isShort)) {
                            this.sendToBackend(value, function (address)
                            {
                                return !!(address[2] === 0);
                            });
                        }
                        //langer Tastendruck
                        if ((address[2] === 1) && (!isShort)) {
                            this.sendToBackend(value, function (address)
                            {
                                return !!(address[2] === 1);
                            });
                        }
                    }
                }
            },

    Für das korrekte Anzeigen mussten 2 Funktionen (s.o.) mit dem Holzhammer überschieben werden.

    Die Magic passiert hier BasicUpdateMW.js

    Code:
            defaultValueHandling: function (address, data) {
    
                // #1: transform the raw value to a JavaScript type
                var value = this.applyTransform(address, data);
    
                // store it to be able to suppress sending of unchanged data
                if (value !== undefined) {
                    this.setBasicValue(value);
                }
    
                // Modifikation der Value um Mapping Icons von Button
                // 1 und 2 unterscheiden zu können
    
                // Funktion der Adresse ermitteln
                var gaFunction = this.getAddressFunction(address);
                if (gaFunction === 3) {
                    // Value um 2 erhöhen, damit andere Bilder genommen werden
                    value += 2;
                }
    
                // #2: map it to a value the user wants to see
                value = this.applyMapping(value);
    
                // #3: format it in a way the user understands the value
                // Formatierung nur bei der Positionsanzeige
                if ((value !== undefined) && (gaFunction === 4)) {
                    value = this.applyFormat(address, value);
                    this.setValue(value);
                }
    
                if (value && value.constructor === Date) {
                    switch (this.getAddress()[address][0]) // special case for KNX
                    {
                        case 'DPT:10.001':
                            value = value.toLocaleTimeString();
                            break;
                        case 'DPT:11.001':
                            value = value.toLocaleDateString();
                            break;
                        case 'OH:datetime':
                            value = value.toLocaleDateString();
                            break;
                        case 'OH:time':
                            value = value.toLocaleTimeString();
                            break;
                    }
                }
    
                this.applyStyling(this.getBasicValue());
                // #4 will happen outside: style the value to be pretty
                return value;
            },
    ....
            defaultUpdate: function (ga, data, passedElement) {
                var element = passedElement || this.getDomElement();
    
                // Funktion der Adresse ermitteln
                var gaFunction = this.getAddressFunction(ga);
                // nur Anzeige Adressen durchlassen
                if (gaFunction < 2) {
                    return data;
                }
                ;
    
                var value = this.defaultValueHandling(ga, data);
    
                // TODO: check if this is the right place for this
                // might be if the styling removes the align class
                if (this.getAlign()) {
                    qx.bom.element.Class.add(element, this.getAlign());
                }
    
                //Das passende Valueelement auswählen
                var valueElement;
                var doUpdate = false;
                switch (gaFunction) {
                    case 2:
                        //Update des Button 1
                        doUpdate = true;
                        //Status Endanschlag des Button 1 abspeichern
                        if (parseInt(data, 16) === 1) {
                            //Endanschlag erreicht keine weisteres Fahren in diese Richtung möglich
                            this.setButtonEndState1(1);
                        } else {
                            this.setButtonEndState1(0);
                        }
                        valueElement = qx.bom.Selector.query('.actor_jal_down > .value', element)[0];
                        break;
                    case 3:
                        //Update des Button 2
                        doUpdate = true;
                        //Status Endanschlag des Button 2 abspeichern
                        if (parseInt(data, 16) === 1) {
                            //Endanschlag erreicht keine weisteres Fahren in diese Richtung möglich
                            this.setButtonEndState2(1);
                        } else {
                            this.setButtonEndState2(0);
                        }
                        valueElement = qx.bom.Selector.query('.actor_jal_up > .value', element)[0];
                        break;
                    case 4:
                        //Positionsvalues
                        valueElement = qx.bom.Selector.query('.actor_jal_pos', element)[0];
                        doUpdate = true;
                        ;
    
                        break;
                    default:
                        //ursprünglicher Code
                        valueElement = this.getValueElement ? this.getValueElement() : qx.bom.Selector.query('.value', element)[0];
                        break;
                }
    
                //Spezialbehandling für den Endanschlag status beider Buttons
                if ((this.getButtonEndState1() === 1) || (this.getButtonEndState2() === 1)) {
                    // die Positionsanzeige wird unterdrückt
                    var posElem = qx.bom.Selector.query('.actor_jal_pos', element)[0];
                    qx.bom.element.Style.setCss(posElem, "float:left; margin: 4px 1px; display: none");
                } else {
                    // die Positionsanzeige wird angezeigt
                    if (gaFunction === 4) {
                        var posElem = qx.bom.Selector.query('.actor_jal_pos', element)[0];
                        qx.bom.element.Style.setCss(posElem, "float:left; margin: 4px 1px; ");
                    }
                }
    
                if (doUpdate) {
                    //Alten Inhalt löschen
                    qx.dom.Element.empty(valueElement);
                    //neuen Inhalt darstellen
                    if (undefined !== value) {
                        this.defaultValue2DOM(value, qx.lang.Function.curry(this._applyValueToDom, valueElement));
                    } else {
                        qx.dom.Element.insertEnd(document.createTextNode('-'), valueElement);
                    }
                }
                return value;
            },
    dazu noch eine neue UpdateMW.js mit folgender mini Änderung (sehr Unschön)

    Code:
    include: cv.ui.common.BasicUpdateMW,
    eingebunden in meine structure_custom_jal.js
    Code:
        include: [
            cv.ui.common.Operate,
            cv.ui.common.UpdateMW,
            cv.ui.common.HasAnimatedButton,
            cv.ui.common.HandleLongpress
        ],
    Wie schon gesagt funktioniert dies bestens, ich bin mir aber unsicher, ob isch irgendwelche größeren Prinzipen der CV missachtet habe.

    Bleibt nur noch die unschönheit der Holzhammer methode.

    Geschickt wäre es wenn man die defaultUpdate() mit einer userUpdate() ersetzen könnte, damit wäre es deutlich einfacher .



    Angehängte Dateien
    Zuletzt geändert von mw2000; 26.01.2019, 15:41. Grund: Dateien angehangen

    Kommentar

    Lädt...
    X