Hauptmenü

Raum-Klimamesser

Begonnen von dt2510, 10 Oktober 2019, 18:12:42

Vorheriges Thema - Nächstes Thema

yersinia

Man könnte warten, bis das SVG komplett geladen ist, aber wie man das dann ins Widget sinnvoll einbaut...derzeit keine Idee. Den Nachteil eines integrierten SVGs sehe ich in der fehlenden Möglichkeit, diese zu adaptieren oder zu verändern. Der Benutzer kann quasi keine Farben anpassen - andererseits: wie hoch ist der Bedarf?

MMn könnte man die id weglassen und stattdessen UIDs nutzen. Bruchbude hatte mal was gebastelt, dass man anstelle einer Benutzerdefinierten id nutzen könnte:
var getUniqueID = (function() {
var staticVar = 0;
return function() {
return (++staticVar).toString();
}
})();

//in der init function dann:
elem.initData('uID', getUniqueID());

//und im weiteren code dann zu verwenden via
elem.data('uID')


Sieht aber schon gut aus, wir nähern uns einer brauchbaren Version. Cool. Mehr Tester wären jetzt noch wünschenswert. :)
viele Grüße, yersinia
----
FHEM 6.3 (SVN) on RPi 4B with RasPi OS Bullseye (perl 5.32.1) | FTUI
nanoCUL->2x868(1x ser2net)@tsculfw, 1x433@Sduino | MQTT2 | Tasmota | ESPEasy
VCCU->14xSEC-SCo, 7xCC-RT-DN, 5xLC-Bl1PBU-FM, 3xTC-IT-WM-W-EU, 1xPB-2-WM55, 1xLC-Sw1PBU-FM, 1xES-PMSw1-Pl

frank

im logproxy wiki findet man auch eine schöne 2D darstellung für behagliches raumklima.

siehe unten => Daten aus x,y-Koordinatenpaaren plotten
https://wiki.fhem.de/wiki/LogProxy
FHEM: 6.0(SVN) => Pi3(buster)
IO: CUL433|CUL868|HMLAN|HMUSB2|HMUART
CUL_HM: CC-TC|CC-VD|SEC-SD|SEC-SC|SEC-RHS|Sw1PBU-FM|Sw1-FM|Dim1TPBU-FM|Dim1T-FM|ES-PMSw1-Pl
IT: ITZ500|ITT1500|ITR1500|GRR3500
WebUI [HMdeviceTools.js (hm.js)]: https://forum.fhem.de/index.php/topic,106959.0.html

Waldmensch

Zitatfehlenden Möglichkeit, diese zu adaptieren oder zu verändern. Der Benutzer kann quasi keine Farben anpassen - andererseits: wie hoch ist der Bedarf?

Man könnte die Farben auch übers widget setzen. Muss halt alles nur im init() eingebaut werden und dann ans SVG passend übergeben werden. Das nutzt ja auch Hexfarben. Letztlich sind es ja maximal 6 Farben (Rand, Hintergrund, Skalen, Zeiger, Schrift). Das ist nur Fleißarbeit. Jetzt wo wir vollen Zugriff auf die SVG Instanz haben ist es easy Atribute da drin (um-)zu switchen

Waldmensch

#33
Hier noch eine Version mit definierbaren Farben und ein Beispiel aus Ingolstadt ;)

Alle verfügbaren Parameter stehen ganz oben im Code

widget_hygrometer.js
var Modul_hygrometer = function () {

    /* parameters
        data-get-temperature = "<Device>:<Reading>"
        data-get-humidity = "<Device>:<Reading>"
        data-svg-id = "<unique id>"
        data-size = "500"
        data-show-devpoint = "0|1"
        data-pointer-speed = "20" // as higher as slower
        data-color-outerborder = "#000000"
        data-color-innerborder = "#000000"
        data-color-background = "#000000"
        data-color-scale = "#000000"
        data-color-pointer = "#000000"
    */

    var svgobj;

    // raw values, needed for deviationpoint calculation
    var temperature, humidity;

    // values with included offsets to move the pointers
    var oldTemp = 92, newTemp = 0;
    var oldHum = 268, newHum = 0;

    var pointerspeed = 20;

    var svgimage = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="200 200 1000 1000" id="{{hygrosvg}}">

<!-- Border -->
<circle cx="500" cy="500" r="265" fill="WhiteSmoke" stroke="#bfc1c2" stroke-width="16" id="border_outer"/>
<circle cx="500" cy="500" r="265"  stroke="#d8d8d8" stroke-width="4" id="border_inner"/>
<g stroke="black" stroke-width="2" fill="none"></g>

<!--<path fill="none" stroke="#2e8b57" stroke-width="20" d="M413,331 A190,190 35 0 1 657,393" />-->

<defs>
<!-- Pointer template Temperature -->
<g id="PO1">
<line stroke-width="2" x1="650" y1="600" x2="650" y2="990" fill="orangered" id="PO1_line" />
<rect x="642" y="555" rx="2" ry="2" width="16" height="64" fill="orangered" id="PO1_rect"/>
<circle cx="650" cy="600" r="2" stroke="brown" stroke-width="4" />
<circle cx="650" cy="600" r="3" fill="grey" />
</g>

<!-- Pointer template Humidity -->
<g id="PO2">
<line stroke-width="2" x1="350" y1="600" x2="350" y2="990" fill="orangered" id="PO2_line"/>
<rect x="342" y="555" rx="2" ry="2" width="16" height="64" fill="orangered" id="PO2_rect"/>
<circle cx="350" cy="600" r="2" stroke="brown" stroke-width="4" />
<circle cx="350" cy="600" r="3" fill="grey" />
</g>

<!-- scale templates -->
<line stroke-width="1" id="M1" x1="650" y1="950" x2="650" y2="970" />
<line stroke-width="2" id="L1" x1="650" y1="950" x2="650" y2="980" />
<line stroke-width="1" id="MM1" x1="650" y1="950" x2="650" y2="975" />

<g id="Z1">
<use xlink:href="#M1" transform="rotate(0,650,600)" />
<use xlink:href="#M1" transform="rotate(1.5,650,600)" />
</g>

<line stroke-width="1" id="M2" x1="350" y1="950" x2="350" y2="970" />
<line stroke-width="2" id="L2" x1="350" y1="950" x2="350" y2="980" />

<g id="Z2">
<use xlink:href="#M2" transform="rotate(0,350,600)" />
<use xlink:href="#M2" transform="rotate(2,350,600)" />
</g>

<!-- 4 stripes templates -->
<line stroke-width="1" id="line1" x1="650" y1="730" x2="650" y2="920" />
<line stroke-width="1" id="line2" x1="650" y1="720" x2="650" y2="920" />
<line stroke-width="1" id="line3" x1="350" y1="720" x2="350" y2="920" />
<line stroke-width="1" id="line4" x1="350" y1="760" x2="350" y2="920" />

</defs>

<!-- Temperature scale -->
<g id="T1" stroke="black">
<use xlink:href="#Z1" transform="rotate(92,650,600)" />
<use xlink:href="#L1" transform="rotate(92,650,600)" />
<use xlink:href="#Z1" transform="rotate(95,650,600)" />
<use xlink:href="#Z1" transform="rotate(98,650,600)" />
<use xlink:href="#MM1" transform="rotate(99.5,650,600)" />
<use xlink:href="#Z1" transform="rotate(101,650,600)" />
<use xlink:href="#Z1" transform="rotate(104,650,600)" />
<use xlink:href="#Z1" transform="rotate(107,650,600)" />
<use xlink:href="#L1" transform="rotate(107,650,600)" />
<use xlink:href="#Z1" transform="rotate(110,650,600)" />
<use xlink:href="#Z1" transform="rotate(113,650,600)" />
<use xlink:href="#MM1" transform="rotate(114.5,650,600)" />
<use xlink:href="#Z1" transform="rotate(116,650,600)" />
<use xlink:href="#Z1" transform="rotate(119,650,600)" />
<use xlink:href="#Z1" transform="rotate(122,650,600)" />
<use xlink:href="#L1" transform="rotate(122,650,600)" />
<use xlink:href="#Z1" transform="rotate(125,650,600)" />
<use xlink:href="#Z1" transform="rotate(128,650,600)" />
<use xlink:href="#MM1" transform="rotate(129.5,650,600)" />
<use xlink:href="#Z1" transform="rotate(131,650,600)" />
<use xlink:href="#Z1" transform="rotate(134,650,600)" />
<use xlink:href="#Z1" transform="rotate(137,650,600)" />
<use xlink:href="#L1" transform="rotate(137,650,600)" />
<use xlink:href="#Z1" transform="rotate(140,650,600)" />
<use xlink:href="#Z1" transform="rotate(143,650,600)" />
<use xlink:href="#MM1" transform="rotate(144.5,650,600)" />
<use xlink:href="#Z1" transform="rotate(146,650,600)" />
<use xlink:href="#Z1" transform="rotate(149,650,600)" />
<use xlink:href="#L1" transform="rotate(152,650,600)" />
</g>

<!-- Humidity scale -->
<g id="T2" stroke="black">
<use xlink:href="#Z2" transform="rotate(208,350,600)" />
<use xlink:href="#Z2" transform="rotate(212,350,600)" />
<use xlink:href="#Z2" transform="rotate(216,350,600)" />
<use xlink:href="#L2" transform="rotate(218,350,600)" />
<use xlink:href="#Z2" transform="rotate(220,350,600)" />
<use xlink:href="#Z2" transform="rotate(224,350,600)" />
<use xlink:href="#Z2" transform="rotate(228,350,600)" />
<use xlink:href="#L2" transform="rotate(228,350,600)" />
<use xlink:href="#Z2" transform="rotate(232,350,600)" />
<use xlink:href="#Z2" transform="rotate(236,350,600)" />
<use xlink:href="#L2" transform="rotate(238,350,600)" />
<use xlink:href="#Z2" transform="rotate(240,350,600)" />
<use xlink:href="#Z2" transform="rotate(244,350,600)" />
<use xlink:href="#Z2" transform="rotate(248,350,600)" />
<use xlink:href="#L2" transform="rotate(248,350,600)" />
<use xlink:href="#Z2" transform="rotate(252,350,600)" />
<use xlink:href="#Z2" transform="rotate(256,350,600)" />
<use xlink:href="#L2" transform="rotate(258,350,600)" />
<use xlink:href="#Z2" transform="rotate(260,350,600)" />
<use xlink:href="#Z2" transform="rotate(264,350,600)" />
<use xlink:href="#L2" transform="rotate(268,350,600)" />
</g>

<!-- numbers on scale -->
<g font-family="arial" font-size="20" font-weight="normal" font-style="normal" stroke="black" fill="black" id ="numbers">
<!-- right side -->
<text x="582" y="295">100</text>
<text x="637" y="342">80</text>
<text x="676" y="394">60</text>
<text x="704" y="454">40</text>
<text x="725" y="522">20</text>
<!-- left side -->
<text x="726" y="590">0</text>
<text x="355" y="322">30</text>
<text x="292" y="399">20</text>
<text x="253" y="492">10</text>
<text x="260" y="590">0</text>
</g>

<!-- 4 grey stripes in middle -->
<g id="T2" stroke="grey">
<use xlink:href="#line1" transform="rotate(117.5,650,600)" />
<use xlink:href="#line2" transform="rotate(126.5,650,600)" />
<use xlink:href="#line3" transform="rotate(233,350,600)" />
<use xlink:href="#line4" transform="rotate(248,350,600)" />
</g>

<!-- Deviation point field -->
<g font-family="arial" font-size="25" font-weight="normal" font-style="normal" stroke="black" fill="black" id="devpoint" display="none">
<text id="txtdevpoint" x="400" y="700"></text>
</g>

<!-- Pointer Temperature -->
<g stroke="red" stroke-width="1" fill="none">
<use xlink:href="#PO1" transform="rotate(92,650,600)" id="PO1a" />
</g>

<!-- Pointer Humidity -->
<g stroke="red" stroke-width="1" fill="none">
<use xlink:href="#PO2" transform="rotate(268,350,600)" id="PO2a" />
</g>

</svg>
`

    function init() {
        console.log("init widget");
        me.elements = $('div[data-type="' + me.widgetname + '"]', me.area);
        me.elements.each(function (index) {

            var elem = $(this);

            // init temperature and humidity
            elem.initData('get-temperature', '0.00');
            elem.initData('get-humidity', '0.00');
           
            // svg id - only set on init
            elem.initData('svg-id', 'none');
            svgobj = $(svgimage.replace("{{hygrosvg}}", elem.data('svg-id'))).appendTo(elem);
            svgobj = document.getElementById(elem.data('svg-id'));

            // size
            elem.initData('size', '500');
            svgobj.setAttribute("style", "width:" + elem.data('size') + ";height:" + elem.data('size') + ";");

            // colors
            elem.initData('color-outerborder', '#bfc1c2');
            svgobj.getElementById("border_outer").setAttribute("stroke", elem.data('color-outerborder'))

            elem.initData('color-background', 'whitesmoke');
            svgobj.getElementById("border_outer").setAttribute("fill", elem.data('color-outerborder'))
           
            elem.initData('color-innerborder', '#d8d8d8');
            svgobj.getElementById("border_inner").setAttribute("stroke", elem.data('color-innerborder'))

            elem.initData('color-scale', 'black');
            svgobj.getElementById("M1").setAttribute("stroke", elem.data('color-scale'))
            svgobj.getElementById("L1").setAttribute("stroke", elem.data('color-scale'))
            svgobj.getElementById("MM1").setAttribute("stroke", elem.data('color-scale'))
            svgobj.getElementById("M2").setAttribute("stroke", elem.data('color-scale'))
            svgobj.getElementById("L2").setAttribute("stroke", elem.data('color-scale'))
            svgobj.getElementById("numbers").setAttribute("stroke", elem.data('color-scale'))
            svgobj.getElementById("numbers").setAttribute("fill", elem.data('color-scale'))
            svgobj.getElementById("devpoint").setAttribute("stroke", elem.data('color-scale'))
            svgobj.getElementById("devpoint").setAttribute("fill",elem.data('color-scale'))

            elem.initData('color-pointer', 'orangered');
            svgobj.getElementById("PO1_line").setAttribute("fill",elem.data('color-pointer'))
            svgobj.getElementById("PO1_rect").setAttribute("fill",elem.data('color-pointer'))
            svgobj.getElementById("PO2_line").setAttribute("fill",elem.data('color-pointer'))
            svgobj.getElementById("PO2_rect").setAttribute("fill",elem.data('color-pointer'))
           
            // show or hide Deviation point - only set on init
            elem.initData('show-devpoint', '0');
            var val = parseInt(elem.data('show-devpoint'));
            showDevpoint(val);

            // speed of pointers - only set on init
            elem.initData('pointer-speed', '20');
            pointerspeed = parseInt(elem.data('pointer-speed'));

            // Device reading for temperature
            if (elem.isDeviceReading('get-temperature')) {
                me.addReading(elem, 'get-temperature');
            }

            // Device reading for humidity
            if (elem.isDeviceReading('get-humidity')) {
                me.addReading(elem, 'get-humidity');
            }
        });
    }

    function update(device, reading) {
        me.elements.each(function (index) {
            var elem = $(this);
            // we see an update in temperature reading
            if (elem.matchDeviceReading('get-temperature', device, reading)) {
                temperature = parseFloat(elem.getReading('get-temperature').val);

                // set Deviation point
                setDevpoint();

                // stop intervall if already run from last update
                clearInterval(a);

                // set target for pointer move
                newTemp = (temperature * 1.5) + 92;
                newTemp = Math.round(newTemp * 100)/100;
                var PO1 = svgobj.getElementById("PO1a");

                // starting smooth move
                var a = setInterval(function(){
                    if(oldTemp < newTemp){
                        oldTemp = Math.round((oldTemp + 0.01) * 100)/100; // move forward
                        PO1.setAttribute("transform", "rotate(" + oldTemp + ",650,600)");
                    } else if ( oldTemp > newTemp) {
                        oldTemp = Math.round((oldTemp - 0.01) * 100)/100; // move backward
                        PO1.setAttribute("transform", "rotate(" + oldTemp + ",650,600)");
                    } else if ( oldTemp == newTemp) {
                        clearInterval(a); // gotcha - kill move
                    }
                }, pointerspeed);
            }

            if (elem.matchDeviceReading('get-humidity', device, reading)) {
                humidity = parseFloat(elem.getReading('get-humidity').val);
                setDevpoint();

                clearInterval(b);
                newHum = 268 - (humidity / 2);
                newHum = Math.round(newHum * 100)/100;
                var PO2 = svgobj.getElementById("PO2a");
                var b = setInterval(function(){
                    if(oldHum < newHum){
                        oldHum = Math.round((oldHum + 0.01) * 100)/100;
                        PO2.setAttribute("transform", "rotate(" + oldHum + ",350,600)");
                    } else if ( oldHum > newHum) {
                        oldHum = Math.round((oldHum - 0.01) * 100)/100;
                        PO2.setAttribute("transform", "rotate(" + oldHum + ",350,600)");
                    } else if ( oldHum == newHum) {
                        clearInterval(b);
                    }
                }, pointerspeed);
            }

        });
    }

    function showDevpoint(show){ //true or false, 0 or 1
        console.log("show Deviation " + show);
        var devpoint = svgobj.getElementById("devpoint");
        devpoint.setAttribute("display", show ? "show" : "none");
    }
   
function setDevpoint() {
        var txtdevpoint = svgobj.getElementById("txtdevpoint");
        txtdevpoint.textContent='Taupunkt ' + getDevpoint(temperature, humidity) + '°C'
    }
   
function getDevpoint(Temperature, Humidity) {
var a = Temperature >= 0 ? 7.5 : 7.6;
var b = Temperature >= 0 ? 237.3 : 240.7;
var sdd = 6.1078 * Math.exp(((a*Temperature)/(b+Temperature))/Math.LOG10E);
var dd = Humidity/100 * sdd;
var c = Math.log(dd/6.1078) * Math.LOG10E;
var Devpoint = (b * c) / (a - c);
n = Math.pow(10, 1);
x = Math.round(Devpoint*n);
return x/n;
}

    var me = $.extend(new Modul_widget(), {
        widgetname: 'hygrometer',
        init: init,
        update: update,
    });

    return me;
};

Waldmensch

#34
Fix für Positionierung, Größe und Ränder. Das SVG ist jetzt nur noch so groß wie der Inhalt. War ein Haufen Holz, alle einzelnen Koordinaten neu zu setzen. Im Anhang auch als Datei zum kopieren nach /opt/fhem/www/tablet/js

Das rote Design bekommt man über diese Definition:
<div data-type = "hygrometer"
data-svg-id = "hygrosvg"
data-get-temperature = "Wetterstation:temperature"
data-get-humidity = "Wetterstation:humidity"
data-show-devpoint= "1"
data-pointer-speed = "20"
data-color-scale = "red"
data-color-background = "black"
data-size = "300"
style=""
class="">
</div>


widget_hygrometer.js
var Modul_hygrometer = function () {

    /* parameters
        data-get-temperature = "<Device>:<Reading>"
        data-get-humidity = "<Device>:<Reading>"
        data-svg-id = "<unique id>"
        data-size = "500"
        data-show-devpoint = "0|1"
        data-pointer-speed = "20" // as higher as slower
        data-color-outerborder = "#000000"
        data-color-innerborder = "#000000"
        data-color-background = "#000000"
        data-color-scale = "#000000"
        data-color-pointer = "#000000"
    */

    var svgobj;

    // raw values, needed for deviationpoint calculation
    var temperature, humidity;

    // values with included offsets to move the pointers
    var oldTemp = 92, newTemp = 0;
    var oldHum = 268, newHum = 0;

    var pointerspeed = 20;

    var svgimage = `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 552 552" id="{{hygrosvg}}">

<!-- Border -->
<circle cx="275" cy="275" r="265" fill="WhiteSmoke" stroke="#bfc1c2" stroke-width="16" id="border_outer"/>
<circle cx="275" cy="275" r="265" stroke="#d8d8d8" stroke-width="4" id="border_inner"/>
<g stroke="black" stroke-width="2" fill="none"></g>

<defs>
<!-- Pointer template Temperature -->
<g id="PO1">
<line stroke-width="2" x1="425" y1="375" x2="425" y2="765" fill="orangered" id="PO1_line"/>
<rect x="417" y="330" rx="2" ry="2" width="16" height="64" fill="orangered" id="PO1_rect"/>
<circle cx="425" cy="375" r="2" stroke="brown" stroke-width="4" />
<circle cx="425" cy="375" r="3" fill="grey"/>
</g>

<!-- Pointer template Humidity -->
<g id="PO2">
<line stroke-width="2" x1="125" y1="375" x2="125" y2="765" fill="orangered" id="PO2_line"/>
<rect x="117" y="330" rx="2" ry="2" width="16" height="64" fill="orangered" id="PO2_rect"/>
<circle cx="125" cy="375" r="2" stroke="brown" stroke-width="4" />
<circle cx="125" cy="375" r="3" fill="grey"/>
</g>

<!-- scale templates -->
<line stroke-width="1" id="M1" x1="425" y1="725" x2="425" y2="745"/>
<line stroke-width="2" id="L1" x1="425" y1="725" x2="425" y2="755"/>
<line stroke-width="1" id="MM1" x1="425" y1="725" x2="425" y2="750"/>

<g id="Z1">
<use xlink:href="#M1" transform="rotate(0,425,375)"/>
<use xlink:href="#M1" transform="rotate(1.5,425,375)"/>
</g>

<line stroke-width="1" id="M2" x1="125" y1="725" x2="125" y2="745"/>
<line stroke-width="2" id="L2" x1="125" y1="725" x2="125" y2="755"/>

<g id="Z2">
<use xlink:href="#M2" transform="rotate(0,125,375)"/>
<use xlink:href="#M2" transform="rotate(2,125,375)"/>
</g>

<!-- 4 stripes templates -->
<line stroke-width="1" id="line1" x1="425" y1="505" x2="425" y2="695"/>
<line stroke-width="1" id="line2" x1="425" y1="495" x2="425" y2="695"/>
<line stroke-width="1" id="line3" x1="125" y1="495" x2="125" y2="695"/>
<line stroke-width="1" id="line4" x1="125" y1="535" x2="125" y2="695"/>

</defs>

<!-- Temperature scale -->
<g id="T1" stroke="black">
<use xlink:href="#Z1" transform="rotate(92,425,375)"/>
<use xlink:href="#L1" transform="rotate(92,425,375)"/>
<use xlink:href="#Z1" transform="rotate(95,425,375)"/>
<use xlink:href="#Z1" transform="rotate(98,425,375)"/>
<use xlink:href="#MM1" transform="rotate(99.5,425,375)"/>
<use xlink:href="#Z1" transform="rotate(101,425,375)"/>
<use xlink:href="#Z1" transform="rotate(104,425,375)"/>
<use xlink:href="#Z1" transform="rotate(107,425,375)"/>
<use xlink:href="#L1" transform="rotate(107,425,375)"/>
<use xlink:href="#Z1" transform="rotate(110,425,375)"/>
<use xlink:href="#Z1" transform="rotate(113,425,375)"/>
<use xlink:href="#MM1" transform="rotate(114.5,425,375)"/>
<use xlink:href="#Z1" transform="rotate(116,425,375)"/>
<use xlink:href="#Z1" transform="rotate(119,425,375)"/>
<use xlink:href="#Z1" transform="rotate(122,425,375)"/>
<use xlink:href="#L1" transform="rotate(122,425,375)"/>
<use xlink:href="#Z1" transform="rotate(125,425,375)"/>
<use xlink:href="#Z1" transform="rotate(128,425,375)"/>
<use xlink:href="#MM1" transform="rotate(129.5,425,375)"/>
<use xlink:href="#Z1" transform="rotate(131,425,375)"/>
<use xlink:href="#Z1" transform="rotate(134,425,375)"/>
<use xlink:href="#Z1" transform="rotate(137,425,375)"/>
<use xlink:href="#L1" transform="rotate(137,425,375)"/>
<use xlink:href="#Z1" transform="rotate(140,425,375)"/>
<use xlink:href="#Z1" transform="rotate(143,425,375)"/>
<use xlink:href="#MM1" transform="rotate(144.5,425,375)"/>
<use xlink:href="#Z1" transform="rotate(146,425,375)"/>
<use xlink:href="#Z1" transform="rotate(149,425,375)"/>
<use xlink:href="#L1" transform="rotate(152,425,375)"/>
</g>

<!-- Humidity scale -->
<g id="T2" stroke="black">
<use xlink:href="#Z2" transform="rotate(208,125,375)"/>
<use xlink:href="#Z2" transform="rotate(212,125,375)"/>
<use xlink:href="#Z2" transform="rotate(216,125,375)"/>
<use xlink:href="#L2" transform="rotate(218,125,375)"/>
<use xlink:href="#Z2" transform="rotate(220,125,375)"/>
<use xlink:href="#Z2" transform="rotate(224,125,375)"/>
<use xlink:href="#Z2" transform="rotate(228,125,375)"/>
<use xlink:href="#L2" transform="rotate(228,125,375)"/>
<use xlink:href="#Z2" transform="rotate(232,125,375)"/>
<use xlink:href="#Z2" transform="rotate(236,125,375)"/>
<use xlink:href="#L2" transform="rotate(238,125,375)"/>
<use xlink:href="#Z2" transform="rotate(240,125,375)"/>
<use xlink:href="#Z2" transform="rotate(244,125,375)"/>
<use xlink:href="#Z2" transform="rotate(248,125,375)"/>
<use xlink:href="#L2" transform="rotate(248,125,375)"/>
<use xlink:href="#Z2" transform="rotate(252,125,375)"/>
<use xlink:href="#Z2" transform="rotate(256,125,375)"/>
<use xlink:href="#L2" transform="rotate(258,125,375)"/>
<use xlink:href="#Z2" transform="rotate(260,125,375)"/>
<use xlink:href="#Z2" transform="rotate(264,125,375)"/>
<use xlink:href="#L2" transform="rotate(268,125,375)"/>
</g>

<!-- numbers on scale -->
<g font-family="arial" font-size="20" font-weight="normal" font-style="normal" stroke="black" fill="black" id ="numbers">
<!-- right side -->
<text x="357" y="70">100</text>
<text x="412" y="117">80</text>
<text x="451" y="169">60</text>
<text x="479" y="229">40</text>
<text x="500" y="297">20</text>
<text x="503" y="365">0</text>
<!-- left side -->
<text x="130" y="97">30</text>
<text x="67" y="174">20</text>
<text x="28" y="267">10</text>
<text x="34" y="365">0</text>
</g>

<!-- 4 grey stripes in middle -->
<g id="T2" stroke="grey">
<use xlink:href="#line1" transform="rotate(117.5,425,375)"/>
<use xlink:href="#line2" transform="rotate(126.5,425,375)"/>
<use xlink:href="#line3" transform="rotate(233,125,375)"/>
<use xlink:href="#line4" transform="rotate(248,125,375)"/>
</g>

<!-- Deviation point field -->
<g font-family="arial" font-size="25" font-weight="normal" font-style="normal" stroke="black" fill="black" id="devpoint" display="none">
<text id="txtdevpoint" x="185" y="475"></text>
</g>

<!-- Pointer Temperature -->
<g stroke="red" stroke-width="1" fill="none">
<use xlink:href="#PO1" transform="rotate(92,425,375)" id="PO1a"/>
</g>

<!-- Pointer Humidity -->
<g stroke="red" stroke-width="1" fill="none">
<use xlink:href="#PO2" transform="rotate(268,125,375)" id="PO2a"/>
</g>

</svg>
`

    function init() {
        console.log("init widget");
        me.elements = $('div[data-type="' + me.widgetname + '"]', me.area);
        me.elements.each(function (index) {

            var elem = $(this);

            // init temperature and humidity
            elem.initData('get-temperature', '0.00');
            elem.initData('get-humidity', '0.00');
           
            // svg id - only set on init
            elem.initData('svg-id', 'none');
            svgobj = $(svgimage.replace("{{hygrosvg}}", elem.data('svg-id'))).appendTo(elem);
            svgobj = document.getElementById(elem.data('svg-id'));

            // size
            elem.initData('size', '500');
            //svgobj.setAttribute("style", "width:" + elem.data('size') + ";height:" + elem.data('size') + ";");
            svgobj.setAttribute("width", elem.data('size'));
            svgobj.setAttribute("height", elem.data('size'));

            // colors
            elem.initData('color-outerborder', '#bfc1c2');
            svgobj.getElementById("border_outer").setAttribute("stroke", elem.data('color-outerborder'))

            elem.initData('color-background', 'whitesmoke');
            svgobj.getElementById("border_outer").setAttribute("fill", elem.data('color-outerborder'))
           
            elem.initData('color-innerborder', '#d8d8d8');
            svgobj.getElementById("border_inner").setAttribute("stroke", elem.data('color-innerborder'))

            elem.initData('color-scale', 'black');
            svgobj.getElementById("M1").setAttribute("stroke", elem.data('color-scale'))
            svgobj.getElementById("L1").setAttribute("stroke", elem.data('color-scale'))
            svgobj.getElementById("MM1").setAttribute("stroke", elem.data('color-scale'))
            svgobj.getElementById("M2").setAttribute("stroke", elem.data('color-scale'))
            svgobj.getElementById("L2").setAttribute("stroke", elem.data('color-scale'))
            svgobj.getElementById("numbers").setAttribute("stroke", elem.data('color-scale'))
            svgobj.getElementById("numbers").setAttribute("fill", elem.data('color-scale'))
            svgobj.getElementById("devpoint").setAttribute("stroke", elem.data('color-scale'))
            svgobj.getElementById("devpoint").setAttribute("fill",elem.data('color-scale'))

            elem.initData('color-pointer', 'orangered');
            svgobj.getElementById("PO1_line").setAttribute("fill",elem.data('color-pointer'))
            svgobj.getElementById("PO1_rect").setAttribute("fill",elem.data('color-pointer'))
            svgobj.getElementById("PO2_line").setAttribute("fill",elem.data('color-pointer'))
            svgobj.getElementById("PO2_rect").setAttribute("fill",elem.data('color-pointer'))
           
            // show or hide Deviation point - only set on init
            elem.initData('show-devpoint', '0');
            var val = parseInt(elem.data('show-devpoint'));
            showDevpoint(val);

            // speed of pointers - only set on init
            elem.initData('pointer-speed', '20');
            pointerspeed = parseInt(elem.data('pointer-speed'));

            // Device reading for temperature
            if (elem.isDeviceReading('get-temperature')) {
                me.addReading(elem, 'get-temperature');
            }

            // Device reading for humidity
            if (elem.isDeviceReading('get-humidity')) {
                me.addReading(elem, 'get-humidity');
            }
        });
    }

    function update(device, reading) {
        me.elements.each(function (index) {
            var elem = $(this);
            // we see an update in temperature reading
            if (elem.matchDeviceReading('get-temperature', device, reading)) {
                temperature = parseFloat(elem.getReading('get-temperature').val);

                // set Deviation point
                setDevpoint();

                // stop intervall if already run from last update
                clearInterval(a);

                // set target for pointer move
                newTemp = (temperature * 1.5) + 92;
                newTemp = Math.round(newTemp * 100)/100;
                var PO1 = svgobj.getElementById("PO1a");

                // starting smooth move
                var a = setInterval(function(){
                    if(oldTemp < newTemp){
                        oldTemp = Math.round((oldTemp + 0.01) * 100)/100; // move forward
                        PO1.setAttribute("transform", "rotate(" + oldTemp + ",425,375)");
                    } else if ( oldTemp > newTemp) {
                        oldTemp = Math.round((oldTemp - 0.01) * 100)/100; // move backward
                        PO1.setAttribute("transform", "rotate(" + oldTemp + ",425,375)");
                    } else if ( oldTemp == newTemp) {
                        clearInterval(a); // gotcha - kill move
                    }
                }, pointerspeed);
            }

            if (elem.matchDeviceReading('get-humidity', device, reading)) {
                humidity = parseFloat(elem.getReading('get-humidity').val);
                setDevpoint();

                clearInterval(b);
                newHum = 268 - (humidity / 2);
                newHum = Math.round(newHum * 100)/100;
                var PO2 = svgobj.getElementById("PO2a");
                var b = setInterval(function(){
                    if(oldHum < newHum){
                        oldHum = Math.round((oldHum + 0.01) * 100)/100;
                        PO2.setAttribute("transform", "rotate(" + oldHum + ",125,375)");
                    } else if ( oldHum > newHum) {
                        oldHum = Math.round((oldHum - 0.01) * 100)/100;
                        PO2.setAttribute("transform", "rotate(" + oldHum + ",125,375)");
                    } else if ( oldHum == newHum) {
                        clearInterval(b);
                    }
                }, pointerspeed);
            }

        });
    }

    function showDevpoint(show){ //true or false, 0 or 1
        console.log("show Deviation " + show);
        var devpoint = svgobj.getElementById("devpoint");
        devpoint.setAttribute("display", show ? "show" : "none");
    }
   
function setDevpoint() {
        var txtdevpoint = svgobj.getElementById("txtdevpoint");
        txtdevpoint.textContent='Taupunkt ' + getDevpoint(temperature, humidity) + '°C'
    }
   
function getDevpoint(Temperature, Humidity) {
var a = Temperature >= 0 ? 7.5 : 7.6;
var b = Temperature >= 0 ? 237.3 : 240.7;
var sdd = 6.1078 * Math.exp(((a*Temperature)/(b+Temperature))/Math.LOG10E);
var dd = Humidity/100 * sdd;
var c = Math.log(dd/6.1078) * Math.LOG10E;
var Devpoint = (b * c) / (a - c);
n = Math.pow(10, 1);
x = Math.round(Devpoint*n);
return x/n;
}

    var me = $.extend(new Modul_widget(), {
        widgetname: 'hygrometer',
        init: init,
        update: update,
    });

    return me;
};

Waldmensch

#35
Ich hatte nach arbeit noch ein bisschen Zeit. Das widget heißt jetzt "gauge" und enthält 2 Analoginstrumente, die über "data-view" spezifiziert werden. Momentan gültige Werte sind "hygrometer" und "barometer". Das Barometer hat einen "Merkzeiger, der zur vollen Stunde auf den aktuellen Wert wechselt und dann für eine Stunde stehenbleibt. Somit sieht man, ob der Luftdruck steigt oder sinkt.

gültige Parameter:
data-view = "hygrometer|barometer"
        data-get-temperature = "<Device>:<Reading>"
        data-get-humidity = "<Device>:<Reading>"
        data-svg-id = "<unique id>"
        data-size = "300"
data-show-devpoint = "0|1"
data-show-baro-value = "0|1"
        data-pointer-speed = "20" // as higher as slower
        data-color-outerborder = "#000000"
        data-color-innerborder = "#000000"
        data-color-background = "#000000"
        data-color-scale = "#000000"
        data-color-pointer = "#000000"


Beispielconfig vom Screenshot:

<li data-row="1" data-col="1" data-sizex="6" data-sizey="5">
  <header>HYGROMETER</header>
<div data-type = "gauge"
data-view = "hygrometer"
data-svg-id = "hygro1"
data-get-temperature = "Wetterstation:temperature"
data-get-humidity = "Wetterstation:humidity"
data-show-devpoint= "1"
data-pointer-speed = "20"
data-color-scale = "red"
data-color-background = "black"
data-size = "300"
style=""
class="top-space-2x">
</div>
</li>
<li data-row="1" data-col="7" data-sizex="6" data-sizey="5">
  <header>BAROMETER</header>
  <div data-type = "gauge"
data-view = "barometer"
data-svg-id = "baro1"
data-show-baro-value = "1"
data-get-pressure = "Wetterstation:pressureRel"
data-pointer-speed = "20"
data-color-scale = "red"
data-color-background = "black"
data-size = "300"
style=""
class="top-space-2x">
</div>
</li>

Waldmensch

mal wieder ein kleines Update. Der View "clock" ist dazugekommen

Beispielconfig vom Screenshot:
<li data-row="1" data-col="1" data-sizex="6" data-sizey="4">
  <header>HYGROMETER</header>
<div
data-type = "gauge"
data-view = "hygrometer"
data-svg-id = "hygro1"
data-get-temperature = "Wetterstation:temperature"
data-get-humidity = "Wetterstation:humidity"
data-show-devpoint= "1"
data-pointer-speed = "20"
data-color-scale = "red"
data-color-background = "black"
data-color-pointer = "red"
data-size = "300"
style=""
class="top-space">
</div>
</li>
<li data-row="1" data-col="7" data-sizex="6" data-sizey="4">
  <header>BAROMETER</header>
  <div
data-type = "gauge"
data-view = "barometer"
data-svg-id = "baro1"
data-show-baro-value = "1"
data-get-pressure = "Wetterstation:pressureRel"
data-pointer-speed = "10"
data-color-scale = "red"
data-color-background = "black"
data-color-pointer = "red"
data-size = "300"
style=""
class="top-space">
</div>
</li>
<li data-row="6" data-col="1" data-sizex="6" data-sizey="4">
<header>Clock</header>
  <div
data-type = "gauge"
data-view = "clock"
data-svg-id = "clock1"
data-color-scale = "red"
data-color-background = "black"
data-color-pointer = "red"
data-size = "300"
style=""
class="top-space">
</div>
</li>

Prof. Dr. Peter Henning

Zunächst einmal Respekt vor der Arbeit, die da hineingesteckt worden ist - wer es etwas Retro mag, wird das sicher gern verwenden.

Allerdings muss ich sagen, dass die Festlegung der "Behaglichkeitszone" ein wenig zu primitiv ist. In den SmartHome Hacks habe ich das ausführlich dargestellt: Welche Feuchte wir als angenehm empfinden, hängt stark von der Temperatur ab. Das bedeutet, dass diese Behaglichkeitszone in diesem antiken Zeigerinstrument nicht einfach die Schnittmenge zweier Kreissektoren ist, siehe Bild.

Desweiteren muss man die Ergonomie kritisieren: Die Zeiger sind einfach zu dünn, um sie schnell ablesen zu können. Bei den echten Zeigerinstrumenten hatte das natürlich mechanische Gründe, Zeiger mussten sehr leicht und gut ausbalanciert sein - darum das fette untere Ende. Warum man diese Beschränkungen dann in eine moderne Anzeige übernimmt, muss man mir erstmal erklären.

LG

pah

Waldmensch

At 1: die Anzeige ist an das Instrument in der Originalen Anfrage (Post 1) angelehnt. Da die die Bereiche prinzipiell durch die Schnittbereiche 4 einfacher ,,Zeiger" dargestellt werden, ist es, mit der passenden Berechnung überhaupt kein Ding, diese ebenfalls zu rotieren, um das abgebildete Polygon dynamisch zu verändern. Leider ist mir das mathematisch eine Nummer zu hoch. Wenn jemand den passenden Algo beisteuert, baue ich das gerne ein.

At 2: in einer der nächsten Versionen werde ich die Strichstärke der Pointer über einen Parameter anpassbar machen. Das ist programmtechnisch überhaupt kein Problem und der aktuelle Zustand ist dem Umstand geschuldet, dass ich direkt vorm PC sitze und das Ganze noch nicht aus Distanz getestet habe. Vermutlich sind aber auch die  sw Defaults (ohne Farbsetzung in der Definition) schon besser lesbar.


Gesendet von iPhone mit Tapatalk

Prof. Dr. Peter Henning

Das ergonomische Problem wird dadurch verstärkt, dass die vorhandene Abbildung die schon schwer ablesbaren Skalen in Richtung auf die "Komfortzonenanzeige" verkleinert.

Mein Vorschlag (wollen wir mal konstruktiv sein...): Das Abbildungsprinzip umkehren. Skalen (in der Abbildung als kurze Bögen repräsentiert) nahe an den Zeiger-Ursprung. Die Zeiger-Ursprünge auseinderziehen und die Komfortzone oben in der Mitte anbringen (in der Abbildung als Polygon zu sehen).

Außerdem:
- zusätzliche digitale Anzeige der Werte
- optische Hervorhebung des Kreuzungspunktes
- und zwar in grüner, gelber oder roter Farbe, je nachdem, ob man sich in der Komfortzone befindet oder nicht.

LG

pah

Waldmensch

Danke für diesen wertvollen Input und die Mühe der Visualisierung. Das ist durchaus umsetzbar. Da werde ich aber ein separates Instrument draus machen, dann hat der User die freie Wahl. Das Plugin lässt sich recht einfach um weitere Instrumente erweitern und die dunklen Winterabende kommen ja erst noch. Auf der Agenda steht als nächstes erst noch ein Aneamometer mit Windrichtungsanzeige und ein einfaches Thermometer, sowie ein einfaches Hygrometer, da das Kombiinstrument ja eher für den Innenbereich ist.


Gesendet von iPhone mit Tapatalk

Prof. Dr. Peter Henning

Oh, da bringe ich mich gerne ein. Für das neue FHEM-Buch habe ich das Bar-Widget genau beschrieben, siehe Anlage - und ein Thermometer habe ich ebenfalls schon realisiert, und zwar mit der temperaturabhängigen Farbskala aus den SmarHome Hacks.

LG

pah

Waldmensch

Ein paar Veränderungen u.a. auf Basis der Vorschläge zur Ergonomie von Prof. Dr. Peter Henning
- Pointer Widths (die Dicke der Zeiger) können als Array vorgegeben werden. Zahlentyp is Float
- Pointer Length (die Länge der Zeiger) können als Array vorgegeben werden. Zahlentyp is Float
- die "svg-id" wird nicht mehr benötigt und entfällt ersatzlos. Intern wird nun einen UUID verwendet um die SVG zu adressieren
- der Barometer Memory Zeiger hat jetzt einen kleinen 24h cache. Über den Parameter data-baro-history kann die Anzahl der Stunden festgelegt werden, um die der Memory Zeiger hinterherhängt. Der Zeiger wird natürlich erst sichtbar, wenn rückblickend schon ein Wert im Cache ist. Der cache überlebt einen FTUI reload nicht. Zahlentyp ist Integer.

Beispielconfig für die Darstellung im Screenshot:
<li data-row="1" data-col="1" data-sizex="6" data-sizey="4">
  <header>HYGROMETER</header>
<div
data-type = "gauge"
data-view = "hygrometer"
data-get-temperature = "Wetterstation:temperatureInside"
data-get-humidity = "Wetterstation:humidityInside"
data-show-devpoint= "1"
data-pointer-speed = "20"
data-pointer-widths = '["0.0","6"]'
data-pointer-lengths = '["370.0","370.0"]'
data-color-scale = "red"
data-color-background = "black"
data-color-pointer = "red"
data-size = "300"
style=""
class="top-space">
</div>
</li>
<li data-row="1" data-col="7" data-sizex="6" data-sizey="4">
  <header>BAROMETER</header>
  <div
data-type = "gauge"
data-view = "barometer"
data-baro-show-value = "1"
data-baro-history = "2"
data-get-pressure = "Wetterstation:pressureRel"
data-pointer-speed = "10"
data-pointer-widths = '["6"]'
data-color-scale = "red"
data-color-background = "black"
data-color-pointer = "red"
data-size = "300"
style=""
class="top-space">
</div>
</li>
<li data-row="6" data-col="1" data-sizex="6" data-sizey="4">
<header>Clock</header>
  <div
data-type = "gauge"
data-view = "clock"
data-color-scale = "red"
data-color-background = "black"
data-color-pointer = "red"
data-size = "300"
style=""
class="top-space">
</div>
</li>



Prof. Dr. Peter Henning

Noch ein Tipp: Die Abkürzung für Hektopascal heißt nicht hpa, sondern hPa.

LG

pah


Waldmensch

Das kommt davon, wenn man bei Apple spickt ;) Korrigiere ich mit der nächsten Version.

https://apps.apple.com/de/app/barometer-atmospharendruck/id769602146