In needed of a chart that shows todays and tomorrows hourly prices gathered through the Tibber Binding i created this widget for the MainUI.
You only need these three channels of the tibber thing linked to corresponding items. No transformations etc. needed. To see “Prices for today” and “Prices for tomorrow” you need to tick on “Show advanced”
The chart will also work if you only supply one JSON. Horizontal lines will be shortened and tomorrows 6,12,18,24 will get visible set to false.
Currently the y-axis only shows a fixed price range from 0 to 40 cents; i plan on making the range dynamic to be able to show extreme low and high prices when necessary.
Screenshots
Only todays prices without spacing of the bars
Today and tomorrow without spacing and current hour indication
Default colors work best on dark profile and can be changed in “Configure Widget” dialog
Changelog
Version 0.1
- initial release
Resources
uid: tibber2DayChart
tags:
- tibber
- chart
props:
parameters:
- context: item
label: JSON of todays prices
name: jsonPricesToday
required: false
type: TEXT
- context: item
label: JSON of tomorrows prices
name: jsonPricesTomorrow
required: false
type: TEXT
- context: item
label: Timestamp for measurement (empty for no highlighting)
name: dtMeasurement
required: false
type: TEXT
- label: graph color (default rgba(35, 184, 204, 0.55))
name: graph_background
required: false
type: TEXT
- label: graph color for current hour (default rgba(35, 184, 204, 0.9))
name: graph_background_now
required: false
type: TEXT
- label: graph x-axis text color (default= lightgrey)
name: graph_x_axis_text_color
required: false
type: TEXT
- label: graph y-axis text color (default= lightgrey)
name: graph_y_axis_text_color
required: false
type: TEXT
- label: graph axis line color (default= grey)
name: graph_axis_line_color
required: false
type: TEXT
- label: graph spacing between hourbars (default= 0)
name: graph_spacing
required: false
parameterGroups: []
timestamp: Feb 20, 2024, 5:16:37 PM
component: oh-repeater
config:
for: coords
fragment: true
in:
- graph_axis_line_color: =props.graph_axis_line_color?props.graph_axis_line_color :'grey'
graph_background: =props.graph_background?props.graph_background:'rgba(35, 184, 204, 0.55)'
graph_background_now: =props.graph_background_now?props.graph_background_now:'rgba(35, 184, 204, 0.90)'
graph_spacing: =props.graph_spacing?props.graph_spacing:0
graph_x_axis_text_color: =props.graph_x_axis_text_color?props.graph_x_axis_text_color :'lightgrey'
graph_y_axis_text_color: =props.graph_y_axis_text_color?props.graph_y_axis_text_color :'lightgrey'
p0: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[0].total)) * 450
p1: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[1].total)) * 450
p2: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[2].total)) * 450
p3: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[3].total)) * 450
p4: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[4].total)) * 450
p5: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[5].total)) * 450
p6: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[6].total)) * 450
p7: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[7].total)) * 450
p8: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[8].total)) * 450
p9: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[9].total)) * 450
p10: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[10].total)) * 450
p11: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[11].total)) * 450
p12: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[12].total)) * 450
p13: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[13].total)) * 450
p14: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[14].total)) * 450
p15: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[15].total)) * 450
p16: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[16].total)) * 450
p17: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[17].total)) * 450
p18: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[18].total)) * 450
p19: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[19].total)) * 450
p20: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[20].total)) * 450
p21: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[21].total)) * 450
p22: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[22].total)) * 450
p23: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesToday].state)[23].total)) * 450
p24: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[0].total)) * 450
p25: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[1].total)) * 450
p26: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[2].total)) * 450
p27: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[3].total)) * 450
p28: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[4].total)) * 450
p29: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[5].total)) * 450
p30: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[6].total)) * 450
p31: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[7].total)) * 450
p32: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[8].total)) * 450
p33: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[9].total)) * 450
p34: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[10].total)) * 450
p35: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[11].total)) * 450
p36: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[12].total)) * 450
p37: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[13].total)) * 450
p38: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[14].total)) * 450
p39: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[15].total)) * 450
p40: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[16].total)) * 450
p41: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[17].total)) * 450
p42: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[18].total)) * 450
p43: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[19].total)) * 450
p44: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[20].total)) * 450
p45: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[21].total)) * 450
p46: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[22].total)) * 450
p47: =200 - (Number.parseFloat(JSON.parse(items[props.jsonPricesTomorrow].state)[23].total)) * 450
sourceType: array
slots:
default:
- component: f7-card
config:
style:
height: 235px
slots:
default:
- component: f7-block
config:
style:
display: flex
flex-direction: column
left: -10px
position: absolute
top: -5px
slots:
default:
- component: Label
config:
style:
color: =`${loop.coords.graph_y_axis_text_color}`
font-size: 12px
margin-top: 0px
text: 40
- component: Label
config:
style:
color: =`${loop.coords.graph_y_axis_text_color}`
font-size: 12px
margin-top: 25px
text: 30
- component: Label
config:
style:
color: =`${loop.coords.graph_y_axis_text_color}`
font-size: 12px
margin-top: 25px
text: 20
- component: Label
config:
style:
color: =`${loop.coords.graph_y_axis_text_color}`
font-size: 12px
margin-top: 25px
text: 10
- component: Label
config:
style:
color: =`${loop.coords.graph_y_axis_text_color}`
font-size: 12px
margin-top: 25px
text: 0
- component: f7-block
config:
style:
display: flex
flex-direction: row
slots:
default:
- component: Label
config:
style:
color: =`${loop.coords.graph_x_axis_text_color}`
font-size: 12px
margin-left: 5px
text: 0
- component: Label
config:
style:
color: =`${loop.coords.graph_x_axis_text_color}`
font-size: 12px
margin-left: 53px
text: 6
- component: Label
config:
style:
color: =`${loop.coords.graph_x_axis_text_color}`
font-size: 12px
margin-left: 50px
text: 12
- component: Label
config:
style:
color: =`${loop.coords.graph_x_axis_text_color}`
font-size: 12px
margin-left: 50px
text: 18
- component: Label
config:
style:
color: =`${loop.coords.graph_x_axis_text_color}`
font-size: 12px
margin-left: 48px
text: 24
- component: Label
config:
style:
color: =`${loop.coords.graph_x_axis_text_color}`
font-size: 12px
margin-left: 50px
visible: =props.jsonPricesTomorrow ? true:false
text: 6
- component: Label
config:
style:
color: =`${loop.coords.graph_x_axis_text_color}`
font-size: 12px
margin-left: 50px
visible: =props.jsonPricesTomorrow ? true:false
text: 12
- component: Label
config:
style:
color: =`${loop.coords.graph_x_axis_text_color}`
font-size: 12px
margin-left: 50px
visible: =props.jsonPricesTomorrow ? true:false
text: 18
- component: Label
config:
style:
color: =`${loop.coords.graph_x_axis_text_color}`
font-size: 12px
margin-left: 48px
visible: =props.jsonPricesTomorrow ? true:false
text: 24
- component: svg
config:
height: 100%
width: 100%
slots:
default:
- component: polygon
config:
fill: =loop.coords.graph_axis_line_color
points: =`30,19 30,21 ${props.jsonPricesTomorrow?"510":"270"},21 ${props.jsonPricesTomorrow?"510":"270"},19`
- component: polygon
config:
fill: =loop.coords.graph_axis_line_color
points: =`30,64 30,66 ${props.jsonPricesTomorrow?"510":"270"},66 ${props.jsonPricesTomorrow?"510":"270"},64`
- component: polygon
config:
fill: =loop.coords.graph_axis_line_color
points: =`30,109 30,111 ${props.jsonPricesTomorrow?"510":"270"},111 ${props.jsonPricesTomorrow?"510":"270"},109`
- component: polygon
config:
fill: =loop.coords.graph_axis_line_color
points: =`30,154 30,156 ${props.jsonPricesTomorrow?"510":"270"},156 ${props.jsonPricesTomorrow?"510":"270"},154`
- component: polygon
config:
fill: =loop.coords.graph_axis_line_color
points: =`30,198 30,200 ${props.jsonPricesTomorrow?"510":"270"},200 ${props.jsonPricesTomorrow?"510":"270"},198`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('HH')=="0"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`40,${loop.coords.p0} 30,${loop.coords.p0} 30,200 ${40-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="1"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`50,${loop.coords.p1} 40,${loop.coords.p1} 40,200 ${50-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="2"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`60,${loop.coords.p2} 50,${loop.coords.p2} 50,200 ${60-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="3"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`70,${loop.coords.p3} 60,${loop.coords.p3} 60,200 ${70-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="4"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`80,${loop.coords.p4} 70,${loop.coords.p4} 70,200 ${80-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="5"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`90,${loop.coords.p5} 80,${loop.coords.p5} 80,200 ${90-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="6"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`100,${loop.coords.p6} 90,${loop.coords.p6} 90,200 ${100-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="7"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`110,${loop.coords.p7} 100,${loop.coords.p7} 100,200 ${110-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="8"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`120,${loop.coords.p8} 110,${loop.coords.p8} 110,200 ${120-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="9"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`130,${loop.coords.p9} 120,${loop.coords.p9} 120,200 ${130-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="10"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`140,${loop.coords.p10} 130,${loop.coords.p10} 130,200 ${140-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="11"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`150,${loop.coords.p11} 140,${loop.coords.p11} 140,200 ${150-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="12"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`160,${loop.coords.p12} 150,${loop.coords.p12} 150,200 ${160-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="13"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`170,${loop.coords.p13} 160,${loop.coords.p13} 160,200 ${170-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="14"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`180,${loop.coords.p14} 170,${loop.coords.p14} 170,200 ${180-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="15"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`190,${loop.coords.p15} 180,${loop.coords.p15} 180,200 ${190-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="16"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`200,${loop.coords.p16} 190,${loop.coords.p16} 190,200 ${200-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="17"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`210,${loop.coords.p17} 200,${loop.coords.p17} 200,200 ${210-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="18"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`220,${loop.coords.p18} 210,${loop.coords.p18} 210,200 ${220-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="19"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`230,${loop.coords.p19} 220,${loop.coords.p19} 220,200 ${230-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="20"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`240,${loop.coords.p20} 230,${loop.coords.p20} 230,200 ${240-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="21"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`250,${loop.coords.p21} 240,${loop.coords.p21} 240,200 ${250-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="22"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`260,${loop.coords.p22} 250,${loop.coords.p22} 250,200 ${260-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =dayjs(items[props.dtMeasurement].state).format('H')=="23"?`${loop.coords.graph_background_now}`:`${loop.coords.graph_background}`
points: =`270,${loop.coords.p23} 260,${loop.coords.p23} 260,200 ${270-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`280,${loop.coords.p24} 270,${loop.coords.p24} 270,200 ${280-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`290,${loop.coords.p25} 280,${loop.coords.p25} 280,200 ${290-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`300,${loop.coords.p26} 290,${loop.coords.p26} 290,200 ${300-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`310,${loop.coords.p27} 300,${loop.coords.p27} 300,200 ${310-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`320,${loop.coords.p28} 310,${loop.coords.p28} 310,200 ${320-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`330,${loop.coords.p29} 320,${loop.coords.p29} 320,200 ${330-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`340,${loop.coords.p30} 330,${loop.coords.p30} 330,200 ${340-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`350,${loop.coords.p31} 340,${loop.coords.p31} 340,200 ${350-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`360,${loop.coords.p32} 350,${loop.coords.p32} 350,200 ${360-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`370,${loop.coords.p33} 360,${loop.coords.p33} 360,200 ${370-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`380,${loop.coords.p34} 370,${loop.coords.p34} 370,200 ${380-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`390,${loop.coords.p35} 380,${loop.coords.p35} 380,200 ${390-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`400,${loop.coords.p36} 390,${loop.coords.p36} 390,200 ${400-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`410,${loop.coords.p37} 400,${loop.coords.p37} 400,200 ${410-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`420,${loop.coords.p38} 410,${loop.coords.p38} 410,200 ${420-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`430,${loop.coords.p39} 420,${loop.coords.p39} 420,200 ${430-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`440,${loop.coords.p40} 430,${loop.coords.p40} 430,200 ${440-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`450,${loop.coords.p41} 440,${loop.coords.p41} 440,200 ${450-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`460,${loop.coords.p42} 450,${loop.coords.p42} 450,200 ${460-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`470,${loop.coords.p43} 460,${loop.coords.p43} 460,200 ${470-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`480,${loop.coords.p44} 470,${loop.coords.p44} 470,200 ${480-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`490,${loop.coords.p45} 480,${loop.coords.p45} 480,200 ${490-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`500,${loop.coords.p46} 490,${loop.coords.p46} 490,200 ${500-loop.coords.graph_spacing},200`
- component: polygon
config:
fill: =loop.coords.graph_background
points: =`510,${loop.coords.p47} 500,${loop.coords.p47} 500,200 ${510-loop.coords.graph_spacing},200`