Energy dashboard again-----

I am considering migration from Home Assistant to openHAB because I do like the automations editor in Home Assistant and the tool support building your own integrations are poor and in Python (which I hate)…

All of this looks better in openHAB :slight_smile: but check listing what I need from openHAB I can’t find an equivalent to the Energy Dashboard in HA.

In Energy Dashboard - #9 by marcel_verpaalen was a question for Energy Dashboard like HomeAssistant’s and someone fixed an Energy Summary widget: OH3 Livio Energy Summary Animated

But what about the rest of the Energy Dashboard:

  • the colored hourly energy consumption based on whether the consumption is fulfilled using my own current production, from grid, discharging the house battery or is from charging the house battery.
  • a hourly solar production and prediction (the prediction comes from forecast.solar)
  • and a cost/revenue summary for each of the consumption categories.

Is it all DIY from scratch? and if is it doable?

Example of what it looks like in HA:

Welcome!

I’ve moved your post to a more appropriate category. The Tutorials and Solutions category is a place to post tutorials, not request them.

OH comes with a fairly flexible charting capability. I would be surprised if what you are looking for isn’t possible but I personally don’t do much with Charts so I can’t offer advice on how to set it up like that. But in general you’ll probably not find much about using just energy search terms since it’s a generic capability. So yes, unless someone has published a widget on the marketplace you’ll probably have to configure this from scratch.

Unfortunately I don’t see a Forecast.solar add-on. Though it does appear to have a fairly straight forward API (see Problem Reading PV Forecast via HTTP Binding from API Forecast.Solar for one example and search the forum for more).

There are also Solcast (see Solcast sendHttpGetRequest).

However, OH’s charting assumes a time series in the past so it might take some work to generate a forecast chart like that. I don’t think it’s impossible but I’ve not seen it done yet. So this too would be something that needs to be built.

That’s straight forward. Some Items and some rules to run the calculations and a widget to show the current Item’s calculated state.

dear for graph I used Grafana integrated in OH

for costs…it’s a simple rule with some calculations

later I will publish some pictures

I created a small widget which displays my production/consumption/injection per day, month, year. All this is just text. When clicking on one of the items, a OH chart pop-ups. More details and cost calculations are in Grafana.

I’m also very interested in the forecast.solar thing. Hopefully someone van create a binding in the future.

I just used the http binding a while back to quick get data from the forecast.solar api.

UID: http:url:450cc0b512
label: Forecast.Solar API
thingTypeUID: http:url
configuration:
  authMode: BASIC
  ignoreSSLErrors: false
  baseURL: API_CALL_HERE
  delay: 0
  stateMethod: GET
  refresh: 600
  commandMethod: GET
  contentType: application/json
  timeout: 3000
  bufferSize: 2048
channels:
  - id: response
    channelTypeUID: http:string
    label: API response
    description: ""
    configuration:
      mode: READONLY

But in the end I ended up not really using the thing/item because it was so much easier just to include the API call directing in the rule code I was writing.

Actually I so the same for some other stuff. Can you share this rule which you are using?

This is with ECMAScript-2021 (the JSScripting add-on):

var now = time.ZonedDateTime.now();
var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.SolarForecast');
var runtime = require("@runtime")

var mainPanelUrl = 'API_URL_HERE';
var northPanelUrl = 'API_URL_HERE';

var mainForecast = JSON.parse(actions.HTTP.sendHttpGetRequest(mainPanelUrl));
var northForecast = JSON.parse(actions.HTTP.sendHttpGetRequest(northPanelUrl));
logger.info(JSON.stringify(mainForecast));

var startHour = now.format(time.DateTimeFormatter.ofPattern('yyyy-MM-dd HH:00:00'));
var endHour = now.plusHours(1).format(time.DateTimeFormatter.ofPattern('yyyy-MM-dd HH:00:00'));

var mainMin = mainForecast.result.watts[startHour] || 0;
var mainMax = mainForecast.result.watts[endHour] || 0;
var northMin = northForecast.result.watts[startHour] || 0;
var northMax = northForecast.result.watts[endHour] || 0;

var mainEstimate = mainMin + ((mainMax - mainMin) * now.minute() / 60);
var northEstimate = northMin + ((northMax - northMin) * now.minute() / 60);
var totalEstimate = Math.round(mainEstimate + northEstimate);

logger.info(`Main cells: ${mainMin} - ${mainMax}, North cells: ${northMin} - ${northMax}, Current estimate at ${now.minute()} - ${totalEstimate} (${totalEstimateAdj} adjusted)`);
items.getItem('SolarForecast_Watts').sendCommand(totalEstimate);

var mainMinH = mainForecast.result.watt_hours[startHour] || 0;
var mainMaxH = mainForecast.result.watt_hours[endHour] || 0;
var northMinH = northForecast.result.watt_hours[startHour] || 0;
var northMaxH = northForecast.result.watt_hours[endHour] || 0;

var mainEstimateH = mainMinH + ((mainMaxH - mainMinH) * now.minute() / 60);
var northEstimateH = northMinH + ((northMaxH - northMinH) * now.minute() / 60);
var totalEstimateH = Math.round(mainEstimateH + northEstimateH);

logger.info(`Main cells: ${mainMinH} - ${mainMaxH}, North cells: ${northMinH} - ${northMaxH}, Current estimate at ${now.minute()} - ${totalEstimateH}`);
items.getItem('SolarForecast_WattHours').sendCommand(totalEstimateH);

thanks!
If I understand it well, you only store the data for the specific hour (now). And not for all future hours the coming 48 hours (which I get back with the public API).
I am planning to inject this data once a day to my influxdb to have a nice forecast graph above my actual production. Or is this not the way to go?

Hi ,

Is possible to share the code for the widget and graphs ?

Thanks
Artur

I created one widget, which can show me data of today, yesterday, this month, last month or this year. This can be modified via a prop:
image

All the values are calculated via rules and added to items. All these items have the same suffixes (today, yesterday, thisMonth…) to make it easier.
If I choose today, the widged will also show my battery level and rainwater tank.

So this widget is certainly not useable for everybody, cause I made it specific for my needs (and I’m not a widget expert at all)

uid: solarman_energy
tags: []
props:
  parameters:
    - default: today
      description: Time for card. Must be today, yesterday, thisMonth, prevMonth or thisYear
      label: Period
      name: period
      required: false
      type: TEXT
      pattern: today|yesterday|thisMonth|prevMonth|thisYear
  parameterGroups: []
timestamp: Jun 8, 2022, 10:06:36 PM
component: f7-card
config:
  style:
    border-radius: var(--f7-card-expandable-border-radius)
    box-shadow: 5px 5px 10px 1px rgba(0,0,0,0.1)
    margin-left: 5px
    margin-right: 5px
    noShadow: false
    padding: 0px
  title: '="Energy " + (props.period == "thisMonth" ? "this month" : props.period == "prevMonth" ? "previous month": props.period == "thisYear" ? "this year": props.period)'
slots:
  default:
    - component: f7-row
      config:
        style:
          align-items: left
          justify-content: left
          margin-left: 10px
          margin-top: 10px
        visible: true
      slots:
        default:
          - component: oh-icon
            config:
              color: lightgreen
              height: 30
              icon: iconify:mdi:solar-power-variant
              style:
                margin-right: 10px
          - component: Label
            config:
              style:
                font-size: 17px
                font-weight: 700
                margin-left: 0px
              text: Solar Panels
    - component: f7-row
      config:
        style:
          align-items: center
          justify-content: center
          margin-left: 20px
          margin-top: 10px
        visible: true
      slots:
        default:
          - component: f7-col
            config:
              class:
                - display-flex
                - justify-content-left
            slots:
              default:
                - component: oh-icon
                  config:
                    color: green
                    height: 30
                    icon: iconify:mdi:solar-power
                    style:
                      margin-right: 10px
                - component: oh-link
                  config:
                    action: analyzer
                    actionAnalyzerItems: =['solarman_CumulativeProductionActive_' + props.period]
                    color: white
                    style:
                      //font-weight: bold
                      font-size: 20px
                      margin: 0px 0px
                    text: =items['solarman_CumulativeProductionActive_' + props.period].state
          - component: f7-col
            config:
              class:
                - display-flex
                - justify-content-left
            slots:
              default:
                - component: oh-icon
                  config:
                    color: red
                    height: 30
                    icon: iconify:mdi:flash
                    style:
                      margin-right: 10px
                - component: oh-link
                  config:
                    action: analyzer
                    actionAnalyzerItems: =['solarman_CumulativeConsumption_' + props.period]
                    color: white
                    style:
                      //font-weight: bold
                      font-size: 20px
                      margin: 0px 0px
                    text: =items['solarman_CumulativeConsumption_' + props.period].state
    - component: f7-row
      config:
        style:
          align-items: center
          justify-content: center
          margin-left: 20px
          margin-top: 10px
        visible: '=props.period == "today" ? true : false'
      slots:
        default:
          - component: f7-col
            config:
              class:
                - display-flex
                - justify-content-left
            slots:
              default:
                - component: oh-icon
                  config:
                    color: green
                    height: 30
                    icon: iconify:mdi:transmission-tower-import
                    style:
                      margin-right: 10px
                - component: oh-link
                  config:
                    action: analyzer
                    actionAnalyzerItems: =['solarman_DailyGridFeedin']
                    color: white
                    style:
                      //font-weight: bold
                      font-size: 20px
                      margin: 0px 0px
                    text: =items['solarman_DailyGridFeedin'].state + ' kWh'
          - component: f7-col
            config:
              class:
                - display-flex
                - justify-content-left
            slots:
              default:
                - component: oh-icon
                  config:
                    color: red
                    height: 30
                    icon: iconify:mdi:transmission-tower-export
                    style:
                      margin-right: 10px
                - component: oh-link
                  config:
                    action: analyzer
                    actionAnalyzerItems: =['solarman_DailyEnergyPurchased']
                    color: white
                    style:
                      //font-weight: bold
                      font-size: 20px
                      margin: 0px 0px
                    text: =items['solarman_DailyEnergyPurchased'].state + ' kWh'
    - component: f7-row
      config:
        style:
          align-items: center
          justify-content: center
          margin-left: 30px
          margin-top: 10px
        visible: '=props.period == "today" ? true : false'
      slots:
        default:
          - component: f7-col
            config:
              class:
                - display-flex
                - justify-content-left
            slots:
              default:
                - component: oh-icon
                  config:
                    color: purple
                    height: 30
                    icon: iconify:mdi:home-battery
                    style:
                      margin-right: 10px
                - component: oh-link
                  config:
                    action: analyzer
                    actionAnalyzerItems: =['solarman_SoCBatteryPack1']
                    color: white
                    style:
                      //font-weight: bold
                      font-size: 20px
                      margin: 0px 0px
                    text: =items['solarman_SoCBatteryPack1'].state + ' %'
    - component: f7-row
      config:
        style:
          align-items: left
          justify-content: left
          margin-left: 10px
          margin-top: 10px
        visible: true
      slots:
        default:
          - component: oh-icon
            config:
              color: yellow
              height: 25
              icon: iconify:mdi:meter-electric
              style:
                margin-right: 10px
          - component: Label
            config:
              style:
                font-size: 17px
                font-weight: 700
                margin-left: 0px
              text: Electricity
    - component: f7-row
      config:
        style:
          align-items: center
          justify-content: center
          margin-left: 20px
          margin-top: 10px
        visible: true
      slots:
        default:
          - component: f7-col
            config:
              class:
                - display-flex
                - justify-content-left
            slots:
              default:
                - component: oh-icon
                  config:
                    color: green
                    height: 30
                    icon: iconify:mdi:transmission-tower-import
                    style:
                      margin-right: 10px
                - component: oh-link
                  config:
                    action: analyzer
                    actionAnalyzerItems: =['mqtt_dsmr_electricityReturned_' + props.period]
                    color: white
                    style:
                      //font-weight: bold
                      font-size: 20px
                      margin: 0px 0px
                    text: =items['mqtt_dsmr_electricityReturned_' + props.period].state
          - component: f7-col
            config:
              class:
                - display-flex
                - justify-content-left
            slots:
              default:
                - component: oh-icon
                  config:
                    color: red
                    height: 30
                    icon: iconify:mdi:transmission-tower-export
                    style:
                      margin-right: 10px
                - component: oh-link
                  config:
                    action: analyzer
                    actionAnalyzerItems: =['mqtt_dsmr_electricityDelivered_' + props.period]
                    color: white
                    style:
                      //font-weight: bold
                      font-size: 20px
                      margin: 0px 0px
                    text: =items['mqtt_dsmr_electricityDelivered_' + props.period].state
    - component: f7-row
      config:
        style:
          align-items: left
          justify-content: left
          margin-left: 10px
          margin-top: 10px
        visible: true
      slots:
        default:
          - component: oh-icon
            config:
              color: orange
              height: 25
              icon: iconify:mdi:meter-gas
              style:
                margin-right: 10px
          - component: Label
            config:
              style:
                font-size: 17px
                font-weight: 700
                margin-left: 0px
              text: Gas
    - component: f7-row
      config:
        style:
          align-items: center
          justify-content: center
          margin-left: 30px
          margin-top: 10px
        visible: true
      slots:
        default:
          - component: f7-col
            config:
              class:
                - display-flex
                - justify-content-left
            slots:
              default:
                - component: oh-icon
                  config:
                    color: orange
                    height: 30
                    icon: iconify:mdi:meter-gas
                    style:
                      margin-right: 10px
                - component: oh-link
                  config:
                    action: analyzer
                    actionAnalyzerItems: =['mqtt_dsmr_gas_' + props.period]
                    color: white
                    style:
                      //font-weight: bold
                      font-size: 20px
                      margin: 0px 0px
                    text: =items['mqtt_dsmr_gas_' + props.period].displayState
    - component: f7-row
      config:
        style:
          align-items: left
          justify-content: left
          margin-left: 10px
          margin-top: 10px
        visible: true
      slots:
        default:
          - component: oh-icon
            config:
              color: lightblue
              height: 30
              icon: iconify:mdi:water
              style:
                margin-right: 10px
          - component: Label
            config:
              style:
                font-size: 17px
                font-weight: 700
                margin-left: 0px
              text: Water
    - component: f7-row
      config:
        style:
          align-items: center
          justify-content: center
          margin-left: 20px
          margin-top: 10px
        visible: true
      slots:
        default:
          - component: f7-col
            config:
              class:
                - display-flex
                - justify-content-left
            slots:
              default:
                - component: oh-icon
                  config:
                    color: lightblue
                    height: 30
                    icon: iconify:mdi:cup-water
                    style:
                      margin-right: 10px
                - component: oh-link
                  config:
                    action: analyzer
                    actionAnalyzerItems: =['mqtt_pulse_water' + (props.period).substring(0, 1).toUpperCase() + (props.period).substring(1)]
                    color: white
                    style:
                      //font-weight: bold
                      font-size: 20px
                      margin: 0px 0px
                    text: =items['mqtt_pulse_water' + (props.period).substring(0, 1).toUpperCase() + (props.period).substring(1)].displayState
          - component: f7-col
            config:
              class:
                - display-flex
                - justify-content-left
              visible: '=props.period == "today" ? true : false'
            slots:
              default:
                - component: oh-icon
                  config:
                    color: lightblue
                    height: 30
                    icon: iconify:mdi:water-well
                    style:
                      margin-right: 10px
                - component: oh-link
                  config:
                    action: analyzer
                    actionAnalyzerItems: =['rainwater_percent']
                    color: white
                    style:
                      //font-weight: bold
                      font-size: 20px
                      margin: 0px 0px
                    text: =items['rainwater_percent'].displayState
    - component: f7-card-footer
      slots:
        default:
          - component: Label
            config:
              text: '="Last update: " + dayjs(items.solarman_lastupdate_.state).fromNow()'

Thanks !!!

That’s correct. I found that the forecast.solar predictions weren’t quite as accurate as I had hoped for my system. However, the forecast values are refined throughout the day so this was an attempt to see if the values got closer to my system production as the day went on by continually updating the values and doing a little linear interpolation between the hour values.

That may be a fine way to go for your system, I think this isn’t so much a right/wrong choice as a personal decision. I even tried building a custom estimate from the astro sun data which was slightly better. In the end I dropped getting a solar estimate from my todo list and went on to other projects.

If you’re planning on just one call a day ans processing the data in a rule to push to influxDB then the http binding is probably the (ever-so-slightly) easier way to do go.