A minialistic widget displaying forecasted and actual solar production for the current week.
Forecasted and actual values are displayed using a bullet-style bar chart.
The data is retrieved from persistence, with both Item and persistence service configurable per series.
Additionally, series colors and labels can be customised.
Really like this and have a version running now on my set up, however for me it would be more useful if it could show a rolling 7 days and not always start from Monday as this would display more useful historic data. I cannot see how this could be adjusted for that though, is it possible?
Have changed it to
chartType: dynamic
and
period: 6D
but cannot see how to not always start on a Monday, but the ‘last’ bar being the current day.
@florian-h05 Thank you for this cool and useful widget.
I have a minor issue with the forecast values. Not sure if it is related to the widget or the aggregated data. The forecast value for Sunday is not shown. IIRC the aggregation function last (Latest) is used.
I will test a different aggregation function other than last on next Sunday.
To clarify: The forcast service delivers values for up to two days (today and tomorrow). On Monday I can see todays (Mondays) forecast value and tomorrows (Tuesdays) forecast value. Until Saturday the widget shows data like described. On Sunday I do not see the todays (Sundays) value, the column remains empty.
Here is my code.
editable: true
uid: solarForecast
tags:
- chart
props:
parameters:
- context: item
description: Item for forecasted energy (stored in persistence)
label: Item
name: forecastItem
required: true
type: TEXT
groupName: forecast
- context: persistenceService
description: Persistence service for forecasted energy Item
label: Persistence Service
name: forecastService
required: false
type: TEXT
groupName: forecast
- default: last
description: Aggregation function for forecasted energy Item
label: Aggregation Funktion
name: forecastAggregationFunction
required: false
type: TEXT
groupName: forecast
options:
- label: Average
value: average
- label: Sum
value: sum
- label: Minimum
value: min
- label: Maximum
value: max
- label: First (earliest)
value: first
- label: Last (latest)
value: last
- label: Difference of firsts
value: diff_first
- label: Difference of lasts
value: diff_last
- context: item
description: Item for actual energy produced (stored in persistence)
label: Item
name: actualItem
required: true
type: TEXT
groupName: actual
- context: persistenceService
description: Persistence service for actual energy Item
label: Persistence Service
name: actualService
required: false
type: TEXT
groupName: actual
- default: last
description: Aggregation function for actual energy Item
label: Aggregation Funktion
name: actualAggregationFunction
required: false
type: TEXT
groupName: actual
options:
- label: Average
value: average
- label: Sum
value: sum
- label: Minimum
value: min
- label: Maximum
value: max
- label: First (earliest)
value: first
- label: Last (latest)
value: last
- label: Difference of firsts
value: diff_first
- label: Difference of lasts
value: diff_last
- default: kWh
description: Y-Axis Unit
name: yAxisName
required: false
type: TEXT
- default: 250px
description: Height of the widget (any CSS height value supported, but
<code>px</code> is recommended)
label: Height
name: height
required: false
type: TEXT
groupName: appearance
- default: Forecast
description: Chart label (will be displayed in the legend and on tooltip hover)
for forecasted production
label: Forecast Label
name: forecastLabel
required: false
type: TEXT
groupName: appearance
- default: Actual
description: Chart label (will be displayed in the legend and on tooltip hover)
for actual produced energy
label: Actual Label
name: actualLabel
required: false
type: TEXT
groupName: appearance
- context: color
default: "#ff9800"
description: Color for produced energy bar
name: colorProduced
required: false
type: TEXT
groupName: appearance
- context: color
default: "#999999"
description: Color for forecasted energy bar (light mode)
name: colorForecastLight
required: false
type: TEXT
groupName: appearance
- context: color
default: "#e0e0e0"
description: Color for forecasted energy bar (dark mode)
name: colorForecastDark
required: false
type: TEXT
groupName: appearance
parameterGroups:
- name: forecast
label: Forecasted Production
- name: actual
label: Actual Production
- name: appearance
label: Appearance
timestamp: May 18, 2026, 8:28:18 PM
component: oh-context
config:
constants:
aggregateDimension1: isoWeekday
backgroundColor: "=themeOptions.dark === 'dark' ? '#1c1c1d' : '#fff'"
functions:
forecastFormatter: "=(params) => Number(params.value[1]) ?
Number(params.value[1]).toFixed(3).toString(). replace('.',',') : ''"
producedFormatter: =(params) => Number(params.value[1]).toFixed(3).toString().replace('.',',')
tooltipFormatter: =(value, index) =>
Number(value).toFixed(3).toString().replace('.', ',') + ' ' +
props.yAxisName
slots:
default:
- 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
slots:
content:
- component: oh-chart
config:
chartType: isoWeek
height: =props.height
options:
backgroundColor: =const.backgroundColor
periodVisible: false
slots:
grid:
- component: oh-chart-grid
config:
bottom: 30
containLabel: true
left: 5
right: 5
top: 10
legend:
- component: oh-chart-legend
config:
bottom: 0
show: true
series:
- component: oh-aggregate-series
config:
aggregationFunction: =props.forecastAggregationFunction
barWidth: 50%
dimension1: =const.aggregateDimension1
item: =props.forecastItem
itemStyle:
color: "=themeOptions.dark === 'dark' ? props.colorForecastDark :
props.colorForecastLight"
label:
color: "=themeOptions.dark === 'dark' ? props.colorForecastDark :
props.colorForecastLight"
formatter: =fn.forecastFormatter
position: top
show: true
name: =props.forecastLabel + ' (in ' + props.yAxisName + ')'
service: =props.forecastService
type: bar
noItemState: true
- component: oh-aggregate-series
config:
aggregationFunction: =props.actualAggregationFunction
barGap: -60%
barWidth: 50%
dimension1: =const.aggregateDimension1
item: =props.actualItem
itemStyle:
color: =props.colorProduced
label:
color: =props.colorProduced
formatter: =fn.producedFormatter
position: top
show: true
name: =props.actualLabel + ' (in ' + props.yAxisName + ')'
service: =props.actualService
type: bar
noItemState: true
tooltip:
- component: oh-chart-tooltip
config:
show: true
trigger: axis
valueFormatter: =fn.tooltipFormatter
xAxis:
- component: oh-category-axis
config:
axisLine:
show: false
axisTick:
show: false
categoryType: week
weekdayFormat: short
yAxis:
- component: oh-value-axis
config:
axisLabel:
show: false
splitLine:
show: false
I changed your original widget code because I like to use different aggregation functions other than yours for my charts. I am using last for aggregation of forecast energy values and diff_last for energy production.
At the moment I have the slight feeling that there is an issue with the aggregation of forecast values when using the aggregation function last. Not only in the widget but in charts too. On Sundays the aggregated value of Sunday is not shown in a chart with dimension isoWeekday.
// edit: When using the aggregation function max in my setup the value for Sunday is shown.
Do you know have an idea what I am facing? If not please ask again.
What openHAB version do you use? 5.2 M4 contains a number of fixes for chart aggregation functions.
Charts and charting in widgets is the same thing, there is no difference besides where it is displayed in.