Store historical data in InMemory persistence - display ECHART (not Grafana) dashboard

I run Openhab 4.2.3 on Pi5 and use RRD4j as default persistence and store electricity data on InfluxDB2 with Grafana on a Proxmox server.
A smartmeter provides data of the electricity usage in my house and transfers the data via MQTT to my Openhab system. Some of the data is stored in RRD4j but the totals of the daily power usage and monthly totals are stored in InfluxDB2 (to avoid deleting by RRD4j).
Details stored in RRD4j can be displayed in a widget and on a chart on Openhab screen:
image

With Grafana I have created a dashboard which presents the yearly data by month totals. The data presented on the Grafana dashboard is stored in InfluxDB2.


Within Grafana I can share the dashboard: Link (within the Link I replace “localhost” by the IP of the Grafana server), Snapshot or Embed (iframe). The problem is, that I can’t display the shared dashboard on the Openhab screen. Therefor I run the Grafana dashboard at the end of every month and create a screenshot of the dashboard an store it in the “html” folder of Openhab [\10.49.101.40\openHAB-conf\html](file://10.49.101.40/openHAB-conf/html). This is a bit too complicated, and I will lose the “dynamic functionality” of the chart.
image

Therefore, I want to move the 12 monthly totals of electricity usage for every year into the InMemory persistence … but I don’t know how to get the historical data into the persistence.

It would be great if you could help me, to get the Grafana dashboard displayed on the Openhab screen … or provide a small rule which writes the monthly electricity totals into the InMemory persistence … if possible, two years overlapping on the Openhab screen.

To use the in memory persistence you need to install it (it’s a separate add-on) and configure the persistence strategy. Unlike other persistence add-ons, it’s default strategy does not save any data.

You’ll need at least one Item though you might need one Item per month. I don’t use bar charts in OH so don’t know how they work.

Either way you’ll need a rule that calculates the totals for each month (I don’t know how those are stored in your InfluxDB already so the specifics are an exercise left to the student). You’ll at least need to calculate the last day of each month for the next step.

Then to save the value to the inmemory persistence will depend on the rules language you are using. In JS Scripting it would be:

items.ItemName.persistence.persist(endOfMonthDT, sum, 'inmemory');

where endOfMonthDT is a ZonedDateTime at 11:59:59 PM on the last day of that month, sum is the value you want to chart, and "inmemory" tells OH which persistence add-on to save the value to.

Thank you Rich @rlkoshak for your quick reply.
I created a rule with the 12 values for 2023.

items.Stromverbrauch_Monatsende.persistence.persist(‘2023-01-31T23:59:59’,484.704, ‘inmemory’);
items.Stromverbrauch_Monatsende.persistence.persist(‘2023-02-28T23:59:59’,437.797, ‘inmemory’);
items.Stromverbrauch_Monatsende.persistence.persist(‘2023-03-31T23:59:59’,494.810, ‘inmemory’);
items.Stromverbrauch_Monatsende.persistence.persist(‘2023-04-30T23:59:59’,492.663, ‘inmemory’);
items.Stromverbrauch_Monatsende.persistence.persist(‘2023-05-31T23:59:59’,442.657, ‘inmemory’);
items.Stromverbrauch_Monatsende.persistence.persist(‘2023-06-30T23:59:59’,442.288, ‘inmemory’);
items.Stromverbrauch_Monatsende.persistence.persist(‘2023-07-31T23:59:59’,446.869, ‘inmemory’);
items.Stromverbrauch_Monatsende.persistence.persist(‘2023-08-31T23:59:59’,477.908, ‘inmemory’);
items.Stromverbrauch_Monatsende.persistence.persist(‘2023-09-30T23:59:59’,415.493, ‘inmemory’);
items.Stromverbrauch_Monatsende.persistence.persist(‘2023-10-31T23:59:59’,476.385, ‘inmemory’);
items.Stromverbrauch_Monatsende.persistence.persist(‘2023-11-30T23:59:59’,497.806, ‘inmemory’);
items.Stromverbrauch_Monatsende.persistence.persist(‘2023-12-31T23:59:59’,555.073, ‘inmemory’);

… but I only see the first value with date of today
image

Did I use a wrong format for the date … or did I do anything else wrong?

You need to use a ZonedDateTime, (i.e. time.ZonedDateTime) Object. You are just using a String here. You need to convert that to a ZonedDateTime. Those appear to be ISO8601 so it might be as simple as time.toZTD("2023-01-...)

Thank you Rich @rlkoshak for clarification. By preparing the needed data I discovered a strange behaviour of Blockly rules when reading data from RRD4j - I copy @stefan.hoehn who as far as I know is managing Blockly.
I get the following result when I read the 3 values for date 2024-11-30, 2024-12-01 and 2024-12-02:
2024-12-04 15:49:17.909 [INFO ] [tion.script.ui.TestPersistenceDate01] - 2024-11-30: 9662.294
2024-12-04 15:49:17.918 [INFO ] [tion.script.ui.TestPersistenceDate01] - 2024-12-01: 9662.294
2024-12-04 15:49:17.929 [INFO ] [tion.script.ui.TestPersistenceDate01] - 2024-12-02: 9690.373

The date of 2024-12-01 is the same as of 2024-11-30 but it has to be 9676.127
… which can also be seen in the following chart:

I used the following Test rule:

Could you please explain the behaviour of Blockly (when the month switches)

rrd4j stores data every minute. So there will be values stored for that date all throughout the day.

Do you want the value at the start of that date or at the end of that date? I think by default if you do not specify it, the value returned will be on that date at midnight (i.e. the start of the day). So unless you wrote that month’s data to rrd4j before midnight on the previous day, you’ll be picking up the previous month’s data.

A Openhab rule has stored the value at midnight (Austria time … is same as German time) on all three days. Why do two of three days show the same value when I get the values with Blockly and show three different values in the chart? The chart values are right!

Exactly at midnight? Not midnight plus 100-200 msec? Storing a value take some time. Your query is asking for the data at exactly 2024-11-30T00:00:00.000 but the value might not have been saved until 2024-11-30T00:00:00.150. Also, if you want the full month’s worth of data, should the value be written at 2024-12-01T00:00:00.000? If you write at midnight on the 30th you miss a whole day from the month.

The timing is really important here.

Whay does it show correctly in the chart? Because these tiny bits of difference in the chart are imperceptible.

Shall I use noon time 2024-12-01T12:00:00.000 instead of midnight 2024-12-01T00:00:00.000 of each day to have enough tolerance?

But what you need to do is figure out exactly when the rule writes these values to persistence and then choose a time in your query that is reliably after that. 12 hours is way overkill and the persistence functions will only look back so far. A second should be sufficient. But there’s not enough info here to give a definitive answer.

For example, If your rule runs at 11:59:59.999 to save the value (for example) you might want your query to be at least 00:00:00.100 on the next day to reliably get the saved value. It takes some milliseconds to actually complete the save to persistence. 100 msecs is usually enough. Once second is almost always going to be enough.

I thougt it might be better to have a specific value for every day … but now I see the difficulties when doing that. Beside the smartmeter line in day steps, I also have a continously growing smartmeter line (where you don’t see steps).


When I use my rule with these values I get the right results:
2024-12-04 17:31:36.307 [INFO ] [tion.script.ui.TestPersistenceDate01] - 2024-11-30: 9662.294
2024-12-04 17:31:36.313 [INFO ] [tion.script.ui.TestPersistenceDate01] - 2024-12-01: 9676.127
2024-12-04 17:31:36.320 [INFO ] [tion.script.ui.TestPersistenceDate01] - 2024-12-02: 9690.373

In this case a continuos line is better than a line with steps!
Thank you very much Rich for this exciting discussion - training for myself.

Sorry Rich I still have problems by storing the values in InMemory.

I have created a number item and tried the following rule:

items.kWh2024.persistence.persist(time.toZTD(‘2024-01-31T23:59’),558.205, ‘inmemory’);
items.kWh2024.persistence.persist(time.toZTD(‘2024-02-28T23:59’),455.587, ‘inmemory’);

I couldn’t see items in the chart

Then I tried TimeSeries. I found the documentation on JavaScript Scripting

My adjusted rule:

var timeSeries = new items.TimeSeries('ADD'); // Create a new TimeSeries with policy ADD
timeSeries.add(time.toZDT('2024-01-31T23:59'), Quantity('558.205 kWh')).add(time.toZDT('2024-02-28T23:59'), Quantity('455.587 kWh')).add(time.toZDT('2024-03-31T23:59'), Quantity('481.220 kWh')).add(time.toZDT('2024-04-30T23:59'), Quantity('483.733 kWh')).add(time.toZDT('2024-05-31T23:59'), Quantity('451.596 kWh'));
console.log(timeSeries); // Let's have a look at the TimeSeries
items.getItem('kWh2024').persistence.persist(timeSeries, 'inmemory'); // Persist the TimeSeries for the Item 'MyDistanceItem' using the InMemory persistence service

The log info

2024-12-05 19:47:13.874 [INFO ] [tion.script.ui.WriteDataIntoInMemory] - TimeSeries (Begin=2024-01-31T22:59:00Z, End=2024-05-31T21:59:00Z, Size=5, States=[2024-01-31T22:59:00Z → 558.205 kWh], [2024-02-28T22:59:00Z → 455.587 kWh], [2024-03-31T21:59:00Z → 481.22 kWh], [2024-04-30T21:59:00Z → 483.733 kWh], [2024-05-31T21:59:00Z → 451.596 kWh])

The TimeSeries seems to be created, but when I click on item kWh2024, I dont see any values

It’s a bit difficult …
… any hint how to step forward?

I don’t really use the inmemory persistence nor have I ever used Timeseries. So beyond what’s in the docs I can’t really help. But I know that charts will use the default persistence engine unless specifically configured to use one of the other ones. I believe you set the persistene engine to use on a per Item basis in the chart settings.

Yes you are right - charts use the default persisctence service … but you are able to activate “show advanced” in the Item / Time-Series settings in the charts definition and select the persistence service

Thanks! One step forward!

I have now moved the data into the InMemory persistence and “converted” the Grafana dashboard to a Openhab Chart:


I first tried to display the total of the month with time “last day of month”. This displayed the February data above “Mar” and April data above “May” … which was a bit irritating. That’s the reason why I changed the time to display the total for every month on the “10th” of the month “yyyy-mm-10” which looks better.

I used the following rules to get the data into InMemory

JavaScript rule to get the 12 month totals for every year into a TimeSeries
//
// Year 2023
// Create a new TimeSeries with policy ADD 
var timeSeries2023 = new items.TimeSeries('ADD'); 
timeSeries2023.add(time.toZDT('2024-01-10T23:59'), 
                       Quantity('484.704 kWh')).add(time.toZDT('2024-02-10T23:59'), Quantity('437.797 kWh')).add(time.toZDT('2024-03-10T23:59'), 
                       Quantity('494.810 kWh')).add(time.toZDT('2024-04-10T23:59'), Quantity('492.663 kWh')).add(time.toZDT('2024-05-10T23:59'), 
                       Quantity('442.657 kWh')).add(time.toZDT('2024-06-10T23:59'), Quantity('442.288 kWh')).add(time.toZDT('2024-07-10T23:59'), 
                       Quantity('446.869 kWh')).add(time.toZDT('2024-08-10T23:59'), Quantity('477.908 kWh')).add(time.toZDT('2024-09-10T23:59'),
                       Quantity('415.493 kWh')).add(time.toZDT('2024-10-10T23:59'), Quantity('476.385 kWh')).add(time.toZDT('2024-11-10T23:59'),
                       Quantity('497.806 kWh')).add(time.toZDT('2024-12-10T23:59'), Quantity('555.073 kWh')) ;
// Let's have a look at the TimeSeries 
console.log(timeSeries2023); 
// Persist the TimeSeries for the Item 'kWh2024' using the InMemory persistence service
items.getItem('kWh2023').persistence.persist(timeSeries2023, 'inmemory'); 
//
// Year 2024
// Create a new TimeSeries with policy ADD
var timeSeries2024 = new items.TimeSeries('ADD'); 
timeSeries2024.add(time.toZDT('2024-01-10T23:59'), 
                          Quantity('558.205 kWh')).add(time.toZDT('2024-02-10T23:59'), Quantity('455.587 kWh')).add(time.toZDT('2024-03-10T23:59'), 
                          Quantity('481.220 kWh')).add(time.toZDT('2024-04-10T23:59'), Quantity('483.733 kWh')).add(time.toZDT('2024-05-10T23:59'), 
                          Quantity('451.596 kWh')).add(time.toZDT('2024-06-10T23:59'), Quantity('486.790 kWh')).add(time.toZDT('2024-07-10T23:59'),
                          Quantity('452.671 kWh')).add(time.toZDT('2024-08-10T23:59'), Quantity('446.660 kWh')).add(time.toZDT('2024-09-10T23:59'),
                          Quantity('445.123 kWh')).add(time.toZDT('2024-10-10T23:59'), Quantity('467.268 kWh')).add(time.toZDT('2024-11-10T23:59'),
                          Quantity('417.602 kWh')).add(time.toZDT('2024-12-10T23:59'), Quantity('80.970 kWh')) ;
// Let's have a look at the TimeSeries
console.log(timeSeries2024); 
// Persist the TimeSeries for the Item 'kWh2024' using the InMemory persistence service
items.getItem('kWh2024').persistence.persist(timeSeries2024, 'inmemory');

at the begin of the year all 12 values can be 0.0 and you can step by step update every month with the next script which updates only the current month

JavaScript rule which does not update all 12 value but only the value of current month
//
// Year 2024
// Replace one month of the TimeSeries with policy REPLACE
var timeSeries2024 = new items.TimeSeries('REPLACE'); 
timeSeries2024.add(time.toZDT('2024-12-10T23:59'), Quantity('95.448 kWh')) ;
// Let's have a look at the TimeSeries
console.log(timeSeries2024); 
// Persist the TimeSeries for the Item 'kWh2024' using the InMemory persistence service
items.getItem('kWh2024').persistence.persist(timeSeries2024, 'inmemory');

you can run this rule every day so that you can see how the month increase

The rules still need to be improved (update the values in the rule) so that they run without my help (fully automated)

Chart Code - see where to define the persistence - service: inmemory
config:
  chartType: year
  label: kWh2024
  period: Y
slots:
  grid:
    - component: oh-chart-grid
      config:
        includeLabels: true
        containLabel: true
        show: true
  legend:
    - component: oh-chart-legend
      config:
        bottom: 3
        type: scroll
  series:
    - component: oh-time-series
      config:
        gridIndex: 0
        item: kWh2023
        name: kWh 2023
        service: inmemory
        type: scatter
        xAxisIndex: 0
        yAxisIndex: 0
    - component: oh-time-series
      config:
        gridIndex: 0
        item: kWh2024
        name: kWh 2024
        service: inmemory
        type: bar
        xAxisIndex: 0
        yAxisIndex: 0
  tooltip:

Beside the work to improve the rules I’m still interested to know how to display Grafana dashboards within the Openhab screen (Grafana has much more possibilities to adjust a chart). Many thanks again to Rich who helps to overcome some gaps in my knowledge with some hints to get that done!

I read several documents about chart-pages, chart with widgets in the OpenHAB Community Forum and the ECHART documentation https://echarts.apache.org/en/cheat-sheet.html. A widget from @stefan13 which I adjusted for my needs, helped me to step forward and get the needed charts as chart-pages and charts with widgets.

adjusted widget for charts from @stefan13

the adjusted widget. I used ‘itemVerbrauch’ and itemTemperatur with values every minute from RRD4J-persistence for DAY, WEEK and MONTH view. For the YEAR view I used ‘itemVerbrauchJahr’ with monthly totals and ‘itemkWh20xxErw’ for the expected value at end of month from InMemory persistence. Some ECHART-code like ‘Symbol:’ or ‘SymbolSize:’ work in widgets.

uid: Card_Verbrauch
tags:
  - BG
props:
  parameters:
    - description: A text prop
      label: Prop 1
      name: prop1
      required: false
      type: TEXT
    - context: item
      description: Strom Verbrauch
      label: Item
      name: prop_itemVerbrauch
      required: false
      type: TEXT
    - context: item
      description: Strom Verbrauch Jahr
      label: Item
      name: prop_itemVerbrauchJahr
      required: false
      type: TEXT
    - context: item
      description: Strom Monatserwartung
      label: Item
      name: prop_itemkWh20xxErw
      required: false
      type: TEXT
    - context: item
      description: Temperatur Item
      label: Item
      name: prop_itemTemperatur
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Jan 22, 2025, 11:13:04 AM
component: f7-card
config:
  backdrop: false
  class:
    - no-padding
  expandable: false
  style:
    --f7-theme-color: var(--f7-text-color)
    border-radius: var(--f7-card-expandable-border-radius)
    box-shadow: var(--f7-card-expandable-box-shadow)
    height: 515px
    margin-bottom: 0px
    margin-left: 0px
    margin-right: 0px
    margin-top: 0px
    width: 100%
  swipeToClose: false
slots:
  default:
    - component: oh-link
      config:
        action: navigate
        actionPage: page:Verbrauch_Stunde
        actionPageTransition: f7-dive
        style:
          margin-left: 10px
          margin-top: 10px
          opacity: 60%
          position: absolute
          z-index: 1
        visible: "(=vars.varPeriod == 'day' | vars.varPeriod == undefined) ? true :
          false"
    - component: oh-link
      config:
        action: navigate
        actionPage: page:Verbrauch_Woche
        actionPageTransition: f7-dive
        style:
          margin-left: 10px
          margin-top: 10px
          opacity: 60%
          position: absolute
          z-index: 1
        visible: "=vars.varPeriod == 'week'  ? true : false"
    - component: oh-link
      config:
        action: navigate
        actionPage: page:Verbrauch_Monat
        actionPageTransition: f7-dive
        style:
          margin-left: 10px
          margin-top: 10px
          opacity: 60%
          position: absolute
          z-index: 1
        visible: "=vars.varPeriod == 'month'  ? true : false"
    - component: oh-link
      config:
        action: navigate
        actionPage: page:Verbrauch_Jahr
        actionPageTransition: f7-dive
        style:
          margin-left: 10px
          margin-top: 10px
          opacity: 60%
          position: absolute
          z-index: 1
        visible: "=vars.varPeriod == 'year'  ? true : false"
    - component: f7-segmented
      config:
        class: segmented-round
        style:
          bottom: 0px
          height: 30px
          left: 0px
          position: absolute
          width: 100%
          z-index: 2
      slots:
        default:
          - component: oh-button
            config:
              action: variable
              actionVariable: varPeriod
              actionVariableValue: day
              iconSize: 20px
              outline: true
              style:
                --f7-button-bg-color: "=(vars.varPeriod == 'day' || vars.varPeriod == undefined)
                  ? 'transparent' :   '#f0f0f0'  "
                --f7-button-hover-bg-color: "#e7f3fe"
                --f7-button-pressed-bg-color: "#9dcefb"
                height: 100%
                width: 100%
              text: Tag
              textColor: "=(vars.varPeriod == 'day' || vars.varPeriod == undefined ) ? 'red'
                :   'black'  "
          - component: oh-button
            config:
              action: variable
              actionVariable: varPeriod
              actionVariableValue: week
              iconSize: 20px
              outline: true
              style:
                --f7-button-bg-color: "=(vars.varPeriod == 'week' ) ? 'transparent' :   '#f0f0f0'  "
                --f7-button-hover-bg-color: "#e7f3fe"
                --f7-button-pressed-bg-color: "#9dcefb"
                height: 100%
                width: 100%
              text: Woche
              textColor: "=(vars.varPeriod == 'week' ) ? 'red' :   'black'  "
          - component: oh-button
            config:
              action: variable
              actionVariable: varPeriod
              actionVariableValue: month
              iconSize: 20px
              outline: true
              style:
                --f7-button-bg-color: "=(vars.varPeriod == 'month')  ? 'transparent' :   '#f0f0f0'  "
                --f7-button-hover-bg-color: "#e7f3fe"
                --f7-button-pressed-bg-color: "#9dcefb"
                height: 100%
                width: 100%
              text: Monat
              textColor: "=(vars.varPeriod == 'month' ) ? 'red' :   'black'  "
          - component: oh-button
            config:
              action: variable
              actionVariable: varPeriod
              actionVariableValue: year
              iconSize: 20px
              outline: true
              style:
                --f7-button-bg-color: "=(vars.varPeriod == 'year') ? 'transparent' :   '#f0f0f0'  "
                --f7-button-hover-bg-color: "#e7f3fe"
                --f7-button-pressed-bg-color: "#9dcefb"
                height: 100%
                width: 100%
              text: Jahr
              textColor: "=(vars.varPeriod == 'year' ) ? 'red' :   'black'  "
              visible: true
    - component: oh-chart
      config:
        chartType: year
        height: 100%
        options:
          backgroundColor: transparent
        sidebar: true
        visible: "=vars.varPeriod == 'year'  ? true : false"
      slots:
        calendar: []
        grid:
          - component: oh-chart-grid
            config:
              height: 70%
              includeLabels: true
              left: 70
              right: 70
              show: false
              top: 80
        legend:
          - component: oh-chart-legend
            config:
              left: 20
              orient: horizontal
              show: true
              top: 10
              width: 600
        series:
          - component: oh-aggregate-series
            config:
              aggregationFunction: average
              color: yellow
              dimension1: month
              gridIndex: 0
              id: 0
              item: =props.prop_itemVerbrauchJahr
              service: inmemory
              noBoundary: true
              markLine:
                data:
                  - type: average
              name: Strom-Verbrauch
              type: bar
              xAxisIndex: 0
              yAxisIndex: 0
          - component: oh-aggregate-series
            config:
              aggregationFunction: average
              color: yellow
              dimension1: month
              gridIndex: 0
              item: =props.prop_itemkWh20xxErw
              service: inmemory
              lineStyle:
                width: 2
              markPoint:
                data:
                  - name: max
                    type: max
              name: Monatserwartung
              type: line
              xAxisIndex: 0
              yAxisIndex: 0
              symbol: arrow
              symbolSize: 20
          - component: oh-aggregate-series
            config:
              aggregationFunction: average
              color: red
              dimension1: month
              gridIndex: 0
              id: 1
              item: =props.prop_itemTemperatur
              lineStyle:
                width: 2
                type: solid
              name: Temperatur
              type: line
              xAxisIndex: 0
              yAxisIndex: 1
              symbol: circle
              symbolSize: 5
        tooltip:
          - component: oh-chart-tooltip
            config:
              confine: true
              show: true
              trigger: axis
        xAxis:
          - component: oh-category-axis
            config:
              categoryType: year
              gridIndex: 0
              nameGap: 22
              nameLocation: center
              monthFormat: short
        yAxis:
          - component: oh-value-axis
            config:
              axisLabel:
                formatter: "{value} kWh"
              gridIndex: 0
              max: 600
              nameGap: 30
              nameLocation: center
          - component: oh-value-axis
            config:
              axisLabel:
                formatter: "{value} °C"
              gridIndex: 0
              nameGap: 40
              nameLocation: center
              scale: true
    - component: oh-chart
      config:
        chartType: isoWeek
        height: 100%
        options:
          backgroundColor: transparent
        sidebar: true
        visible: "=vars.varPeriod == 'week' ? true : false"
      slots:
        grid:
          - component: oh-chart-grid
            config:
              height: 70%
              includeLabels: true
              left: 70
              right: 70
              show: false
              top: 80
        legend:
          - component: oh-chart-legend
            config:
              left: 70
              orient: horizontal
              show: true
              top: 10
              width: 600
        series:
          - component: oh-aggregate-series
            config:
              aggregationFunction: diff_last
              color: yellow
              dimension1: isoWeekday
              gridIndex: 0
              id: 0
              item: =props.prop_itemVerbrauch
              markLine:
                data:
                  - type: average
              name: Strom-Verbrauch
              type: bar
              xAxisIndex: 0
              yAxisIndex: 0
              label:
                show: false
                formatter: =v=>Number.parseFloat(v.data[1]).toFixed(1) + " kWh"
          - component: oh-aggregate-series
            config:
              aggregationFunction: average
              color: red
              dimension1: isoWeekday
              gridIndex: 0
              id: 1
              item: =props.prop_itemTemperatur
              lineStyle:
                width: 2
                type: solid
              name: Temperatur
              type: line
              xAxisIndex: 0
              yAxisIndex: 1
              symbol: circle
              symbolSize: 10
        tooltip:
          - component: oh-chart-tooltip
            config:
              confine: true
              show: true
              trigger: axis
        xAxis:
          - component: oh-category-axis
            config:
              categoryType: week
              gridIndex: 0
              nameGap: 22
              nameLocation: center
              monthFormat: short
              weekdayFormat: short
        yAxis:
          - component: oh-value-axis
            config:
              axisLabel:
                formatter: "{value} kWh"
              gridIndex: 0
              nameGap: 40
              nameLocation: center
          - component: oh-value-axis
            config:
              axisLabel:
                formatter: "{value} °C"
              gridIndex: 0
              nameGap: 40
              nameLocation: center
              scale: true
              show: true
    - component: oh-chart
      config:
        chartType: month
        height: 100%
        options:
          backgroundColor: transparent
        sidebar: true
        visible: "=vars.varPeriod == 'month' ? true : false"
      slots:
        calendar: []
        grid:
          - component: oh-chart-grid
            config:
              height: 70%
              includeLabels: true
              left: 70
              right: 70
              show: false
              top: 80
        legend:
          - component: oh-chart-legend
            config:
              left: 70
              orient: horizontal
              show: true
              top: 10
              width: 600
        series:
          - component: oh-aggregate-series
            config:
              aggregationFunction: diff_last
              color: yellow
              dimension1: date
              gridIndex: 0
              id: 0
              item: =props.prop_itemVerbrauch
              markLine:
                data:
                  - type: average
              markPoint:
                data:
                  - name: min
                    type: min
                  - name: max
                    type: max
              name: Strom-Verbrauch
              type: bar
              xAxisIndex: 0
              yAxisIndex: 0
              label:
                show: false
                formatter: =v=>Number.parseFloat(v.data[1]).toFixed(1) + " kWh"
          - component: oh-aggregate-series
            config:
              aggregationFunction: average
              color: red
              dimension1: date
              gridIndex: 0
              id: 1
              item: =props.prop_itemTemperatur
              lineStyle:
                width: 2
                type: solid
              name: Temperatur
              type: line
              xAxisIndex: 0
              yAxisIndex: 1
              symbol: circle
              symbolSize: 5
        tooltip:
          - component: oh-chart-tooltip
            config:
              confine: true
              show: true
              trigger: axis
        xAxis:
          - component: oh-category-axis
            config:
              categoryType: month
              gridIndex: 0
              nameGap: 22
              nameLocation: center
              weekdayFormat: short
              monthFormat: short
        yAxis:
          - component: oh-value-axis
            config:
              axisLabel:
                formatter: "{value} kWh"
              gridIndex: 0
              nameGap: 40
              nameLocation: center
          - component: oh-value-axis
            config:
              axisLabel:
                formatter: "{value} °C"
              gridIndex: 0
              nameGap: 40
              nameLocation: center
              scale: true
    - component: oh-chart
      config:
        chartType: day
        height: 100%
        options:
          backgroundColor: transparent
        sidebar: true
        visible: "=vars.varPeriod == 'day' || vars.varPeriod == undefined ? true :
          false"
      slots:
        calendar: []
        grid:
          - component: oh-chart-grid
            config:
              height: 70%
              includeLabels: true
              left: 70
              right: 70
              show: false
              top: 80
        legend:
          - component: oh-chart-legend
            config:
              left: 70
              orient: horizontal
              show: true
              top: 10
              width: 600
        series:
          - component: oh-aggregate-series
            config:
              aggregationFunction: diff_last
              color: yellow
              dimension1: hour
              gridIndex: 0
              id: 0
              item: =props.prop_itemVerbrauch
              markLine:
                data:
                  - type: average
              markPoint:
                data:
                  - name: min
                    type: min
                  - name: max
                    type: max
              name: Strom-Verbrauch
              type: bar
              xAxisIndex: 0
              yAxisIndex: 0
              label:
                show: false
                formatter: =v=>Number.parseFloat(v.data[1]).toFixed(1) + " kWh"
          - component: oh-aggregate-series
            config:
              aggregationFunction: average
              color: red
              dimension1: hour
              gridIndex: 0
              id: 1
              item: =props.prop_itemTemperatur
              lineStyle:
                width: 2
                type: solid
              name: Temperatur
              type: line
              xAxisIndex: 0
              yAxisIndex: 1
              symbol: circle
              symbolSize: 5
        tooltip:
          - component: oh-chart-tooltip
            config:
              confine: true
              show: true
              trigger: axis
        xAxis:
          - component: oh-category-axis
            config:
              categoryType: day
              gridIndex: 0
              nameGap: 22
              nameLocation: center
              monthFormat: short
              weekdayFormat: short
        yAxis:
          - component: oh-value-axis
            config:
              axisLabel:
                formatter: "{value} kWh"
              gridIndex: 0
              nameGap: 40
              nameLocation: center
          - component: oh-value-axis
            config:
              axisLabel:
                formatter: "{value} °C"
              gridIndex: 0
              nameGap: 40
              nameLocation: center
              scale: true

The charts created by the widget within a tabbed page:
Day view

Year view 2025 with expected value at the end of the current month ‘Monatserwartung’:

view of previous Years:

Rule to calculate expected value at the end of the month - runs every night
//
// Update current month value and expected value at end of current month
//
var temp = 0;
// Format DayDatum 'YYYY-MM-DD'
var datum = items.getItem('DayDatum').state; 
var datum1 = datum;
var datum2 = datum;
// get day, month, Year from date
var jahr = datum.substring(0, 4);
jahr = parseInt(jahr);
console.log(jahr); 
var monat = datum.substring(5, 7);
monat = parseInt(monat);
console.log(monat);
var tag = datum.substring(8, 10);
tag = parseInt(tag);
console.log(tag);
// I use the 10th or 28th in chart and widget (display reasons) 
datum1 = datum.substring(0, 8) + '10T23:59';
datum2 = datum.substring(0, 8) + '28T23:59';
console.log(datum1); 
console.log(datum2); 
// last day of month
var last = 31 ;
if (monat == 4 || monat == 6 || monat == 9 || monat == 11) {
  last = 30;   
}
// last day of February - leap year? 
if (monat == 2) {
  temp = parseInt(jahr / 4) ; 
  temp = temp * 4 ;
  if (jahr == temp) {
    last = 29 ;
  } else {last = 28} ;
}
// DayMonatswert = kWh of current month  
var monatswert = items.getItem('DayMonatswert').state; 
console.log(monatswert); 
// expected kWh at the end of current month
monatserwartung = monatswert * last / tag  ;
monatserwartung = Math.round(monatserwartung) ;
console.log(monatserwartung);
monatswert = monatswert + ' kWh';
monatserwartung = monatserwartung + ' kWh';
//
//
// Replace in TimeSeries current month with month value 'Monatswert' - with policy REPLACE
var timeSeries2025 = new items.TimeSeries('REPLACE'); 
timeSeries2025.add(time.toZDT(datum1), Quantity(monatswert)) ;
// Persist the TimeSeries for the Item 'kWh2025' using the InMemory persistence service
items.getItem('kWh2025').persistence.persist(timeSeries2025, 'inmemory'); 
// timeSeries2025 and 'kWh2025' has to be replaced at begin of every year timeSeries2026, timeSeries2027 ...
// 
// Display the expected value at the end of the month 'Monatserwartung' as seperate value
var timeSeries20zz = new items.TimeSeries('REPLACE'); 
timeSeries20zz.add(time.toZDT(datum1), Quantity(monatserwartung)) ;
// Persist the TimeSeries for the Item 'kWhTEMP' using the InMemory persistence service
items.getItem('kWhTEMP').persistence.persist(timeSeries20zz, 'inmemory'); 
// 
//
// timeSeries20xx for widget
// Replace in TimeSeries current month with month value 'Monatswert' - with policy REPLACE
var timeSeries20xx = new items.TimeSeries('REPLACE'); 
timeSeries20xx.add(time.toZDT(datum2), Quantity(monatswert)) ;
// Persist the TimeSeries for the Item 'kWh20xx' using the InMemory persistence service
items.getItem('kWh20xx').persistence.persist(timeSeries20xx, 'inmemory'); 
// 
// Display the expected value at the end of the month 'Monatserwartung' as seperate value
var timeSeries20yy = new items.TimeSeries('REPLACE'); 
timeSeries20yy.add(time.toZDT(datum2), Quantity(monatserwartung)) ;
// Persist the TimeSeries for the Item 'kWh20xxErwartung' using the InMemory persistence service
items.getItem('kWh20xxErwartung').persistence.persist(timeSeries20yy, 'inmemory'); 
//

Within other tabs ot the tabbed page you see the today view and year comparison with expected value at the end of the current month (the remaining month will be filled with red bars in the next months):

Within the chart pages you can display a button to view the ‘Data Table’ of the bars and lines.


Is it possible to view the time in Format DD.MM.YYYY and a quantity like ‘kWh’ behind the values?

I hope this topic help others to create their charts

I used the past weeks to get a better understanding of ECharts. ECHARTS is a great tool even you have to experience a bit to get some functions working within Openhab.

I will now implement all charts with ECHARTS and will no longer use Grafana!

Attached the status of my charts on electricity power used in my house.

tab chart power used in current year (year=2025 [yellow+orange], year-1=2024 [green], year-2=2023 [blue]):


Data Table view:

If you use widgets to create your chart, the time is displayed correct … which is currently not the case if you use the chart tool in pages).

tab chart power used in previous year 2024 (year=2024 [yellow, orange], year-1=2023 [green]):


pie chart power used the past 3 years:

the widget used for the charts in a tabbed page
uid: Card_Verbrauch
tags:
  - BG
props:
  parameters:
    - description: A text prop
      label: Prop 1
      name: prop1
      required: false
      type: TEXT
    - context: item
      description: Strom Verbrauch
      label: Item
      name: prop_itemVerbrauch
      required: false
      type: TEXT
    - context: item
      description: Strom Verbrauch Jahr
      label: Item
      name: prop_itemVerbrauchJahr
      required: false
      type: TEXT
    - context: item
      description: Strom Monatserwartung
      label: Item
      name: prop_itemkWh20xxMonatserwartung
      required: false
      type: TEXT
    - context: item
      description: Strom Monatdurchschnitt
      label: Item
      name: prop_itemkWh20xxMonatsdurchschnitt
      required: false
      type: TEXT
    - context: item
      description: Temperatur Item
      label: Item
      name: prop_itemTemperatur
      required: false
      type: TEXT
  parameterGroups: []
timestamp: Feb 10, 2025, 11:05:25 AM
component: f7-card
config:
  backdrop: false
  class:
    - no-padding
  expandable: false
  style:
    --f7-theme-color: var(--f7-text-color)
    border-radius: var(--f7-card-expandable-border-radius)
    box-shadow: var(--f7-card-expandable-box-shadow)
    height: 515px
    margin-bottom: 0px
    margin-left: 0px
    margin-right: 0px
    margin-top: 0px
    width: 100%
  swipeToClose: false
slots:
  default:
    - component: f7-segmented
      config:
        class: segmented-round
        style:
          bottom: -15px
          height: 30px
          left: 0px
          position: absolute
          width: 100%
          z-index: 2
      slots:
        default:
          - component: oh-button
            config:
              action: variable
              actionVariable: varPeriod
              actionVariableValue: year
              iconSize: 20px
              outline: true
              style:
                --f7-button-bg-color: "=(vars.varPeriod == 'year' || vars.varPeriod ==
                  undefined) ? 'transparent' : '#f0f0f0' "
                --f7-button-hover-bg-color: "#e7f3fe"
                --f7-button-pressed-bg-color: "#9dcefb"
                height: 100%
                width: 100%
              text: Jahr
              textColor: "=(vars.varPeriod == 'year' || vars.varPeriod == undefined) ? 'red' :
                'black'  "
              visible: true
          - component: oh-button
            config:
              action: variable
              actionVariable: varPeriod
              actionVariableValue: total
              iconSize: 20px
              outline: true
              style:
                --f7-button-bg-color: "=(vars.varPeriod == 'total') ? 'transparent' : '#f0f0f0' "
                --f7-button-hover-bg-color: "#e7f3fe"
                --f7-button-pressed-bg-color: "#9dcefb"
                height: 100%
                width: 100%
              text: ∑ Jahre
              textColor: "=(vars.varPeriod == 'total' ) ? 'red' : 'black'  "
              visible: true
          - component: oh-button
            config:
              action: variable
              actionVariable: varPeriod
              actionVariableValue: month
              iconSize: 20px
              outline: true
              style:
                --f7-button-bg-color: "=(vars.varPeriod == 'month')  ? 'transparent' : '#f0f0f0' "
                --f7-button-hover-bg-color: "#e7f3fe"
                --f7-button-pressed-bg-color: "#9dcefb"
                height: 100%
                width: 100%
              text: Monat
              textColor: "=(vars.varPeriod == 'month' ) ? 'red' :   'black'  "
          - component: oh-button
            config:
              action: variable
              actionVariable: varPeriod
              actionVariableValue: week
              iconSize: 20px
              outline: true
              style:
                --f7-button-bg-color: "=(vars.varPeriod == 'week' ) ? 'transparent' : '#f0f0f0' "
                --f7-button-hover-bg-color: "#e7f3fe"
                --f7-button-pressed-bg-color: "#9dcefb"
                height: 100%
                width: 100%
              text: Woche
              textColor: "=(vars.varPeriod == 'week' ) ? 'red' : 'black'  "
          - component: oh-button
            config:
              action: variable
              actionVariable: varPeriod
              actionVariableValue: day
              iconSize: 20px
              outline: true
              style:
                --f7-button-bg-color: "=(vars.varPeriod == 'day' ) ? 'transparent' : '#f0f0f0' "
                --f7-button-hover-bg-color: "#e7f3fe"
                --f7-button-pressed-bg-color: "#9dcefb"
                height: 100%
                width: 100%
              text: Tag
              textColor: "=(vars.varPeriod == 'day' ) ? 'red' : 'black'"
    - component: oh-chart
      config:
        height: 100%
        options:
          backgroundColor: transparent
        sidebar: false
        visible: "=vars.varPeriod == 'total'  ? true : false"
      slots:
        title:
          - component: oh-chart-title
            config:
              show: true
              text: Strom-Jahresvergleich
              top: 0
              left: 170px
        legend:
          - component: oh-chart-legend
            config:
              left: center
              orient: horizontal
              show: true
              bottom: 25px
              width: 600
        grid:
          - component: oh-chart-grid
            config:
              height: 70%
              includeLabels: true
              left: 70
              right: 70
              show: false
              top: 60
        series:
          - component: oh-data-series
            config:
              type: pie
              avoidLabelOverlap: true
              labelLine:
                length: 20
              radius:
                - 25%
                - 55%
              center:
                - 50%
                - 70%
              startAngle: 180
              endAngle: 360
              data:
                - value: =items.Strom2023.state
                  name: "2023"
                  label:
                    show: true
                    formatter: |-
                      {c|{c} kWh/Jahr
                      472 kWh/Monat
                      15.5 kWh/Tag}
                    backgroundColor: "#F6F8FC"
                    borderColor: "#8C8D8E"
                    borderWidth: 1
                    borderRadius: 4
                    padding: 2
                    rich:
                      c:
                        color: "#4C5058"
                        fontSize: 12
                        fontWeight: bold
                        lineHeight: 20
                - value: =items.Strom2024.state
                  name: "2024"
                  label:
                    show: true
                    formatter: |-
                      {c|{c} kWh/Jahr
                      468 kWh/Monat
                      15.3 kWh/Tag}
                    backgroundColor: "#F6F8FC"
                    borderColor: "#8C8D8E"
                    borderWidth: 1
                    borderRadius: 4
                    padding: 2
                    rich:
                      c:
                        color: "#4C5058"
                        fontSize: 12
                        fontWeight: bold
                        lineHeight: 20
                - value: =items.Strom2025.state
                  name: "2025"
                  label:
                    show: true
                    formatter: "{c|{c} kWh/Jahr}"
                    backgroundColor: "#F6F8FC"
                    borderColor: "#8C8D8E"
                    borderWidth: 1
                    borderRadius: 4
                    padding: 2
                    rich:
                      c:
                        color: "#4C5058"
                        fontSize: 12
                        fontWeight: bold
                        lineHeight: 20
        tooltip:
          - component: oh-chart-tooltip
            config:
              show: true
    - component: oh-chart
      config:
        chartType: isoWeek
        height: 100%
        options:
          backgroundColor: transparent
        sidebar: true
        visible: "=vars.varPeriod == 'week' ? true : false"
      slots:
        grid:
          - component: oh-chart-grid
            config:
              height: 70%
              includeLabels: true
              left: 70
              right: 70
              show: false
              top: 70
        legend:
          - component: oh-chart-legend
            config:
              left: 70
              orient: horizontal
              show: true
              bottom: 25px
              width: 600
        series:
          - component: oh-aggregate-series
            config:
              aggregationFunction: diff_last
              color: yellow
              dimension1: isoWeekday
              gridIndex: 0
              id: 0
              item: =props.prop_itemVerbrauch
              markLine:
                data:
                  - type: average
                    label:
                      shom: true
                      position: end
                      formatter: "{c} kWh"
                      backgroundColor: "#FF6B22"
                      padding: 2
              name: Strom-Verbrauch
              type: bar
              xAxisIndex: 0
              yAxisIndex: 0
              label:
                show: false
                formatter: =v=>Number.parseFloat(v.data[1]).toFixed(1) + " kWh"
          - component: oh-aggregate-series
            config:
              aggregationFunction: average
              color: "#673AB7"
              dimension1: isoWeekday
              gridIndex: 0
              id: 1
              item: =props.prop_itemTemperatur
              lineStyle:
                width: 2
                type: dashed
              name: Temperatur
              type: line
              step: middle
              xAxisIndex: 0
              yAxisIndex: 1
              symbol: circle
              symbolSize: 5
        tooltip:
          - component: oh-chart-tooltip
            config:
              confine: true
              show: true
              trigger: axis
        xAxis:
          - component: oh-category-axis
            config:
              categoryType: week
              gridIndex: 0
              nameGap: 22
              nameLocation: center
              monthFormat: short
              weekdayFormat: short
        yAxis:
          - component: oh-value-axis
            config:
              axisLabel:
                formatter: "{value} kWh"
              gridIndex: 0
              nameGap: 40
              nameLocation: center
          - component: oh-value-axis
            config:
              axisLabel:
                formatter: "{value} °C"
              gridIndex: 0
              nameGap: 40
              nameLocation: center
              scale: true
              show: true
    - component: oh-chart
      config:
        chartType: month
        height: 100%
        options:
          backgroundColor: transparent
        sidebar: true
        visible: "=vars.varPeriod == 'month' ? true : false"
      slots:
        calendar: []
        grid:
          - component: oh-chart-grid
            config:
              height: 70%
              includeLabels: true
              left: 70
              right: 70
              show: false
              top: 70
        legend:
          - component: oh-chart-legend
            config:
              left: 70
              orient: horizontal
              show: true
              bottom: 25px
              width: 600
        series:
          - component: oh-aggregate-series
            config:
              aggregationFunction: diff_last
              color: yellow
              dimension1: date
              gridIndex: 0
              id: 0
              item: =props.prop_itemVerbrauch
              markLine:
                data:
                  - type: average
                    label:
                      shom: true
                      position: end
                      formatter: "{c} kWh"
                      backgroundColor: "#FF6B22"
                      padding: 2
              markPoint:
                data:
                  - name: min
                    type: min
                  - name: max
                    type: max
              name: Strom-Verbrauch
              type: bar
              xAxisIndex: 0
              yAxisIndex: 0
              label:
                show: false
                formatter: =v=>Number.parseFloat(v.data[1]).toFixed(1) + " kWh"
          - component: oh-aggregate-series
            config:
              aggregationFunction: average
              color: "#673AB7"
              dimension1: date
              gridIndex: 0
              id: 1
              item: =props.prop_itemTemperatur
              lineStyle:
                width: 2
                type: dashed
              name: Temperatur
              type: line
              step: middle
              xAxisIndex: 0
              yAxisIndex: 1
              symbol: circle
              symbolSize: 5
        tooltip:
          - component: oh-chart-tooltip
            config:
              confine: true
              show: true
              trigger: axis
        xAxis:
          - component: oh-category-axis
            config:
              categoryType: month
              gridIndex: 0
              nameGap: 22
              nameLocation: center
              weekdayFormat: short
              monthFormat: short
        yAxis:
          - component: oh-value-axis
            config:
              axisLabel:
                formatter: "{value} kWh"
              gridIndex: 0
              nameGap: 40
              nameLocation: center
          - component: oh-value-axis
            config:
              axisLabel:
                formatter: "{value} °C"
              gridIndex: 0
              nameGap: 40
              nameLocation: center
              scale: true
    - component: oh-chart
      config:
        chartType: day
        height: 100%
        options:
          backgroundColor: transparent
        sidebar: true
        visible: "=vars.varPeriod == 'day' ? true : false"
      slots:
        calendar: []
        grid:
          - component: oh-chart-grid
            config:
              height: 70%
              includeLabels: true
              left: 70
              right: 70
              show: false
              top: 70
        legend:
          - component: oh-chart-legend
            config:
              left: 70
              orient: horizontal
              show: true
              bottom: 25px
              width: 600
        series:
          - component: oh-aggregate-series
            config:
              aggregationFunction: diff_last
              color: yellow
              dimension1: hour
              gridIndex: 0
              id: 0
              item: =props.prop_itemVerbrauch
              markLine:
                data:
                  - type: average
                    label:
                      shom: true
                      position: end
                      formatter: "{c} kWh"
                      backgroundColor: "#FF6B22"
                      padding: 2
              markPoint:
                data:
                  - name: min
                    type: min
                  - name: max
                    type: max
              name: Strom-Verbrauch
              type: bar
              xAxisIndex: 0
              yAxisIndex: 0
              label:
                show: false
                formatter: =v=>Number.parseFloat(v.data[1]).toFixed(1) + " kWh"
          - component: oh-aggregate-series
            config:
              aggregationFunction: average
              color: "#673AB7"
              dimension1: hour
              gridIndex: 0
              id: 1
              item: =props.prop_itemTemperatur
              lineStyle:
                width: 2
                type: dashed
              name: Temperatur
              type: line
              step: middle
              xAxisIndex: 0
              yAxisIndex: 1
              symbol: circle
              symbolSize: 5
        tooltip:
          - component: oh-chart-tooltip
            config:
              confine: true
              show: true
              trigger: axis
        xAxis:
          - component: oh-category-axis
            config:
              categoryType: day
              gridIndex: 0
              nameGap: 22
              nameLocation: center
              monthFormat: short
              weekdayFormat: short
        yAxis:
          - component: oh-value-axis
            config:
              axisLabel:
                formatter: "{value} kWh"
              gridIndex: 0
              nameGap: 40
              nameLocation: center
          - component: oh-value-axis
            config:
              axisLabel:
                formatter: "{value} °C"
              gridIndex: 0
              nameGap: 40
              nameLocation: center
              scale: true
    - component: oh-chart
      config:
        periodVisible: true
        chartType: year
        height: 100%
        options:
          backgroundColor: transparent
        sidebar: false
        visible: "(=vars.varPeriod == 'year' || vars.varPeriod == undefined) ? true :
          false"
      slots:
        calendar: []
        title:
          - component: oh-chart-title
            config:
              show: true
              subtext: "2023: 5664 kWh  -  2024: 5614 kWh"
              top: 0
              left: 170px
        grid:
          - component: oh-chart-grid
            config:
              height: 70%
              includeLabels: true
              left: 75
              right: 75
              show: false
              top: 70
        legend:
          - component: oh-chart-legend
            config:
              left: 25
              orient: horizontal
              show: true
              bottom: 25px
              width: 600
        series:
          - component: oh-aggregate-series
            config:
              aggregationFunction: average
              color: "#007AFF"
              dimension1: month
              gridIndex: 0
              item: =props.prop_itemVerbrauchJahr
              service: inmemory
              noBoundary: true
              offsetAmount: 2
              offsetUnit: year
              lineStyle:
                width: 4
              markLine:
                data:
                  - type: average
                    symbol: none
                    label:
                      shom: true
                      position: start
                      formatter: "{c} kWh"
                      backgroundColor: "#007AFF"
                      padding: 2
              name: Jahr-2
              type: line
              step: middle
              xAxisIndex: 0
              yAxisIndex: 0
          - component: oh-aggregate-series
            config:
              aggregationFunction: average
              color: "#009688"
              dimension1: month
              gridIndex: 0
              item: =props.prop_itemVerbrauchJahr
              service: inmemory
              noBoundary: true
              offsetAmount: 1
              offsetUnit: year
              lineStyle:
                width: 4
              markLine:
                data:
                  - type: average
                    symbol: none
                    label:
                      shom: true
                      position: middle
                      formatter: "{c} kWh"
                      backgroundColor: "#009688"
                      padding: 2
              name: Jahr-1
              type: line
              step: middle
              xAxisIndex: 0
              yAxisIndex: 0
          - component: oh-aggregate-series
            config:
              aggregationFunction: average
              color: yellow
              dimension1: month
              gridIndex: 0
              id: 0
              item: =props.prop_itemVerbrauchJahr
              service: inmemory
              noBoundary: true
              markLine:
                data:
                  - type: average
                    symbol: circle
                    label:
                      shom: true
                      formatter: "{c} kWh"
                      backgroundColor: "#FF6B22"
                      padding: 2
              name: Jahr
              type: bar
              xAxisIndex: 0
              yAxisIndex: 0
          - component: oh-aggregate-series
            config:
              aggregationFunction: average
              color: yellow
              dimension1: month
              gridIndex: 0
              item: =props.prop_itemkWh20xxMonatserwartung
              service: inmemory
              noBoundary: true
              lineStyle:
                width: 2
              markPoint:
                data:
                  - name: max
                    type: max
              name: Monatserwartung
              type: line
              xAxisIndex: 0
              yAxisIndex: 0
              symbol: arrow
              symbolSize: 20
          - component: oh-aggregate-series
            config:
              aggregationFunction: average
              color: "#FF6B22"
              dimension1: month
              gridIndex: 0
              item: =props.prop_itemkWh20xxMonatsdurchschnitt
              service: inmemory
              noBoundary: true
              lineStyle:
                width: 2
              markLine:
                data:
                  - type: average
                    symbol: circle
                    label:
                      shom: true
                      formatter: "{c} kWh"
                      backgroundColor: "#FF6B22"
                      padding: 2
              name: Monat-Ø
              type: line
              xAxisIndex: 0
              yAxisIndex: 0
          - component: oh-aggregate-series
            config:
              aggregationFunction: average
              color: "#673AB7"
              dimension1: month
              gridIndex: 0
              id: 1
              item: =props.prop_itemTemperatur
              noBoundary: true
              lineStyle:
                width: 2
                type: dashed
              name: Temperatur
              type: line
              step: middle
              xAxisIndex: 0
              yAxisIndex: 1
              symbol: circle
              symbolSize: 5
        tooltip:
          - component: oh-chart-tooltip
            config:
              confine: true
              show: true
              trigger: axis
        toolbox:
          - component: oh-chart-toolbox
            config:
              presetFeatures:
                - restore
                - dataView
                - magicType
              top: 8
              left: 10
              show: true
        xAxis:
          - component: oh-category-axis
            config:
              categoryType: year
              gridIndex: 0
              nameGap: 20
              nameLocation: center
              monthFormat: short
        yAxis:
          - component: oh-value-axis
            config:
              axisLabel:
                formatter: "{value} kWh"
              gridIndex: 0
              nameGap: 30
              nameLocation: center
          - component: oh-value-axis
            config:
              axisLabel:
                formatter: "{value} °C"
              gridIndex: 0
              nameGap: 40
              nameLocation: center
              scale: true
Rule which runs every night to update the charts and to calculate the expected power value for current month an the average monthly power value
//
// Update current month value and expected value at end of current month
//
// Format DayDatum 'YYYY-MM-DD'
var datum = items.getItem('DayDatum').state; 
var datum2 = datum;
// get day, month, Year from date
var jahr = datum.substring(0, 4);
jahr = parseInt(jahr);
console.log(jahr); 
// is year a leap year?
var schaltjahr = 0 ;
var jahrxx = parseInt(jahr / 4) ; 
jahrxx = jahrxx * 4 ;
if (jahr == jahrxx) {schaltjahr = 1} ;
//
var monat = datum.substring(5, 7);
monat = parseInt(monat);
console.log(monat);
var tag = datum.substring(8, 10);
tag = parseInt(tag);
console.log(tag);
// I use the 28th of month in chart and widget for month total
datum2 = datum.substring(0, 8) + '28T23:59';
console.log(datum2); 
// last day of month
var last = 31 ;
if (monat == 4 || monat == 6 || monat == 9 || monat == 11) {last = 30} ;
// last day of February - leap year? 
if (monat == 2) {
  last = 28 ;
  if (schaltjahr == 1) {last = 29 } ;
}
// DayMonatswert = kWh of current month  
var monatswert = items.getItem('DayMonatswert').state; 
console.log(monatswert); 
// monatserwartung = expected kWh at the end of current month
monatserwartung = monatswert * last / tag  ;
monatserwartung = Math.round(monatserwartung) ;
console.log(monatserwartung);
monatswert = monatswert + ' kWh';
monatserwartung = monatserwartung + ' kWh';
// in January the average kWh rate over all month in year is equal to expected kWh rate of actual month
if (monat == 1) {
  monatsdurchschnitt = monatserwartung ;
} else {
  // in Feb ... Dez: calculate the average kWh value over all month in year 
  // calculate date until actual Date
  var monatstage = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ] ;  
  if (schaltjahr == 1) { monatstage = [ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]} ;
  // days of actual month
  var tage = tag ;
  console.log(tage);
  var j = monat - 1;
  for (i=0; i < monatstage.length; i++) {
    if (i >= j) {break};
    tage = tage + monatstage[i];
    console.log(tage);
  }
  // DayJahreswert = kWh since 01 Jan of actual year
  var jahreswert = items.getItem('DayJahreswert').state; 
  // monatsdurchschnitt = the average kWh value over all month in year 
  monatsdurchschnitt = jahreswert * last / tage ;
  monatsdurchschnitt = Math.round(monatsdurchschnitt) ;
  console.log(monatsdurchschnitt);
  monatsdurchschnitt = monatsdurchschnitt + ' kWh';
}  
//
// timeSeries20xx for widget
// Replace in TimeSeries current month with month value 'Monatswert' - with policy REPLACE
var timeSeries20xx = new items.TimeSeries('REPLACE'); 
timeSeries20xx.add(time.toZDT(datum2), Quantity(monatswert)) ;
// Persist the TimeSeries for the Item 'kWh20xx' using the InMemory persistence service
items.getItem('kWh20xx').persistence.persist(timeSeries20xx, 'inmemory'); 
// 
// Display the expected kWh value at the end of the month 'Monatserwartung' as seperate value
var timeSeries20yy = new items.TimeSeries('REPLACE'); 
timeSeries20yy.add(time.toZDT(datum2), Quantity(monatserwartung)) ;
// Persist the TimeSeries for the Item 'kWh20xxErwartung' using the InMemory persistence service
items.getItem('kWh20xxErwartung').persistence.persist(timeSeries20yy, 'inmemory'); 
//
// Display the average kWh value over all month of current year 'Monatdurchschnitt' as seperate value
var timeSeries20dd = new items.TimeSeries('REPLACE'); 
timeSeries20dd.add(time.toZDT(datum2), Quantity(monatsdurchschnitt)) ;
// Persist the TimeSeries for the Item 'kWh20xxErwartung' using the InMemory persistence service
items.getItem('kWh20xxMonatsdurchschnitt').persistence.persist(timeSeries20dd, 'inmemory'); 
//

I hope this may help some of you to create good charts

1 Like