Hauptmenü

Raum-Klimamesser

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

Vorheriges Thema - Nächstes Thema

yersinia

#15
GEIL @Waldmensch!

Den SVG Code könnte man in eine .svg Grafik giessen und dann enstprechend in den HTML Code einbinden.

Um die Zeiger zu adaptieren könnte man entweder das label-widget oder besser symbol widget kopieren und adaptieren um die Werte von Devices auszulesen und die svg entsprechend zu manipulieren. :D

Ich könnte mir sowas in der Art vorstellen im FTUI (Beispiel!):
<object data="hygro.svg" type="image/svg+xml" id="hygrosvg" class="">
<img src="hygro.svg" id="hygrosvg" class="" />
</object>
<div data-type="hygro"
data-device-t="TempDevice"
data-reading-t="ReadingT"
data-device-h="HumDevice"
data-reading-h="ReadingH"
data-svgid="hygrosvg"
style="visibility: hidden;"
class=""></div>

Dabei beeinflusst das widget nur die SVG und zeigt selbst nichts an.

Man könnte auch, analog zum Analoganzeige widget, das SVG dynamisch durch JS generieren lassen. Ob sich dies allerdings lohnt ist eine andere Frage, der dynamische Anteil in diesem SVG ist relativ gering.

Ach wenn man immer soviel Zeit wie Ideen hätte...-.-
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

Waldmensch

Zitatdas SVG dynamisch durch JS generieren lassen
Würde ich nicht machen. Eine separate Datei lässt sich imho besser skinnen. Wer was mit dunklem Hintergrund haben will, nimmt einfach ein "gemoddetes" SVG in den Pfad. Es wäre sicher cool, eine komplette FTUI page mit solchen Analoginstrumenten zu füllen. Das macht optisch sicher was her. Hat was von Steampunk ;)

yersinia

#17
Ich habe hier mal eine erste Version zusammen gewurschtelt.

Die Berechnungen und das SVG ist von Waldmensch. Danke dafür.  :D

Die widget_hygro.js muss in den js-Folder von ftui nach /opt/fhem/www/tablet/js, die hygro.svg irgndwohin, wo ftui drauf zugreifen kann - ich hab sie nach /opt/fhem/www/tablet kopiert.

Aufruf aus FTUI via
<object data="hygro.svg" type="image/svg+xml" id="hygrosvg" class="" style="">
                </object>
                <div data-type="hygro"
                        data-device="TEMP-DEVICE"
                        data-get="TEMP-READING"
                        data-mode="temp"
                        data-svg-id="hygrosvg"
                        style="visibility: hidden;"
                        class=""></div>
                <div data-type="hygro"
                        data-device="HUMIDTY-DEVICE"
                        data-get="HUMIDITY-READING"
                        data-mode="hum"
                        data-svg-id="hygrosvg"
                        style="visibility: hidden;"
                        class=""></div>

dabei wird erst das svg object geladen und dann das widget zweimal aufgerufen - einmal für die temperatur und einmal für die humidity. So kann man auch zwei verschiedene Devices benutzen.

  • <object> bindet die svg ein; wobei die id entscheidend ist (hier hygrosvg); mittels data wird die SVG Datei eingebunden - hierbei auf den Pfad achten
  • data-type="hygro" um das widget aufzurufen
  • data-device und data-get sollten klar sein: wie bei anderen widgets werden hier das Device und die Readings übergeben
  • data-mode (temp oder hum) weisst das reading dem linken oder rechten Zeiger zu
  • data-svg-id setzt den Link zum entsprechenden SVG Object

Wie gesagt, ist erstmal nur gewurschtelt und sicher noch nicht perfekt.

Durch setzen verschiedener ids kann man mehrere Hygrometer auf einer Seite anzeigen.
Getestet auf FF 69.0.3 auf aktuellem FTUI.
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

Waldmensch

Man könnte unten in den freien Bereich zum Beispiel noch den Taupunkt kunstvoll einfügen. Der würde ja thematisch reinpassen.
Als weitere Rundinstrumente würde sich noch eine Windrose anbieten. Bin echt am überlegen, ein ganzes FTUI nur als edle Wetterstation zu gestalten. Eventuell mit einem Hintergrund aus oxidiertem Kupfer und ein paar Nieten. Die langen Winterabende kommen ja erst noch ;)


Gesendet von iPhone mit Tapatalk

Waldmensch

@yersinia: falls Du die Formel für den Taupunkt irgendwo unterkriegst:

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;
}

yersinia

@Waldmensch, sicher, wenn man das ins JS gegossen bekommt, kann man dies in das widget einfriemeln.

Kannst du das SVG entsprechend manipulieren sodass man auch ein Textfeld im SVG für den Taupunkt und ggf Temp sowie Humidity hat? Sofern gewollt.
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

Waldmensch

Heute schaffe ich das nicht mehr. Ich muss auch erstmal schauen, ob man normale Styles wie ,,visible" im SVG anwenden kann. Es sollte ja nach Möglichkeit von außen steuerbar sein. Ich habe noch nie zuvor mit SVG rumgemurkelt. ;)


Gesendet von iPhone mit Tapatalk

yersinia

Zitat von: Waldmensch am 23 Oktober 2019, 13:55:12
Ich muss auch erstmal schauen, ob man normale Styles wie ,,visible" im SVG anwenden kann. Es sollte ja nach Möglichkeit von außen steuerbar sein.
Sollte eigentlich gehen, das ganze noch mit einer id versehen, dann kann man da -analog zur Zeiger-Rotation- via JS drauf zugreifen, denke ich.
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

Waldmensch

#23
Habe es mal schnell gemacht. Wie beim letzten mal als HTML. Das musst Du Dir mal auseinanderpflücken wie Du es brauchst. Ich habe ins SVG auch ein paar Kommentare eingefügt, was dort was ist. Die beiden Funktionen zum setzen der Zeiger sind auf float umgestellt. Dadurch sind jetzt Dezimalwerte wie 20.25 möglich und werden auch so angezeigt. Zusätzlich habe ich noch einen Eyecatcher drin. Die Zeiger bewegen sich jetzt sehr smoth. Wenn das zu langsam ist, den Intervall, der jetzt 20ms ist verkleinern. Für noch langsamer, den Intervall erhöhen.

<html>
<head>
<style>
#hygro {
height:100%;
width:100%;
}
</style>
<script>

var oldTemp = 92, newTemp = 0;
var oldHum = 268, newHum = 0;

function setptr1() {
clearInterval(a);
newTemp = (parseFloat(document.getElementById("valuepo1").value) *1.5) + 92;
newTemp = Math.round(newTemp * 100)/100;
var PO1 = document.getElementById("PO1a");
var a = setInterval(function(){
if(oldTemp < newTemp){
oldTemp = Math.round((oldTemp + 0.01) * 100)/100;
PO1.setAttribute("transform", "rotate(" + oldTemp + ",650,600)");
} else if ( oldTemp > newTemp) {
oldTemp = Math.round((oldTemp - 0.01) * 100)/100;
PO1.setAttribute("transform", "rotate(" + oldTemp + ",650,600)");
} else if ( oldTemp == newTemp) {
clearInterval(a);
}
},20);
}
function setptr2() {
clearInterval(b);
newHum = 268 - (parseFloat(document.getElementById("valuepo2").value) /2);
newHum = Math.round(newHum * 100)/100;
var PO2 = document.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);
}
},20);
}
function showDevpoint(show){ //true or false, 0 or 1
var devpoint = document.getElementById("devpoint");
devpoint.setAttribute("display", show ? "show" : "none");
}
function setDevpoint() {
var txtdevpoint = document.getElementById("txtdevpoint");
var tempval = parseFloat(document.getElementById("valuepo1").value)
var humval = parseFloat(document.getElementById("valuepo2").value)
txtdevpoint.textContent='Taupunkt ' + getDevpoint(tempval,humval) + '°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;
}
</script>
</head>
<body>
<input type="text" id="valuepo1"></input><button onclick = "setptr1();" >set Temp</button><br>
<input type="text" id="valuepo2"></input><button onclick = "setptr2();" >set Hum</button><br>
<button onclick = "setDevpoint();" >Set Devpoint</button><button onclick = "showDevpoint(true);" >Show Devpoint</button><button onclick = "showDevpoint(false);" >Hide Devpoint</button><br>

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1000" height="1000" id="hygro" >

<!-- Border -->
<circle cx="500" cy="500" r="265" fill="WhiteSmoke" stroke="#bfc1c2" stroke-width="16"/>
<circle cx="500" cy="500" r="265" fill-opacity="0" stroke="#d8d8d8" stroke-width="4"/>
<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"/>
<rect x="642" y="555" rx="2" ry="2" width="16" height="64" fill="orangered"/>
<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"/>
<rect x="342" y="555" rx="2" ry="2" width="16" height="64" fill="orangered"/>
<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" >
<!-- 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>

</body>
</html>

yersinia

#24
Cool! :D

Ich habe gerade versucht, das mal einzubauen, da ist mir in dem von mir verwendeten Konzept ein Knackpunkt aufgefallen: da ich das widget zweimal aufrufe, kann ich auch zwei verschiedene Devices unterstützen (eins für die Temperatur, eins für die Luftfeuchte). Dadurch kann ich den Taupunkt nach meinem derzeitigen Kenntnisstand nicht definieren, da ich beide Werte benötige - aber mWn nicht widgetübergreifend auf den jeweils anderen Wert zugreifen.... :-\
Die Alternative wäre, zu versuchen die Funktion nur auf ein Device zu beschränken, dann könnte ich auch den Taupunkt bestimmen. Da muss ich nochmal einige Nächte drüber grübeln... :-[
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

Waldmensch

In verschiedenen anderen Widgets kann man aber einem Parameter device:reading übergeben also vorgesehen und machbar sollte das sein. Vielleicht hilft ja @setstate mal mit einem Widget Korpus aus. Ich weiß nicht, ob im Wiki zum ,,eigene Widgets" etwas über die Readings steht. Habe den Artikel neulich nur überflogen.
Worst case muss man halt die Readings über notifys in einem Dummy auf FHEM Ebene zusammenführen.
Die Devpoint Berechnung sollte vielleicht noch abgesichert werden gegen 0 Wert im humidity. 0 wert in Temperatur ist ja eigentlich valide. Ich habe es aber nicht getestet

Zu dem smooth move. Das dauert natürlich etwas, bis der Zeiger von 0 auf bspw 20 Grad geklettert ist. Wenn dann im weiteren Verlauf nur noch Änderungen im Gradbereich kommen sieht es jedenfalls genial analogintstrumentmäßig aus. :)


Gesendet von iPhone mit Tapatalk

Waldmensch

#26
Teste mal den Widget code unten, der tut es bei mir ganz gut. Nur das SVG kriege ich nicht richtig in die Gridster Zelle. Bin da aber jetzt auch zu müde. Irgendwie feuert ein "setreading" in einem Dummy kein Event an FTUI.

EDIT: Houston, wir haben ein Problem. Wie können wir sicherstellen, dass das SVG geladen ist, bevor das Widget ausgeführt wird? Der Code unten bringt einen Fehler, wenn das SVG noch nicht geladen ist. Ist dann quasi ein Glücksspiel mit der F5 Taste.

Definition:  <object data="hygro.svg" type="image/svg+xml" id="hygrosvg" class="" style=""></object>
  <div data-type="hygrometer"
data-get-temperature="test_temperature:temp"
data-get-humidity="test_humidity:hum"
data-show-devpoint="0"
data-svg-id="hygrosvg"
style="visibility: hidden;"
class=""></div>


Widget:
var Modul_hygrometer = function () {

    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;

    function init() {

        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 = document.getElementById(elem.data('svg-id')).getSVGDocument();
           
            // show or hide Deviation point - only set on init
            elem.initData('show-devpoint', '0');
            var val = parseInt(elem.getReading('show-devpoint').val);
            showDevpoint(val);

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

            // 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
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

#27
Ich habe das SVG jetzt ins Widget eingebaut. Somit entfallen die Probleme, dass das SVG noch nicht geladen ist, wenn das Widget init durchläuft.

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"
style=""
class="">
</div>



widget_hygrometer.js
var Modul_hygrometer = function () {

    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" />
<circle cx="500" cy="500" r="265" fill-opacity="0" stroke="#d8d8d8" stroke-width="4" />
<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" />
<rect x="642" y="555" rx="2" ry="2" width="16" height="64" fill="orangered" />
<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" />
<rect x="342" y="555" rx="2" ry="2" width="16" height="64" fill="orangered" />
<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" >
<!-- 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'));
           
            // 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;
};

yersinia

Woha, das sieht gut aus! Und ich bin überrascht, dass dies mit den verschiedenen Devices und readings so einfach geklappt hat. Oo
Testen kann ich zurzeit aber nicht. Werde ich später nachholen.

Die SVG referenziere ich im Widget erst in der update-function (dann, wenn ich sie wirklich benötige), nicht schon beim init - dies führte zumindest bei mir zu keinem Fehler.

Die SVG ins JS einzubinden halte ich nur dann für sinnvoll, wenn man diese dann auch dynamisch adaptiert. Eine statische SVG ins JS einzubinden um dann via DOM auf das SVG-Objekt zuzugreifen finde ich nicht so gut - ist irgendwie sinnfrei. Dann lieber das SVG dynamisch mit den aktualisierten Werten rendern. Dann könnte man sich auch die id sparen und mit uniqueIds arbeiten. ;)

Die SVG ansich hatte ich mit viewBox="0 0 1000 1000" versucht skalierbarer zu machen, vorher hatte sie eine feste größe von 1000x1000 mit ungewöhnlich großen rand....

Aber ich sehe, wir nähern uns schon dem Ziel an. :D
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

Waldmensch

#29
Ich habe den Beitrag/Code oben nochmal updated, das passte mit den pointer-speed und show-devpoint noch nicht. Viewbox habe ich auch korrigiert, das es jetzt zumindest nach links oben rutscht. Bin aber wirklich nicht der SVG Nerd.

Ich hatte die SVG Ladeprobleme auch im update(). Ich teste mit der Demo_Index.html, da wird ja quasi nix weiter geladen an readings. Daher läuft das init + update wahrscheinlich wesentlich schneller ab, als bei einem vollen FTUI. Das Problem war eindeutig reproduzierbar. Ich habe das selbst mit timeouts zu umgehen, war aber alles Mist

Das SVG intern ist von daher besser, als das man einfach keine separate Datei braucht. Das mit der ID habe ich beibehalten. Also auch wenn Du mehrere Hygrometer hast, werden die eindeutig von den widget instanzen addressiert, solange du unterschiedliche IDs vergibst.

Ich habe an den code etliche Kommentare gepackt, damit du siehst, was ich wo und warum gemacht hab.

ZitatDann lieber das SVG dynamisch mit den aktualisierten Werten rendern.
ich fürchte, das würde flackern