Hauptmenü

Raum-Klimamesser

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

Vorheriges Thema - Nächstes Thema

dt2510

Hat jemand schonmal was in der Art (siehe Foto) umgesetzt ? Kreuzen sich die Zeiger über der schraffierten Fläche, ist das Raumklima ideal.




Gisbert

Hallo dt2510,

interessante Idee, ich hab's nicht umgesetzt. Die Vorausetzung ist die Messung der Temperatur und der rel. Feuchte.
Dann gilt es den funktionalen Zusammenhang zwischen rel. Feuchte und Temperatur entsprechend der schraffierten Fläche zu erfassen und in einem DOIF oder in einem Perlcode wiederzugeben.
Ohne die Lösung zu haben, schätze ich, dass sich der Aufwand in Grenzen halten dürfte.

Viele​ Grüße​ Gisbert​
Aktuelles FHEM | PROXMOX | Fujitsu Futro S740 | Debian 12 | UniFi | Homematic, VCCU, HMUART | ESP8266 | ATtiny85 | Wasser-, Stromzähler | Wlan-Kamera | SIGNALduino, Flamingo Rauchmelder FA21/22RF | RHASSPY

Waldmensch

#2
Ich glaube, er meint eher die grafische Umsetzung in FTUI

Neulich hat doch wer mit Analogen Zeigerinstrumenten hantiert. Das kommt dem am nächsten. Die skalen und Schraffierung kann man ja in einem Hintergrundbild abbilden.


Gesendet von iPhone mit Tapatalk

dkreutz

Das Widget für ein "Analogmessgerät" gibt es hier, vielleicht kann man das ja adaptieren: https://forum.fhem.de/index.php/topic,102315.0.html
Raspberry Pi3B+ (Bullseye) / JeeLink868v3c (LaCrosse), nanoCUL433 (a-culfw V1.24.02), HM-MOD-UART (1.4.1), TEK603, MapleCUL / diverse Sensoren/Sender/Aktoren von Technoline, Intertechno, Shelly, Homematic und MAX!, Froggit Wetterstation, Luftdaten.info / Autor des fhem-skill für Mycroft.ai

dt2510

#4
Erstmal danke für die vielen Antworten. Eine grafische Umsetzung wäre natürlich schön (muss nicht als Analoginstrument sein) aber kein Muss.

Zitat von: Gisbert am 10 Oktober 2019, 19:21:04
Hallo dt2510,

interessante Idee, ich hab's nicht umgesetzt. Die Vorausetzung ist die Messung der Temperatur und der rel. Feuchte.
Dann gilt es den funktionalen Zusammenhang zwischen rel. Feuchte und Temperatur entsprechend der schraffierten Fläche zu erfassen und in einem DOIF oder in einem Perlcode wiederzugeben.
Ohne die Lösung zu haben, schätze ich, dass sich der Aufwand in Grenzen halten dürfte.

Viele​ Grüße​ Gisbert​

Der Zusammenhang ist recht einfach:

optimale Temperatur 17-23°C
optimale Feuchtigkeit 40-60~70% (je nach Messgerät)

Ansonsten eben zu kalt/warm/feucht/trocken.

Vorstellbar wäre die Anzeige von Temperatur und Feuchtigkeit in unterschiedlichen Farben

- hellblau: zu kalt
- rot: zu warm
- orange: zu trocken (Assoziation: Wüste ;) )
- blau: zu nass
- grün: optimal

Hintergrund der Frage ist die Darstellung auf meiner neuen FTUI Oberfläche. Ich plane jeden Raum mit einem Temperatur/Feuchtigkeitsmesser auszustatten und möchte die Messwerte daher auf der FTUI-Seite jedes Raumes an der gleichen Stelle - leicht erkennbar - darstellen.

Ich hab' mehrere Bilder angehängt: Startseite (dashboard.png), ein Beispielraum (noch leer - office.png) und diverse Umsetzungen in den restlichen Bildern. Vorschläge dürfen gerne im Beispielraum skizziert werden.

p.s.: die weißen Ränder im Screenshot kommen vom unsachgemäßen Zuschnitt und sind nicht Bestandteil des Layouts ;)

Eisix

Hallo,

hier ein Beispiel:


<!DOCTYPE html>
<html>
<head>
        <title>FHEM</title>
        <meta charset="UTF-8">
</head>
<body>
<header>BAD_OG</header>
<table border="0px" height="80%" width="100%">
<tr>
        <td>
        <div data-type="symbol"
                data-device="zBad_OG"
                data-get="state"
                data-states='["present","likely","unlikely","absent"]'
                data-icons='["fa-male","fa-male","fa-male half-transparent","fa-male transparent"]'
                data-colors='["#21a000","#21a000","#21a000","#21a000"]'
                class="top tiny compressed left"
        ></div>
<!--
        <div data-type="symbol"
                data-device="Heizung_BAD_OG"
                data-get="state"
                data-get-on="open"
data-get-off="closed"
                data-on-color="red"
                data-off-color="#21a000"
                data-hide-on="!open"
                data-hide-off="open"
data-hide="state"
                data-icon="oa-fts_window_1w_tilt"
                class="top tiny compressed left"
        ></div>
-->

        <div data-type="popup" data-width="450px" data-height="310px" class="">
        <div data-type="label"
                data-device="Sensor_BAD_OG"
                data-get="humidity"
                data-limits='["10","50","70"]'
                data-colors='["#bb6242","#21a000","#6699FF"]'
                data-unit=" %"
                data-part="1"
data-hide="humidity"
                data-hide-on=""
                class="top right"
        ></div>
                <div class="dialog">
                        <header>Luftfeuchtigkeit</header>
                        <div data-type="simplechart"
                                data-device="Sensor_BAD_OG"
                                data-logdevice="logdb"
                                data-columnspec="Sensor_BAD_OG:humidity:::"
                                data-minvalue="10"
                                data-maxvalue="100"
                                data-yticks="10"
                                data-height="250">
                        </div>
              </div>
      </div>
        </td>
</tr>
<tr>
        <td>
<div data-type="label"
data-device="Sensor_BAD_OG"
data-get="temperature"
data-limits='["20","22","25"]'
data-colors='["#6699FF","#21a000","#bb6242"]'
data-unit=" °C"
data-part="1"
class="tall bold inline"
></div>
        </td>
</tr>
<tr>
        <td>
        <div data-type="popup" data-width="450px" data-height="380px" class="inline">
<div data-type="symbol" data-icon="oa-edit_settings" class="inline"></div>
                <div class="dialog" style="background-color:#112026">
                        <header class="large">Handbetrieb</header>
<center>
<br>
                        <div data-type="spinner"
                                data-device="Heizung.Status_BAD_OG"
                                data-get="TempMan"
                                data-set="TempMan"
                                data-icon-left-color="blue"
                                data-icon-right-color="red"
                                data-step="0.5"
                                data-min="10"
                                data-max="30"
                                data-unit="°"
                                class="valueonly"
                        ></div>
<br>
</center>
                        <header class="large">Heizungs-Automatik</header>
<br>
<div class="">
<div class="left">
                <div data-type="spinner"
                        data-device="Heizung.Status_BAD_OG"
                        data-get="TempTag"
                        data-set="TempTag"
                        data-icon-left-color="blue"
                        data-icon-right-color="red"
                        data-step="0.5"
                        data-min="10"
                        data-max="30"
                        data-unit="°"
                        class="valueonly"
                ></div>
<br>
    <div data-type="label" class="inline bigger" >Tag:</div>
    <div data-type="datetimepicker"
data-device="Heizung.Status_BAD_OG"
data-get="Tag"
data-set="Tag"
data-step="5"
          data-datepicker="false"
data-format="H:i"
          class="inline bigger orange"
></div>
</div>
                        <div class="right">
                                <div data-type="spinner"
data-device="Heizung.Status_BAD_OG"
data-get="TempNacht"
data-set="TempNacht"
                                        data-icon-left-color="blue"
                                        data-icon-right-color="red"
                                        data-step="0.5"
                                        data-min="10"
                                        data-max="30"
                                        data-unit="°"
                                        class="valueonly"
                                ></div>
                                <br>
                                        <div data-type="label" class="inline bigger" >Nacht:</div>
                                        <div data-type="datetimepicker"
data-device="Heizung.Status_BAD_OG"
data-get="Nacht"
data-set="Nacht"
                                                data-step="5"
                                                data-datepicker="false"
                                                data-format="H:i"
                                                class="inline bigger orange"
                                        ></div>
                                </div>
                      </div>
<div class="">
<div class="inline">
<br>
<br>
        <div data-type="checkbox"
                                              data-device="Heizung.Status_BAD_OG"
                                                data-get="Party"
                                                data-set="Party"
class=""
        ></div>
      <div data-type="label" class="" >Party</div>
                                </div>
                                <div class="inline">
                                        <div data-type="checkbox"
                                                data-device="Heizung.Status_BAD_OG"
                                                data-get="Sommer"
                                                data-set="Sommer"
                                                class=""
                                        ></div>
                                        <div data-type="label" class="" >Sommer</div>
                                </div>

<div class="inline">
        <div data-type="checkbox"
                                                data-device="Heizung.Status_BAD_OG"
                                                data-get="abwesend"
                                                data-set="abwesend"
class=""
        ></div>
      <div data-type="label" class="" >abwesend</div>
                                </div>
                                <div class="inline">
        <div data-type="checkbox"
                                                data-device="Heizung.Status_BAD_OG"
                                                data-get="Urlaub"
                                                data-set="Urlaub"
class=""
        ></div>
      <div data-type="label" class="" >Urlaub</div>
                                </div>
                                <div class="inline">
        <div data-type="checkbox"
                                                data-device="Heizung.Status_BAD_OG"
                                                data-get="Frost"
                                                data-set="Frost"
class=""
        ></div>
      <div data-type="label" class="" >Frost</div>
                        </div>
                                <div class="inline">
                                        <div data-type="checkbox"
                                                data-device="Heizung.Status_BAD_OG"
                                                data-get="Boost"
                                                data-set="Boost"
                                                class=""
                                        ></div>
                                        <div data-type="label" class="" >Boost</div>
                                </div>

                        </div>
</div>
</div>
        <div data-type="popup" data-width="750px" data-height="350px" class="inline">
<div data-type="symbol" data-icon="fa-area-chart" class="inline"></div>
                <div class="dialog">
                        <header>TEMPERATURE - BAD_OG</header>
                        <div data-type="chart"
                                data-logdevice='["logdb","logdb","logdb","logdb"]'
                                data-logfile="HISTORY"
                                data-columnspec='["Sensor_aussen:CleanTemp:::","EinschaltTemp_BAD_OG:state","Sensor_BAD_OG:CleanTemp:::","Heizung_BAD_OG:state:0::$val=($val=~\\x22off\\x22?0:1)"]'
                                data-style='["ftui l3","ftui l4","ftui l0fill","ftui l1fill"]'
                                data-ptype='["lines","steps","lines","steps"]'
                                data-uaxis='["primary","primary","primary","secondary"]'
                                data-legend='["Aussen","Soll-Temp","Ist-Temp","Heizung"]'
                                data-yunit="°C"
                                data-ytext="Temperature"
                                data-minvalue="auto"
                                data-maxvalue="auto"
                                data-minvalue_sec="0"
                                data-maxvalue_sec="1.1"
                                data-height="300"
                                data-width="700"
                                data-daysago_start="3"
                                data-daysago_end="-1"
                                data-crosshair="true"
                                data-cursorgroup="1"
                                data-scrollgroup="1"
                                data-showlegend="false"
                                data-yticks="auto"
                                data-yticks_sec='[[0,"aus"],[1,"an"]]'
                                data-xticks="auto">
                        </div>
</div>
</div>
<div data-type="switch"
data-device="Heizung.Status_BAD_OG"
data-cmd="set"
data-get="Heizung"
data-set="Heizung"
data-states='["manuell","automatic","boost","off"]'
data-set-states='["automatic","boost","off","manuell"]'
data-icons='["oa-sani_heating_manual","oa-sani_heating_automatic","fs-sani_heating_boost","fs-general_aus"]'
data-colors='["#5EDAFF","#21a000","#FF5E5E","grey"]'
data-background-color="Heizung_BAD_OG:stateColor"
class="inline nocache"
></div>
        </td>
</tr>
</table>
</body>
</html>



Ist auch mit Anwesenheit, Fenster auf/zu (ist auskommentiert) und Heizungssteuerung.

Gruß
Eisix

dt2510

#6
Ich beschränke mich wohl auf eine Textanzeige mit Icons. Aktuell habe ich es so umgesetzt:

Aufruf auf der Seite
<div data-type="include" data-url="modules/moduleRoomClimate.inc" data-parameter='{"dataTemperatureDevice":"FGSD002_ID31","dataHumidityDevice":"PHPAT02_ID32"}'></div>

Raumklima Modul
<div class="module">
  <table width="100%" height="50vh" border="0">
    <colgroup><col width="20%"><col width="80%"></colgroup>
    <tr class="dim20">
      <td class="module_icon"><div data-type="include" data-url="symbols/symbol.inc" data-parameter='{"dataIcon":"fs-temperature_humidity","dataColor":"symbol_ok"}'></div></td>
      <td class="paragraph text_right">Raumklima</td>
    </tr>
    <tr>
      <td class="text_center"></div></td>
      <td>
        <table width="100%" height="50vh" border="0">
          <colgroup><col width="75%"><col width="25%"></colgroup>
          <tr style="height:4vh;">
            <td class="text_3 text_center"><div data-type="include" data-url="labels/labelTemperature.inc" data-parameter='{"dataDevice":"dataTemperatureDevice"}'></div></td>
            <td class="module_icon"><div data-type="include" data-url="symbols/symbolTemperature.inc" data-parameter='{"dataDevice":"dataTemperatureDevice"}'></div></td>
          </tr>
          <tr style="height:4vh;">
            <td class="text_3 text_center"><div data-type="include" data-url="labels/labelHumidity.inc" data-parameter='{"dataDevice":"dataHumidityDevice"}'></div></td>
            <td class="module_icon"><div data-type="include" data-url="symbols/symbolHumidity.inc" data-parameter='{"dataDevice":"dataHumidityDevice"}'></div></td>
          </tr>
        </table>
      </td>
    </tr>
  </table>
</div>


Temperatur Label
<div data-type="label"
     data-device="dataDevice"
     data-get="temperature"
     data-part="1"
     data-unit="%B0C%0A"
     data-limits="[-999,20,26]"
     data-colors='["temperature_cold","temperature_ok","temperature_hot"]'>
</div>


Temperatur Symbol
<div class="autohide"
     data-type="symbol"
     data-device="dataDevice"
     data-get="temperature"
     data-part="1"
     data-limits="[-999,20,26]"
     data-icons='["fa-arrow-down","","fa-arrow-up"]'
     data-colors='["symbol_ok","symbol_ok","symbol_ok"]'>
</div>


Luftfeuchtigkeit Label
<div data-type="label"
     data-device="dataDevice"
     data-get="humidity"
     data-part="1"
     data-unit="% rH"
     data-limits="[0,40,60]"
     data-colors='["humidity_dry","humidity_ok","humidity_wet"]'>
</div>


Luftfeuchtigkeit Symbol
<div class="autohide"
     data-type="symbol"
     data-device="dataDevice"
     data-get="humidity"
     data-part="1"
     data-limits="[0,40,60]"
     data-icons='["fa-arrow-down","","fa-arrow-up"]'
     data-colors='["symbol_ok","symbol_ok","symbol_ok"]'>
</div>


Farbangaben und Klassen sind in einer eigenen css-Datei definiert.

Sind beide Geräte angegeben wird Temperatur und Luftfeuchtigkeit angezeigt sowie ein Pfeil nach oben/unten, falls der jeweilige Wert vom Optimalwert abweicht.
Fehlt ein Gerät (ich habe nicht überall Temperatur und Luftfeuchtigkeits Sensoren) ist das zugehörige Label leer und das Symbol wird per autohide ausgeblendet.

Folgendes möchte ich gerne noch umsetzen - hab' aber leider noch keine Lösung gefunden:


  • Anzeige von "--°C" bzw. "--%rH" wenn ein Gerät nicht angegeben ist
  • Anzeige eines Smileys (links im Modul)

  • :) wenn beide Werte optimal sind
  • :-\ wenn nur 1 Wert optimal ist
  • :( wenn kein Wert optimal ist

Fehlt ein Gerät soll auch nur :) oder :( angezeigt werden - fehlen beide soll gar kein Smiley angezeigt werden.

Was noch nicht umgesetzt wurde ist die Heizungssteuerung (kommt noch).

dt2510

Problem 1 ist schon gelöst.

Ich habe ein dummy "NoDevice" angelegt und die Readings "temperature" und "humidity" auf "--" gesetzt.

Im Label wird jetzt korrekt "--°C" bzw. "--%rH" in der Standardfarbe angezeigt und die Symbole werden per classchanger versteckt (hier im Beispiel für die Luftfeuchtigkeit)

<div class="container"
     data-type="classchanger"
     data-device="dataDevice"
     data-get="humidity"
     data-get-off="--"
     data-off-class="hide">
  <div data-type="symbol"
       data-device="dataDevice"
       data-get="humidity"
       data-part="1"
       data-limits="[0,40,60]"
       data-icons='["fa-arrow-down","","fa-arrow-up"]'
       data-colors='["symbol_ok","symbol_ok","symbol_ok"]'>
  </div>
</div>


Der Aufruf erfolg dann z.B. so
<div data-type="include" data-url="modules/moduleRoomClimate.inc" data-parameter='{"dataTemperatureDevice":"FGSD002_ID31","dataHumidityDevice":"NoDevice"}'></div>

Fehlen nur noch die Smileys ... ich könnte per 99_myUtils.pm Funktion den Wert 0,1 oder 2 ermitteln - aber wie zeige ich das als Symbol an ?

Ulm32b

Zitat von: dt2510 am 15 Oktober 2019, 16:52:39
Fehlen nur noch die Smileys ... ich könnte per 99_myUtils.pm Funktion den Wert 0,1 oder 2 ermitteln - aber wie zeige ich das als Symbol an ?

Mit dem Symbol-Widget (https://wiki.fhem.de/wiki/FTUI_Widget_Symbol) via data-states und data-icons (wobei ich jetzt nicht genau weiß, ob es die gewünschten Icons über einen der verfügbaren Icon-Sets schon gibt).


dt2510

Zitat von: Ulm32b am 15 Oktober 2019, 17:25:23
Mit dem Symbol-Widget (https://wiki.fhem.de/wiki/FTUI_Widget_Symbol) via data-states und data-icons (wobei ich jetzt nicht genau weiß, ob es die gewünschten Icons über einen der verfügbaren Icon-Sets schon gibt).

Die Icons gibt es, aber wie zeige ich einen Funktions-Rückgabewert an ? Ich hab' hier ja kein Device oder Reading.
Als Workaround müsste ich einen Dummy je Raum für Temperatur und Feuchtigkeit anlegen - oder auch eine Struktur mit allen beteiligten Geräten (Temperatur, Luftfeuchtigkeit, Heizkörperthermostate, Fenster, ...), die könnte ich relativ einfach erweitern ...

Waldmensch

Warum klaust Du Dir nicht einfach ein bisschen HTML von hier? http://esp8266.fancon.cz/esp8266-web-hygrometer-dht11-arduino/esp8266-web-hygrometer-dht11-arduino.html


Gesendet von iPhone mit Tapatalk

dt2510

Zitat von: Waldmensch am 15 Oktober 2019, 18:49:36
Warum klaust Du Dir nicht einfach ein bisschen HTML von hier? http://esp8266.fancon.cz/esp8266-web-hygrometer-dht11-arduino/esp8266-web-hygrometer-dht11-arduino.html


Gesendet von iPhone mit Tapatalk

Mir ging es hauptsächlich darum, auf einen Blick zu sehen, ob das Klima im Idealbereich liegt (schraffierte Fläche über der sich die Zeiger kreuzen). Mit der Smiley-Variante komme ich allerdings genau so gut klar wie mit einem Analoginstrument (zumal sich die Zeiger in deinem Beispiel auch nicht kreuzen).
Trotzdem danke für den Link, wer weiß ob man ihn vielleicht mal gebrauchen kann...

Waldmensch

Na es ging ja eher um ,,gucken" wie es gemacht wird. Da eine zweite Skala, zweiten Zeiger und ein passendes Hintergrundbild sollte ja machbar sein.


Gesendet von iPhone mit Tapatalk

Waldmensch

Ich habe mal das oben verlinkte Beispiel modifiziert, das zumindes schon mal 2 funktionale Zeiger drin sind. Die Zeigerwinkel werdem ganz unten im ersten Wert des jeweiligen rotate gesetzt. Den Code unten komplett in eine Textdatei packen, als SVG abspeichern und im Browser laden

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

<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>
<g id="PO1">
<line stroke-width="2" x1="650" y1="600" x2="650" y2="1000" 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>

<g id="PO2">
<line stroke-width="2" x1="350" y1="600" x2="350" y2="1000" 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>

<g>
<line stroke-width="4" id="M1" x1="650" y1="950" x2="650" y2="970"/>
</g>

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

<g>
<line stroke-width="4" id="M2" x1="350" y1="950" x2="350" y2="970"/>
</g>

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

</defs>

<g id="T1" stroke="black">
<use xlink:href="#Z1" transform="rotate(92,650,600)"/>
<use xlink:href="#Z1" transform="rotate(96,650,600)"/>
<use xlink:href="#Z1" transform="rotate(100,650,600)"/>
<use xlink:href="#Z1" transform="rotate(104,650,600)"/>
<use xlink:href="#Z1" transform="rotate(108,650,600)"/>
<use xlink:href="#Z1" transform="rotate(112,650,600)"/>
<use xlink:href="#Z1" transform="rotate(116,650,600)"/>
<use xlink:href="#Z1" transform="rotate(120,650,600)"/>
<use xlink:href="#Z1" transform="rotate(124,650,600)"/>
<use xlink:href="#Z1" transform="rotate(128,650,600)"/>
<use xlink:href="#Z1" transform="rotate(132,650,600)"/>
<use xlink:href="#Z1" transform="rotate(136,650,600)"/>
<use xlink:href="#Z1" transform="rotate(140,650,600)"/>
<use xlink:href="#Z1" transform="rotate(144,650,600)"/>
<use xlink:href="#Z1" transform="rotate(148,650,600)"/>
<use xlink:href="#Z1" transform="rotate(152,650,600)"/>
</g>

<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="#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="#Z2" transform="rotate(232,350,600)"/>
<use xlink:href="#Z2" transform="rotate(236,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="#Z2" transform="rotate(252,350,600)"/>
<use xlink:href="#Z2" transform="rotate(256,350,600)"/>
<use xlink:href="#Z2" transform="rotate(260,350,600)"/>
<use xlink:href="#Z2" transform="rotate(264,350,600)"/>
<use xlink:href="#Z2" transform="rotate(268,350,600)"/>
</g>

<g stroke="red" stroke-width="1" fill="none">
<use xlink:href="#PO1" transform="rotate(110,650,600)"/>
</g>
<g stroke="red" stroke-width="1" fill="none">
<use xlink:href="#PO2" transform="rotate(230,350,600)"/>
</g>

</svg>

Waldmensch

Mangels SVG Skills komme ich nicht weiter und höre hier erstmal auf. Vielleicht kann jemand da die gebogenen und rotierten Texte reinbasteln. Der Code unten ist eine komplette HTML Datei. Mit den 2 Feldern oben kann man temperatur und Feuchtigkeit setzen. Vielleicht kann ja jemand ein Widget draus machen.

<html>
<head>
<style>
#hygro {
height:100%;
width:100%;
}
</style>
<script>
function setptr1() {
var inputval = parseInt(document.getElementById("valuepo1").value) *1.5;
console.log(inputval + 92);
var PO1 = document.getElementById("PO1a");
PO1.setAttribute("transform", "rotate(" + (inputval + 92) + ",650,600)");
}
function setptr2() {
var inputval = parseInt(document.getElementById("valuepo2").value) /2;
console.log(268 - inputval);
var PO2 = document.getElementById("PO2a");
PO2.setAttribute("transform", "rotate(" + (268 - inputval) + ",350,600)");
}
</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>

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

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

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

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

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

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

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

<g font-family="arial" font-size="20" font-weight="normal" font-style="normal" stroke="black" fill="black" >
<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>
<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>

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

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

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

</svg>

</body>
</html>

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


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

ch.eick

Das sollte sicher unterschwellig ein Anagramm für pah sein ;-)

Gesendet von meinem SM-G930F mit Tapatalk

RPI4; Docker; CUNX; Eltako FSB61NP; SamsungTV H-Serie; Sonos; Vallox; Luxtronik; 3x FB7490; Stromzähler mit DvLIR; wunderground; Plenticore 10 mit BYD; EM410; SMAEM; Modbus TCP
Contrib: https://svn.fhem.de/trac/browser/trunk/fhem/contrib/ch.eick

Waldmensch


Ein Anemometer ist dazugekommen. Konfiguration s.u.

Beispielconfig vom Screenshot:
<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>
<li data-row="6" data-col="7" data-sizex="6" data-sizey="4">
<header>ANEMOMETER</header>
  <div
data-type = "gauge"
data-view = "anemometer"
data-get-wind-speed = "Wetterstation:windkmh"
data-get-wind-direction = "Wetterstation:windDirection"
data-wind-unit = "km/h"
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>

Octopus180

Moin

Erstmal muss ich ein Lob auszusprechen, sehr schöne Arbeit die ihr hier leistet.

Meine Frage wäre, brauch ich nur die JS- Datei in das entsprechende Verzeichnis kopieren und dann meine Tablet UI Seite erstellen?

Ich bin leider aus den ganzen Beiträgen nicht so richtig schlau geworden.

Danke für die Hilfe.

Gruß Peter

Waldmensch

Genau. Nur die JS Datei ins JS Verzeichnis des FTUI kopieren. Config Beispiel für die index Seite habe ich in jedem Beitrag. Im Prinzip musst Du nur Deine Readings einsetzen, dann sieht es aus wie auf den Screenshots. Die data-get-wind-direction erwartet einen Winkelwert von 0-360 wobei 0 Nord ist.


Gesendet von iPhone mit Tapatalk

Octopus180

Ok, Danke

Dann werde ich mal versuchen es umzusetzen.

Gruß

Waldmensch

Ich wollte schon immer eine Visualisierung meiner PV Anlage haben, mit der man den Gesamtzustand auf einen Blick erfassen kann. Einen Prototypen habe ich fertig. Meinungen? Fällt noch jemandem was ein?
Im Screenshot:
- 1 = Erzeugung
- 2 = Verbrauch
- 3 = Batterie

Die Punktkette scrollt. Die soll abhängig von einem Reading "charge|discharge|standby" im Uhrzeigersinn, gegen den Uhrzeigersinn drehen oder ausgeblendet werden

Waldmensch

- view "photovoltaic" eingebaut
- Animationen vom Javacode ins SVG verlagert. (reduziert CPU Load erheblich)

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-get-temperature = "Wetterstation:temperatureInside"
data-get-humidity = "Wetterstation:humidityInside"
data-show-devpoint= "1"
data-pointer-speed = "20"
data-pointer-widths = '["0.0","0"]'
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 = '["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="6" data-col="1" data-sizex="6" data-sizey="4">
<header>CLOCK</header>
  <div
data-type = "gauge"
data-view = "clock"
data-clock-timezone = "0"
data-color-scale = "red"
data-color-background = "black"
data-pointer-colors = '["red","red","red"]'

data-size = "300"
style=""
class="top-space">
</div>
</li>
<li data-row="6" data-col="7" data-sizex="6" data-sizey="4">
<header>ANEMOMETER</header>
  <div
data-type = "gauge"
data-view = "anemometer"
data-get-wind-speed = "Wetterstation:windkmh"
data-get-wind-direction = "Wetterstation:windDirection"
data-wind-unit = "km/h"
data-pointer-speed = "10"
data-pointer-widths = '["3"]'
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="13" data-sizex="6" data-sizey="4">
<header>PHOTOVOLTAIC</header>
  <div
data-type = "gauge"
data-view = "photovoltaic"
data-color-scale = "red"
data-color-background = "black"
data-pointer-colors = '["red","red","red"]'
data-get-pv-soc = "Solarwatt:Bat_SoC"
data-get-pv-generation = "Wechselrichter1:ProdTotal"
data-get-pv-consumption = "ESPEasy_sonoff_7_Watt:StromverbrauchAktuell"
data-get-pv-batstate = "Solarwatt:Bat_State"
data-pointer-speed = "10"
data-size = "300"
style=""
class="top-space">
</div>
</li>

Izmir Schlecht

Schaut euch auch mal die Umsetzung unter: https://github.com/HanSolo/SteelSeries-Canvas an.

Ein Beispiel dafür findet ihr unter: http://bbs.wing-willich.de/gauge/gauges_meteo.htm

Wäre toll, wenn sich das als Widget einbinden lassen würde.

Prof. Dr. Peter Henning

Sehr Retro. Es soll ja auch Leute geben, die Internetradios in Holzgehäuse einbauen...

ZitatWäre toll, wenn sich das als Widget einbinden lassen würde.
Klar. Tipp: JavaScript lernen und machen.

LG

pah