Ankündigung

Einklappen
Keine Ankündigung bisher.

Plotly_graph mit State-Attributen befüllen

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

    #31
    soooo... da ich mit der VErschiebung auf der x-Achse nicht weiterkomme, habe ich mal an die Berechnunh der SCOP Zahl gemacht.
    Ich habe deinen Tempalte-Sensor als Vorlage genommen und versucht daraus den SCOP-Sensor zu bauen...

    Code:
      - platform: template
    
        sensors:
        
          vitocal_domestic_hot_water_scop_stats:
            unique_id: vitocal_dhw_scop_stats
            value_template: "{{ now().date() }}"
            attribute_templates:
    
              months_scop: >-
                {# -- Rohdaten für die Berechnung der SCOP laden -- #}
                {%- set data_kwh_input = state_attr('sensor.vitocal_domestic_hot_water_stats', 'months_combined') -%}
                {%- set data_kwh_output = state_attr('sensor.vitocal_domestic_hot_water_output_stats', 'months_combined') -%}
    
                {# -- Namespace zur Sammlung der Einträge -- #}
                {%- set result = namespace(entries=[]) -%}
    
                {# Berechnung der SCOP #}
                {%- for key in data_kwh_output.keys() | union(data_kwh_input.keys()) -%}
                  {%- set val1 = data_kwh_output.get(key) -%}
                  {%- set val2 = data_kwh_input.get(key) -%}
                  {%- if val1 is not none and val2 is not none and val2 != 0 -%}
                    {%- set quotient = val1 / val2 -%}
                  {%- else -%}
                    {%- set quotient = 0 -%}
                  {%- endif -%}
                  {%- set entry = {"date" : key, "value" : quotient | float(0)} -%}
                  {%- set result.entries = result.entries + [entry] -%}
                {%- endfor -%}
    
                {# -- Ergebnis als valides JSON-Array ausgeben -- #}
                {{ result.entries | tojson }}​
    aber da muss noch ein Denkfehler drin sein... es gibt kein Ergebnis

    Kommentar


      #32
      das Problem mit der Verschiebung konnte ich jetzt "lösen".
      Ich habe den timestamp von yyyy-mm-ddT23:59:59 auf yyyy-mm-ddT00.00.01 geändert es ist nach wie vor der selbe Tag aber jetzt wird es korrekt angezeigt.

      Kommentar


        #33
        Uff - darauf, dass Plotly die X-Achsenbeschriftung fälschlicherweise um einen Tag nach vorn verschiebt, wenn der letzte timestamp um 23:59:59 ist, wäre ich nie gekommen. Kenne solche Effekte sonst nur aus Zeitzonenverschiebungen. Muss interessehalber mal nachsehen, was mit 12:00, 15:00 oder 21:00 ist - ist ja fix geändert.

        SCOP-Werte stelle ich mal nach, werd ich heute aber nicht mehr schaffen.

        /tom

        Kommentar


          #34
          Zitat von Tom Bombadil Beitrag anzeigen
          SCOP-Werte stelle ich mal nach, werd ich heute aber nicht mehr schaffen.
          So, heute hatte ich mal Zeit, mir die Sache anzuschauen:
          • Den Sinn von dem hier verstehe ich nicht - wozu?
            | union(data_kwh_input.keys()
          • Bei Zuweisungen von Werten immer daran danken, dass Sensorattribute (inkl. status) immer Strings zurückliefern - und mit Text kann die Jinja Template Engine nicht rechnen. Daher wird dann am Ende der Zuweisung ein "| int" oder "| float" gemacht - das fehlt oben im Code recht häufig (zB hier in den beiden ersten Zeilen):
            {%- set val1 = data_kwh_output.get(key) hier | float -%}
            {%- set val2 = data_kwh_input.get(key) hier | float-%}
            {%- set quotient = val1 / val2 -%}
          Falls Du mir mal aktuelle Wertepaare aller Attribute schickst, kann ich versuchen, tiefer einzusteigen. Kann es mangels Daten mal wieder nicht im Detail nachstellen.

          /tom

          Kommentar


            #35
            ich habe vor einigen Jahren, bei meinem ersten Haus, einiges mit javascript und IOBrocker gemacht. Dieses mal wollte ich es "richtig" machen und habe alles mit KNX gemacht und bin auf Home Assistant umgestiegen. Jinja verstehe ich noch nicht ganz und versuche das ein oder andere mit ChatGPT zu erarbeiten.

            hier mal die Werte Paare

            sensor.vitocal_domestic_hot_water_output_stats
            Code:
            | [
            {
            "date": "2025-07-01T00:00:01",
            "value": 5.9
            },
            {
            "date": "2025-07-02T00:00:01",
            "value": 8.7
            },
            {
            "date": "2025-07-03T00:00:01",
            "value": 5.3
            },
            {
            "date": "2025-07-04T00:00:01",
            "value": 5.4
            },
            {
            "date": "2025-07-05T00:00:01",
            "value": 9.5
            },
            {
            "date": "2025-07-06T00:00:01",
            "value": 6.3
            },
            {
            "date": "2025-07-07T00:00:01",
            "value": 6.8
            },
            {
            "date": "2025-07-08T00:00:01",
            "value": 6.5
            },
            {
            "date": "2025-07-09T00:00:01",
            "value": 7.3
            },
            {
            "date": "2025-07-10T00:00:01",
            "value": 5.2
            },
            {
            "date": "2025-07-11T00:00:01",
            "value": 5.4
            },
            {
            "date": "2025-07-12T00:00:01",
            "value": 4.9
            },
            {
            "date": "2025-07-13T00:00:01",
            "value": 15.1
            },
            {
            "date": "2025-07-14T00:00:01",
            "value": 0
            },
            {
            "date": "2025-07-15T00:00:01",
            "value": 5.6
            },
            {
            "date": "2025-07-16T00:00:01",
            "value": 4.9
            },
            {
            "date": "2025-07-17T00:00:01",
            "value": 5.7
            },
            {
            "date": "2025-07-18T00:00:01",
            "value": 5.9
            },
            {
            "date": "2025-07-19T00:00:01",
            "value": 7.8
            },
            {
            "date": "2025-07-20T00:00:01",
            "value": 15
            },
            {
            "date": "2025-07-21T00:00:01",
            "value": 0
            },
            {
            "date": "2025-07-22T00:00:01",
            "value": 4.2
            },
            {
            "date": "2025-07-23T00:00:01",
            "value": 6.4
            },
            {
            "date": "2025-07-24T00:00:01",
            "value": 7.7
            },
            {
            "date": "2025-07-25T00:00:01",
            "value": 6.2
            },
            {
            "date": "2025-07-26T00:00:01",
            "value": 8.6
            },
            {
            "date": "2025-07-27T00:00:01",
            "value": 6.2
            },
            {
            "date": "2025-07-28T00:00:01",
            "value": 6.2
            },
            {
            "date": "2025-07-29T00:00:01",
            "value": 12.8
            },
            {
            "date": "2025-07-30T00:00:01",
            "value": 4.7
            },
            {
            "date": "2025-07-31T00:00:01",
            "value": 6
            },
            {
            "date": "2025-08-01T00:00:01",
            "value": 9.7
            },
            {
            "date": "2025-08-02T00:00:01",
            "value": 4
            },
            {
            "date": "2025-08-03T00:00:01",
            "value": 0
            }
            ]​ |
            sensor.vitocal_domestic_hot_water_stats
            Code:
            |[
            {
            "date": "2025-07-01T00:00:01",
            "value": 1.6
            },
            {
            "date": "2025-07-02T00:00:01",
            "value": 2
            },
            {
            "date": "2025-07-03T00:00:01",
            "value": 1.2
            },
            {
            "date": "2025-07-04T00:00:01",
            "value": 1.3
            },
            {
            "date": "2025-07-05T00:00:01",
            "value": 1.9
            },
            {
            "date": "2025-07-06T00:00:01",
            "value": 1.4
            },
            {
            "date": "2025-07-07T00:00:01",
            "value": 1.6
            },
            {
            "date": "2025-07-08T00:00:01",
            "value": 1.6
            },
            {
            "date": "2025-07-09T00:00:01",
            "value": 1.9
            },
            {
            "date": "2025-07-10T00:00:01",
            "value": 1.3
            },
            {
            "date": "2025-07-11T00:00:01",
            "value": 1.4
            },
            {
            "date": "2025-07-12T00:00:01",
            "value": 1.2
            },
            {
            "date": "2025-07-13T00:00:01",
            "value": 3.4
            },
            {
            "date": "2025-07-14T00:00:01",
            "value": 0
            },
            {
            "date": "2025-07-15T00:00:01",
            "value": 1.3
            },
            {
            "date": "2025-07-16T00:00:01",
            "value": 1.3
            },
            {
            "date": "2025-07-17T00:00:01",
            "value": 1.4
            },
            {
            "date": "2025-07-18T00:00:01",
            "value": 1.5
            },
            {
            "date": "2025-07-19T00:00:01",
            "value": 1.4
            },
            {
            "date": "2025-07-20T00:00:01",
            "value": 2.9
            },
            {
            "date": "2025-07-21T00:00:01",
            "value": 0
            },
            {
            "date": "2025-07-22T00:00:01",
            "value": 1
            },
            {
            "date": "2025-07-23T00:00:01",
            "value": 1.7
            },
            {
            "date": "2025-07-24T00:00:01",
            "value": 1.6
            },
            {
            "date": "2025-07-25T00:00:01",
            "value": 1
            },
            {
            "date": "2025-07-26T00:00:01",
            "value": 1.8
            },
            {
            "date": "2025-07-27T00:00:01",
            "value": 1.2
            },
            {
            "date": "2025-07-28T00:00:01",
            "value": 1.4
            },
            {
            "date": "2025-07-29T00:00:01",
            "value": 3.3
            },
            {
            "date": "2025-07-30T00:00:01",
            "value": 1.3
            },
            {
            "date": "2025-07-31T00:00:01",
            "value": 1.5
            },
            {
            "date": "2025-08-01T00:00:01",
            "value": 2.6
            },
            {
            "date": "2025-08-02T00:00:01",
            "value": 1.1
            },
            {
            "date": "2025-08-03T00:00:01",
            "value": 0
            }
            ]​
            |

            Kommentar


              #36
              Basierend auf Deinen Daten und der obigen Formel (hab weder das eine noch das andere geprüft): So?

              Code:
                    vitocal_domestic_hot_water_scop_stats:
                      unique_id: vitocal_dhw_scop_stats
                      value_template: "{{ now().date() }}"
                      attribute_templates:
              
                        months_scop: >-
                          {# Rohdaten laden #}
                          {% set data_input = state_attr('sensor.vitocal_domestic_hot_water_stats', 'months_combined') %}
                          {% set data_output = state_attr('sensor.vitocal_domestic_hot_water_output_stats', 'months_combined') %}
              
                          {# Hilfsobjekt für Ergebnisliste vorbereiten #}
                          {% set result = namespace(entries=[]) %}
              
                          {# Schleife über alle Einträge der Eingangsdaten #}
                          {% for input_entry in data_input %}
              
                            {# Variablen vorbereiten #}
                            {% set date = input_entry.date %}
                            {% set output_entry = data_output | selectattr('date', 'equalto', date) | list | first %}
                            {% set input_value = input_entry.value | float(0) %}
                            {% set output_value = output_entry.value | float(0) if output_entry is defined else 0 %}
              
                            {# die eigentliche Berechnung #}
                            {% set scop = (output_value / input_value) if input_value > 0 else 0 %}
              
                            {# Ergebnisliste ergänzen #}
                            {% set entry = {"date": date, "value": scop | round(2)} %}
                            {% set result.entries = result.entries + [entry] %}
              
                          {% endfor %}
              
                          {# Ergebnis des Tamplates zwischen {{ }} ausgeben #}
                          {{ result.entries | tojson }}
              Zu prüfen wie üblich im Template Checker mit:

              Code:
              sensor.vitocal_domestic_hot_water_stats, Attribut 'months_combined':
              {{ state_attr('sensor.vitocal_domestic_hot_water_stats', 'months_combined') }}
              sensor.vitocal_domestic_hot_water_output_stats, Attribut 'months_combined':
              {{ state_attr('sensor.vitocal_domestic_hot_water_output_stats', 'months_combined') }}
              sensor.vitocal_domestic_hot_water_scop_stats, Attribut 'months_scop':
              {{ state_attr('sensor.vitocal_domestic_hot_water_output_stats', 'months_combined') }}​
              Anmerkung: Nach vielen Template-Spielereien kann es Dir passieren (wie gerade bei mir hier), dass einzelne Template-Sensoren beim Start nicht mehr gefunden werden und er neue anlegt (hinten mit _2, _3 usw gekennzeichnet). Dann sucht man sich einen Wolf, warum es nicht geht - aber der eingebaute Jinja2 Template Editor ist Dein Freund, indem man dort mal die state_attr der Eingangswerte abfragt. Selbst das ganze Template ließe sich da testen.

              Also ab und zu mal in Einstellungen -> Geräte & Dienste -> Entitäten nach verwaisten Entitäten filtern - diese markieren, rauslöschen und neu starten. Sonst versucht man auf Dinge zuzugreifen, die vielleicht mittlerweile einen ganz anderen Namen haben.

              Viel Erfolg!

              /tom

              Kommentar


                #37
                hi Tom,

                bin heute mal dazu gekommen es zu testen. Das Template läuft super und die werde passen.

                grafik.png

                jetzt muß ich noch die zweite Y-Achse auf 0 in höhe der x-Achse bringen und die Werte mit NULL rausfiltern.

                Code:
                filters:
                  filter: i>0
                klappt leider nicht.

                Was mir aufgefallen ist, dass natürlich der ZEitstrahl sich verschiebt. Man kann nur den Bereich sehen der übergeben wird also die 2 Monate.
                Nach etwas suchen habe ich eine Abfrage über den CAN-Bus gefunden, der mir die aktuellen Tageswert liefert. Damit kann ich die Were nun fortlaufend aufzeichnen.

                nochmals Vielen Dank für deine Arbeit...

                Kommentar


                  #38
                  Sieht super aus - freut mich, dass es läuft!

                  /tom

                  Kommentar


                    #39
                    Nachtrag: Denk dran - Recorder zeichnet die Werte nur für ein paar Tage auf (glaub, es waren standardmässig 8 Tage). Wenn Du die Daten vom CAN-Bus langfristig aufzeichnen willst, musst Du das entsprechend einstellen.

                    /tom

                    Kommentar


                      #40
                      Ich glaube langsam Plotly mag mich nicht. Ich lese nun die täglichen Werte per MQTT aus. Das klappt auch super.
                      Aber nun bekomme ich die Daten nicht vernüftig als Balkendiagramm dargestellt.

                      grafik.png

                      in der Plotly card
                      grafik.png

                      die werte in Plotly passen nicht... ich habe das Gefühl, dass der Mittelwert pro Tag angezeigt wird. Ich habe noch nicht ganz verstanden, wie ich die Daten in Plotly noch aufbereitet werden müssen.

                      Kommentar


                        #41
                        So, ich habe jetzt mal eine Weile probiert aber irgendwie bin ich mit dem Ergebnis noch nicht so ganz zufrieden.
                        Wenn ich für die SCOP-Zahl Anzeige im Diagramm "period: day" eingebe, bekomme ich einen Durchschnittswert über den ganzen Tag angezeigt.
                        Kann ich irgendwie einrichten, dass ich immer den aktuellen Wert angezeigt bekomme.

                        grafik.png

                        Kommentar


                          #42
                          Ich nehme mal an, das ist die 'neue' Methode, wo Du die Daten jetzt per MQTT abrufst - oder woher kommen die vielen Datenpunkte pro Tag?
                          Weil: Die 'alte' Version liefert ja täglich nur zwei Werte, aus denen man denen man SCOP berechnen kann.

                          Da hilft dann nur, den letzten ermittelten Tageswert aus den aus der Datenbank angelieferten Daten zu filtern - hab ich so aber bisher noch nicht gebraucht. max/min machen hier ja keinen Sinn - der letzte ermittelte Wert kann ja durchaus auch unter max() liegen, wenn der Gesamt-SCOP über den Tag wieder gefallen ist.

                          Ich sehe auf Anhieb 4 Möglichkeiten:
                          • weiter 'on the fly' mit der alten Methode berechnen (die 'willste nicht' Methode),
                          • SCOP per Automation nur einmalig um 23:59:45 ermitteln und einmalig wegschreiben (die 'saubere' Methode, da 'gute Daten'; ggf extra Entity),
                          • oder einen JavaScript formulierten Filter in Plotly auf den letzten angelieferten Eintrag setzen (die 'funktioniert, aber nur für GUI/Plotly' Methode).
                          • [Edit:] Oder, wenn's wirklich nur um die Anzeige geht: SCOP nicht als Datenreihe aus der Datenbank lesen, sondern nach wie vor intern in Plotly per JS berechnen lassen. Datenreihen kann man da beliebig hinzufügen, die müssen nicht aus HA-Sensoren kommen.
                          Vielleicht hat da einer der Mitforisten noch eine andere Idee - Daten aggregieren war hier schon mehrfach Thema, ich hab's einfach im Zusammenhang mit HA noch nicht gebraucht.

                          /tom
                          Zuletzt geändert von Tom Bombadil; 29.08.2025, 17:49.

                          Kommentar


                            #43
                            Vielen Dank für die wie immer ausführliche Antwort.

                            Die "alte" Methode habe ich nach wie vor im Einsatz und liefert zuverlässig die Werte. Das enzige Manke ist, das die Daten auf den aktuellen und den vorausgegangenen Monat beschränkt sind. Es gibt unzählige Datenpunkte die über den CAN-Bus abgefragt werden können. Nicht jede Anlage liefert jeden Datenpunkt. Nun habe ich im nachhinein einen Datenpunkt gefunden der die aktuellen Werte liefert. Daher kommt der "Sinneswandel"

                            Ich denke in dem Fall ist Lösung 4 für mich die beste.

                            • [Edit:] Oder, wenn's wirklich nur um die Anzeige geht: SCOP nicht als Datenreihe aus der Datenbank lesen, sondern nach wie vor intern in Plotly per JS berechnen lassen. Datenreihen kann man da beliebig hinzufügen, die müssen nicht aus HA-Sensoren kommen.

                            Kommentar


                              #44
                              ich habe mal ein wenig rumprobiert mit JS in Plotly.
                              Die Berechnung der SCOP habe ich hinbekommen. Allerdings wird kein wert als Graph angezeigt.

                              Code:
                              type: custom:plotly-graph
                              entities:
                                - entity: sensor.vitocal_200s_vitocal_energy_dhw_input_today
                                  type: bar
                                  statistic: max
                                  period: day
                                - entity: sensor.vitocal_200s_vitocal_energy_dhw_output_today
                                  type: bar
                                  statistic: max
                                  period: day
                                - entity: ""
                                  name: SCOP
                                  mode: markers
                                  fn: |
                                    $fn ({ hass }) => {
                                      const input = parseFloat(hass.states['sensor.vitocal_200s_vitocal_energy_dhw_input_today'].state);
                                      const output = parseFloat(hass.states['sensor.vitocal_200s_vitocal_energy_dhw_output_today'].state);
                                      console.log("input", input);
                                      console.log("output", output);
                                      let scop;
                                      if(input <= 0) {
                                        scop = 0;
                                        } else {
                                        scop = output / input;
                                        };
                                      const y = scop;
                                      console.log("SCOP", y)
                                    }
                              hours_to_show: 7d
                              refresh_interval: 10
                              min_y_axis: 0
                              
                              ​
                              Consolen Log:

                              grafik.png

                              Kommentar


                                #45
                                Schlussendlich habe ich es nun hinbekommen. Ich bin sch erstaunt was alles möglich ist mit JS innerhalb von Plotly. Eventuell ist ja für den einen oder anderen interessant.

                                das hat zu meinem gewünschten Ergebnis geführt:
                                Code:
                                type: custom:plotly-graph
                                entities:
                                  - entity: sensor.vitocal_200s_vitocal_energy_dhw_input_today
                                    name: Energy Input
                                    type: bar
                                    statistic: max
                                    period: day
                                    filters:
                                      - store_var: energy_input
                                  - entity: sensor.vitocal_200s_vitocal_energy_dhw_output_today
                                    name: Energy Output
                                    type: bar
                                    statistic: max
                                    period: day
                                    filters:
                                      - store_var: energy_output
                                  - entity: ""
                                    name: SCOP
                                    mode: markers
                                    y: |
                                      $fn ({ vars }) => {
                                        const y = [];
                                        const input = vars.energy_input.ys;
                                        const output = vars.energy_output.ys;
                                        let inlen = input.length;
                                        for (let i = 0; i < inlen; i++) {
                                          const scop = output[i] / input[i];
                                          y.push(Math.round(parseFloat(scop) * 100) / 100);
                                        }
                                        return y
                                      }
                                    x: $ex vars.energy_input.xs​
                                das ganze lässt sich aber auch noch stark verkürzen
                                Code:
                                y: |
                                $ex vars.energy_output.ys.map((o, i) =>
                                Math.round(o / vars.energy_input.ys[i] * 100) / 100
                                )​
                                oder auch als Filter darstellen.
                                Code:
                                filters:
                                - load_var: energy_output
                                - map_y: "Math.round(y/vars.energy_put.ys[i] * 100) / 100"​
                                Wie schonTom Bombadil schrieb, wenn es nur der Anzeige dienen soll, kann man auf das Template zur Erstellung der Entität verzichten. Die SCOP wird für den jeweiligen Darstellungsbereich immer neu berechnet.

                                grafik.png

                                Kommentar

                                Lädt...
                                X