You just couldn’t resist a challenge! Great work!
Thanks for the great Work !!!
Wow, very cool! Thanks for the work!
Are the animations possible or does the technology not allow it?
Probably yes with offset-path
and offset-distance
it seems… but as usual you can forget Safari. You can define animation keyframes with the stylesheet
config property.
For instance, this demo:
Can be reproduced like so:
component: f7-card
slots:
content:
- component: f7-block
config:
style:
height: 150px
stylesheet: >
@keyframes path-move {
0% { offset-distance: 0%; }
100% { offset-distance: 100%; }
}
slots:
default:
- component: f7-block
config:
style:
width: 40px
height: 40px
background: cyan
animation: path-move 3000ms infinite alternate ease-in-out
offset-path: path('M20,20 C20,100 200,0 200,100')
going further note that you can override the animation speed with:
animation-duration: =Math.round(3000 - Number.parseFloat(items.SomeValue.state.split(' ')[0]) * 300) + 'ms'`
(or something better) to e.g. make it faster when the item quantity state increases.
More info here:
I’ll leave that as an exercise for the reader
Wow, this is really awesome. Many thanks for your efforts. I also noticed this widget on HA pages.
I’m very new to OH and haven’t started to make my own pages yet because I’m still setting up my controllers with Modbus interface (e.g. Steca inverter). So, I’m wondering how to use this widget.
This is really great. Did also anybody try to make the energy dashboard:
Is this somehow feasible in OH3 MainUI?
So it may be right - I couldn’t resist a challenge.
So going back to this - and yet it’s a hack and could be improved but here it is (I think some have found out this trick before me):
if you want to build your own HTML hierarchy…: well it turns out you can use the f7-row component because it offers the ability to choose your own HTML tag along with their children.
So if you inspect (“steal the code of…?”) Home Assistant’s page you’ll note that the widget’s animated “pipes” is a rather simple SVG:
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid slice">
<path id="return" class="return" vector-effect="non-scaling-stroke" d="M47,0 v15 c0,40 -10,35 -30,35 h-20"></path>
<path id="solar" class="solar" vector-effect="non-scaling-stroke" d="M53,0 v15 c0,40 10,35 30,35 h20"></path>
<path class="grid" id="grid" vector-effect="non-scaling-stroke" d="M0,56 H100"></path>
<circle r="1" class="return" vector-effect="non-scaling-stroke">
<animateMotion repeatCount="indefinite" calcMode="linear" dur="5.26366433175909s">
<mpath xlink:href="#return"></mpath>
</animateMotion>
</circle>
<circle r="1" class="solar" vector-effect="non-scaling-stroke">
<animateMotion repeatCount="indefinite" calcMode="linear" dur="3.511455128333689s">
<mpath xlink:href="#solar"></mpath>
</animateMotion>
</circle>
<circle r="1" class="grid" vector-effect="non-scaling-stroke">
<animateMotion repeatCount="indefinite" calcMode="linear" dur="4.102157928533736s">
<mpath xlink:href="#grid"></mpath>
</animateMotion>
</circle>
</svg>
So how would you translate this into openHAB’s widget definition YAML? - well, like this:
- component: f7-row
config:
tag: svg
xmlns: http://www.w3.org/2000/svg
viewBox: 0 0 100 100
preserveAspectRatio: xMidYMid slice
style:
height: auto
slots:
default:
- component: f7-row
config:
tag: path
id: path1
d: M53,0 v15 c0,40 10,35 30,35 h20
stroke: orange
stroke-width: 1
vector-effect: non-scaling-stroke
fill: none
- component: f7-row
config:
tag: circle
r: 1
vector-effect: non-scaling-stroke
fill: orange
style:
stroke-width: 4
slots:
default:
- component: f7-row
config:
tag: animateMotion
repeatCount: indefinite
calcMode: linear
dur: 5s
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path1"
- component: f7-row
config:
tag: path
id: path2
d: M47,0 v15 c0,40 -10,35 -30,35 h-20
stroke: purple
stroke-width: 1
vector-effect: non-scaling-stroke
fill: none
- component: f7-row
config:
tag: circle
r: 1
vectorEffect: non-scaling-stroke
strokeWidth: 10
fill: purple
slots:
default:
- component: f7-row
config:
tag: animateMotion
repeatCount: indefinite
calcMode: linear
dur: 3s
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path2"
- component: f7-row
config:
tag: path
id: path3
d: M0,56 H100
stroke: teal
stroke-width: 1
vector-effect: non-scaling-stroke
fill: none
- component: f7-row
config:
tag: circle
r: 1
vectorEffect: non-scaling-stroke
strokeWidth: 10
fill: teal
slots:
default:
- component: f7-row
config:
tag: animateMotion
repeatCount: indefinite
calcMode: linear
dur: 3s
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path3"
You can change the speed of the animations (dur
properties) with expressions as appropriate.
There could be built-in improvements in this area in the future since it definititely has potential!
Final widget:
uid: energy_summary
tags: []
props:
parameters: []
parameterGroups: []
timestamp: Jan 7, 2022, 12:59:10 PM
component: f7-card
config:
title: Energy Summary (test)
slots:
content:
- component: f7-block
config:
style:
margin: 0
padding: 0
slots:
default:
- component: f7-block
config:
style:
margin: 0
padding: 0
display: flex
justify-content: space-between
--f7-theme-color: var(--f7-text-color)
--f7-block-font-size: 12px
slots:
default:
- component: f7-col
config:
style:
display: flex
flex-direction: column
align-items: center
slots:
default:
- component: Label
config:
text: Non-fossil
- component: f7-block
config:
style:
height: 80px
width: 80px
border: 2px solid darkgreen
border-radius: 40px
display: flex
justify-content: center
align-items: center
flex-direction: column
slots:
default:
- component: oh-icon
config:
icon: if:mdi:leaf
height: 20px
color: darkgreen
- component: Label
config:
text: 0.7 kWh
style:
font-size: 12px
- component: f7-block
config:
style:
height: 30px
width: 2px
padding: 0
margin: 0
border: 1px solid darkgreen
display: flex
justify-content: center
align-items: center
flex-direction: column
- component: f7-block
config:
style:
margin-top: 0
height: 80px
width: 80px
border: 2px solid teal
border-radius: 40px
display: flex
justify-content: center
align-items: center
flex-direction: column
slots:
default:
- component: oh-icon
config:
icon: if:mdi:transmission-tower
height: 20px
color: teal
- component: oh-link
config:
text: 2.3 kWh
iconF7: arrow_left
iconSize: 12px
iconColor: purple
style:
font-size: 12px
white-space: nowrap
- component: oh-link
config:
text: 5.7 kWh
iconF7: arrow_right
iconSize: 12px
iconColor: blue
style:
font-size: 12px
white-space: nowrap
- component: Label
config:
text: Grid
- component: f7-col
config:
style:
flex-grow: 1
display: flex
flex-direction: column
align-items: center
slots:
default:
- component: Label
config:
text: Solar
- component: f7-block
config:
style:
height: 80px
width: 80px
border: 2px solid orange
border-radius: 40px
display: flex
justify-content: center
align-items: center
flex-direction: column
slots:
default:
- component: oh-icon
config:
icon: if:mdi:solar-power
height: 20px
color: orange
- component: Label
config:
text: 9.5 kWh
style:
font-size: 12px
- component: f7-block
config:
style:
margin: 0
padding: 0
width: 100%
display: flex
height: 125px
justify-content: center
slots:
default:
- component: f7-row
config:
tag: svg
xmlns: http://www.w3.org/2000/svg
viewBox: 0 0 100 100
preserveAspectRatio: xMidYMid slice
style:
height: auto
slots:
default:
- component: f7-row
config:
tag: path
id: path1
d: M53,0 v15 c0,40 10,35 30,35 h20
stroke: orange
stroke-width: 1
vector-effect: non-scaling-stroke
fill: none
- component: f7-row
config:
tag: circle
r: 1
vector-effect: non-scaling-stroke
fill: orange
style:
stroke-width: 4
slots:
default:
- component: f7-row
config:
tag: animateMotion
repeatCount: indefinite
calcMode: linear
dur: 5s
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path1"
- component: f7-row
config:
tag: path
id: path2
d: M47,0 v15 c0,40 -10,35 -30,35 h-20
stroke: purple
stroke-width: 1
vector-effect: non-scaling-stroke
fill: none
- component: f7-row
config:
tag: circle
r: 1
vectorEffect: non-scaling-stroke
strokeWidth: 10
fill: purple
slots:
default:
- component: f7-row
config:
tag: animateMotion
repeatCount: indefinite
calcMode: linear
dur: 3s
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path2"
- component: f7-row
config:
tag: path
id: path3
d: M0,56 H100
stroke: teal
stroke-width: 1
vector-effect: non-scaling-stroke
fill: none
- component: f7-row
config:
tag: circle
r: 1
vectorEffect: non-scaling-stroke
strokeWidth: 10
fill: teal
slots:
default:
- component: f7-row
config:
tag: animateMotion
repeatCount: indefinite
calcMode: linear
dur: 3s
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path3"
- component: f7-col
config:
style:
display: flex
flex-direction: column
align-items: center
slots:
default:
- component: Label
config:
text: Gas
- component: f7-block
config:
style:
height: 80px
width: 80px
border: 2px solid darkred
border-radius: 40px
display: flex
justify-content: center
align-items: center
flex-direction: column
slots:
default:
- component: oh-icon
config:
icon: if:mdi:gas
height: 20px
color: darkred
- component: Label
config:
text: 1.7 m³
style:
font-size: 12px
- component: f7-block
config:
style:
height: 30px
width: 2px
padding: 0
margin: 0
border: 1px solid darkred
display: flex
justify-content: center
align-items: center
flex-direction: column
- component: f7-block
config:
style:
margin-top: 0
height: 80px
width: 80px
border: 2px solid gray
border-radius: 40px
display: flex
justify-content: center
align-items: center
flex-direction: column
slots:
default:
- component: oh-icon
config:
icon: if:mdi:home
height: 20px
color: gray
- component: Label
config:
text: 12.9 kWh
style:
font-size: 12px
white-space: nowrap
- component: Label
config:
text: Home
Very nice! This should be in the marketplace for sure.
This is perhaps the coolest thing in OH.
I put this widget on my Overview page (copied the code above). I haven’t included my own data yet but will do once I can read my energy meters. There is one glitch, though. For some reason the lines are too short. I tried to look at the code but didn’t find the parameters that I would need to change. I also tried to change the column widths but this didn’t help.
For sure, but I meant this to be a example/showcase and I’m afraid I’m too busy (read: lazy) to make it into a proper turn-key widget. What I’m willing to try however is to make a Wiki entry in the marketplace so the widget would be initially be the one above with the hardcoded values and eventually (but I’m not holding my breath ) it would be improved by others who can edit wiki entries?
dear
Grat job, I want to start from your code to add the possibility to select items from standard UI
just for information, NON FOSSIL value is related to???
how it’s calculated (or should be calculated?)
How do you read GAS value? there is a special hardware (like shelly em or other for energy ) or do you read the value from your supllier site/api?
This is completely up to you. If you have smart meters at home, you can read them, or try DIY projects for meter readings. There are many to find in google.
I for myself read my gas meter with a proximity sensor and a tasmota baseded nodeMCU and my smart electricity meter with a SML reader connected to the same nodeMCU.
dear All
here you can find the first version of configurable widget.
Let me know if you find some bugs or if you have suggestion for improve it
This is a very nice work, thank you.
I do have a humble question, would it be possible (for someone) to add battery charging and usage to the widget…basically it needs to be connected to Solar and Home for charging from solar and supplying home…
I really tried myself but am really not sufficient enough in YAML design…
Thanks.
Did anybody already managed to rebuild the complete Home Assistant Energy Dashboard with all the charts and graphs.
I think there should be a standard template/page in openHAB to easily create this kind of page, as actually everybody could use it.
Who says that ? I e.g could not use it like I assume many others
There is no need to make it a standard page/widget, but feel free to create the complete setup and publish it to the marketplace, so anybody who wants it, can use it. It might become a nice project like the main_widget project.
But like always, somebody has to make a start.
Hi Livio,
thanks for the nice widget. I like it and use it. I would love to have just one more parameter to add, or basically it could be calculated also with the values we can provide now →
on the left side we see how much we import and export from/to the grid. I would also like to see similarly on the right side (home) how much energy that I used is from the solarplant and how much is imported. its basically a simple substraction from values we have.
could you add it? if not i may fuzzle around a bit with the widget as i think it should be not so difficult. but maybe its quick for you and you like the idea. if not i may share my experiment here.
however. thanks for making this work already!
mathias
Here is my implementation without “Non-fossil” and “Gas”, but with property item-support and slight style changes.
uid: energy-summary
tags: []
props:
parameters:
- context: item
description: The item for grid consumption
label: Grid Consumption
name: grid_consumption
required: false
- context: item
description: The item for grid surplus
label: Grid Surplus
name: grid_surplus
required: false
type: TEXT
- context: item
description: The item for pv production
label: PV Production
name: pv_production
required: false
type: TEXT
- context: item
label: PV Own Consumption
name: pv_own_consumption
required: false
type: TEXT
- context: item
description: The item for home consumption
label: Home Consumption
name: home_consumption
required: false
type: TEXT
parameterGroups: []
timestamp: Aug 17, 2023, 7:14:09 PM
component: f7-card
config:
title: Energy Summary
slots:
content:
- component: f7-block
config:
style:
margin: 0
padding: 0
slots:
default:
- component: f7-block
config:
style:
margin: 0
padding: 0
display: flex
justify-content: space-between
--f7-theme-color: var(--f7-text-color)
--f7-block-font-size: 12px
slots:
default:
- component: f7-col
config:
style:
display: flex
flex-direction: column
align-items: center
slots:
default:
- component: f7-block
config:
style:
margin-top: 140px
padding-top: 10px
height: 100px
width: 100px
border: 2px solid teal
border-radius: 50px
display: flex
justify-content: top
align-items: center
flex-direction: column
slots:
default:
- component: oh-icon
config:
icon: if:mdi:transmission-tower
height: 25px
color: teal
- component: oh-link
config:
text: =@props.grid_surplus
iconF7: arrow_left
iconSize: 12px
iconColor: purple
style:
font-size: 12px
white-space: nowrap
action: analyzer
actionAnalyzerItems:
- =props.grid_surplus
- component: oh-link
config:
text: =@props.grid_consumption
iconF7: arrow_right
iconSize: 12px
iconColor: grey
style:
font-size: 12px
white-space: nowrap
action: analyzer
actionAnalyzerItems:
- =props.grid_consumption
- component: Label
config:
text: Grid
- component: f7-col
config:
style:
flex-grow: 1
display: flex
flex-direction: column
align-items: center
slots:
default:
- component: Label
config:
text: PV
- component: f7-block
config:
style:
padding-top: 20px
height: 100px
width: 100px
border: 2px solid orange
border-radius: 50px
display: flex
justify-content: top
align-items: center
flex-direction: column
slots:
default:
- component: oh-icon
config:
icon: if:mdi:solar-power
height: 25px
color: orange
- component: oh-link
config:
text: =@props.pv_production
style:
font-size: 12px
action: analyzer
actionAnalyzerItems:
- =props.pv_production
- component: f7-block
config:
style:
margin: 0
padding: 0
width: 100%
display: flex
height: 125px
justify-content: center
slots:
default:
- component: f7-row
config:
tag: svg
xmlns: http://www.w3.org/2000/svg
viewBox: 0 0 100 100
preserveAspectRatio: xMidYMid slice
style:
height: auto
slots:
default:
- component: f7-row
config:
tag: path
id: path1
d: M53,0 v15 c0,40 10,35 30,35 h20
stroke: orange
stroke-width: 1
vector-effect: non-scaling-stroke
fill: none
- component: f7-row
config:
tag: circle
r: 1
vector-effect: non-scaling-stroke
fill: orange
style:
stroke-width: 4
slots:
default:
- component: f7-row
config:
tag: animateMotion
repeatCount: indefinite
calcMode: linear
dur: 5s
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path1"
- component: f7-row
config:
tag: path
id: path2
d: M47,0 v15 c0,40 -10,35 -30,35 h-20
stroke: purple
stroke-width: 1
vector-effect: non-scaling-stroke
fill: none
- component: f7-row
config:
tag: circle
r: 1
vectorEffect: non-scaling-stroke
strokeWidth: 10
fill: purple
slots:
default:
- component: f7-row
config:
tag: animateMotion
repeatCount: indefinite
calcMode: linear
dur: 3s
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path2"
- component: f7-row
config:
tag: path
id: path3
d: M0,56 H100
stroke: teal
stroke-width: 1
vector-effect: non-scaling-stroke
fill: none
- component: f7-row
config:
tag: circle
r: 1
vectorEffect: non-scaling-stroke
strokeWidth: 10
fill: teal
slots:
default:
- component: f7-row
config:
tag: animateMotion
repeatCount: indefinite
calcMode: linear
dur: 3s
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path3"
- component: f7-col
config:
style:
display: flex
flex-direction: column
align-items: center
slots:
default:
- component: f7-block
config:
style:
margin-top: 140px
padding-top: 10px
height: 100px
width: 100px
border: 2px solid gray
border-radius: 50px
display: flex
justify-content: top
align-items: center
flex-direction: column
slots:
default:
- component: oh-icon
config:
icon: if:mdi:home
height: 25px
color: grey
- component: oh-link
config:
text: =@props.pv_own_consumption
iconF7: arrow_right
iconSize: 12px
iconColor: yellow
style:
font-size: 12px
white-space: nowrap
action: analyzer
actionAnalyzerItems:
- =props.pv_own_consumption
- component: oh-link
config:
text: =@props.home_consumption
iconF7: arrow_right
iconSize: 12px
iconColor: grey
style:
font-size: 12px
white-space: nowrap
action: analyzer
actionAnalyzerItems:
- =props.home_consumption
- component: Label
config:
text: Home
Having strange problems when it comes to small screens. Any idea how to solve this?