Dear openHAB and solar “comrades-in-arms”,
I got the described widget working on my system and was able to adapt it quite well to my needs.
My primary solar system is a “Fronius Symo Gen24 Plus 10” + 16.6kWh battery + solar panels 5.58kW on the garage roof in 285° west orientation, 15° inclination).
In addition, I currently have ONE PV system (600W) and soon TWO more small PV systems (960W + 1920W) mounted in the stairwell in south orientation on smaller partial areas (195° south orientation, 80° inclination for winter optimization).
Unfortunately, I am just too stupid to understand this f7 programming at the crucial points to adapt this representation for me now. I just can’t manage to rebuild/extend the widget in the code in a meaningful way, as I can’t really find any catchy complex examples. I’m still having a lot of trouble getting a handle on the syntax and incorporating additional representations so that they end up where I want them.
LINEUP is still at the moment…
a.) EITHER make the current flow representation layered so that all three small mini PVs (APSys, DEYE 1k and DEYE 2k) show their current flow directly to the consumer grid without messing up the existing diagram (icons of battery and battery level on top).
b.) OR I put another wide green strip at the very bottom behind the consumer symbol, so to speak as a collective line of all my consumers and let the mini PV animations of the current flow only straight down.
Do you have tips for me to solve this?
uid: FRONIUS_widget
tags: []
props:
parameters:
- context: item
label: Netzeinspeisung
name: netzeinspeisung
required: true
type: TEXT
- context: item
label: Netzbezug
name: netzbezug
required: true
type: TEXT
- context: item
label: Gesamtverbrauch
name: gesamtverbrauch
required: true
type: TEXT
- context: item
label: PV Leistung
name: pv_leistung
required: true
type: TEXT
- context: item
label: PV Leistung APSys
name: pv_leistungapsys
required: false
type: TEXT
- context: item
label: PV Leistung DEYE1k
name: pv_leistungdeye1k
required: false
type: TEXT
- context: item
label: PV Leistung DEYE2k
name: pv_leistungdeye2k
required: false
type: TEXT
- context: item
label: Batterieleistung
name: batterieleistung
required: true
type: TEXT
- context: item
label: Batterie Ladezustand
name: batterylevel
required: true
type: TEXT
parameterGroups: []
timestamp: May 20, 2023, 11:54:36 AM
component: f7-card
config:
class:
- display-flex
- flex-direction-column
- align-items-center
style:
height: 512px
slots:
content:
- component: f7-block
config:
style:
--f7-theme-color: var(--f7-text-color)
display: flex
justify-content: space-between
padding: 0
slots:
default:
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: row
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: column
height: 110px
justify-content: center
margin-top: 0
width: 110px
slots:
default:
- component: oh-icon
config:
height: 110px
icon: INVERTER_grid_2
style:
margin-top: -130px
- component: Label
config:
style:
color: red
font-size: 20px
font-weight: bold
margin-top: -16px
text-align: center
white-space: nowrap
width: 100px
text: =(Number.parseFloat(items[props.netzbezug].state.split(" ")[0]) - Number.parseFloat(items[props.netzeinspeisung].state.split(" ")[0])) + " W"
visible: '=(Number.parseFloat(items[props.netzbezug].state.split(" ")[0]) - Number.parseFloat(items[props.netzeinspeisung].state.split(" ")[0]) > 0) ? true : false'
- component: Label
config:
style:
color: green
font-size: 20px
font-weight: bold
margin-top: -16px
text-align: center
white-space: nowrap
width: 100px
text: =((Number.parseFloat(items[props.netzbezug].state.split(" ")[0]) - Number.parseFloat(items[props.netzeinspeisung].state.split(" ")[0])) * -1) + " W"
visible: '=(Number.parseFloat(items[props.netzbezug].state.split(" ")[0]) - Number.parseFloat(items[props.netzeinspeisung].state.split(" ")[0]) < 0) ? true : false'
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: column
flex-grow: 1
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: column
height: 110px
justify-content: center
margin-top: 0
width: 110px
slots:
default:
- component: Label
config:
style:
font-size: 20px
font-weight: bold
text-align: center
white-space: wrap
width: 100px
text: ="Fronius"
- component: Label
config:
style:
color: orange
font-size: 20px
font-weight: bold
text-align: center
white-space: wrap
width: 100px
text: =items[props.pv_leistung].displayState
- component: oh-icon
config:
height: 110px
icon: INVERTER_pv_2
style:
margin-top: -30px
- component: f7-block
config:
style:
display: flex
justify-content: center
margin: 0
padding: 0
width: 100%
slots:
default:
- component: f7-row
config:
preserveAspectRatio: xMidYMid slice
style:
height: auto
width: auto
tag: svg
viewBox: 0 0 100 100
xmlns: http://www.w3.org/2000/svg
slots:
default:
- component: f7-row
config:
d: M60 -5 v10 c0 30 10 35 30 35 h20
fill: none
id: path1
stroke: rgba(100, 150, 200, 0.8)
stroke-width: 2
tag: path
vector-effect: non-scaling-stroke
visible: '=(items[props.batterieleistung].state.split(" ")[0]) < 0 ? true : false'
- component: f7-row
config:
fill: rgba(100, 150, 200, 0.8)
r: 6
style:
stroke-width: 4
tag: circle
vector-effect: non-scaling-stroke
visible: '=(items[props.batterieleistung].state.split(" ")[0]) < 0 ? true : false'
slots:
default:
- component: f7-row
config:
calcMode: linear
dur: 4s
repeatCount: indefinite
tag: animateMotion
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path1"
- component: f7-row
config:
d: M40 -5 v10 c0 40 -10 35 -30 35 h-20
fill: none
id: path2
stroke: rgba(100, 150, 200, 0.8)
stroke-width: 2
tag: path
vector-effect: non-scaling-stroke
visible: '=(Number.parseFloat(items[props.netzeinspeisung].state.split(" ")[0]) > 0 && Number.parseFloat(items[props.netzbezug].state.split(" ")[0]) == 0) ? true : false'
- component: f7-row
config:
fill: rgba(100, 150, 200, 0.8)
r: 6
strokeWidth: 10
tag: circle
vectorEffect: non-scaling-stroke
visible: '=(Number.parseFloat(items[props.netzeinspeisung].state.split(" ")[0]) > 0 && Number.parseFloat(items[props.netzbezug].state.split(" ")[0]) == 0) ? true : false'
slots:
default:
- component: f7-row
config:
calcMode: linear
dur: 4s
repeatCount: indefinite
tag: animateMotion
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path2"
- component: f7-row
config:
d: M50, 0 v100
fill: none
id: path3
stroke: rgba(100, 150, 200, 0.8)
stroke-width: 2
tag: path
vector-effect: non-scaling-stroke
visible: '=(Number.parseFloat(items[props.pv_leistung].state.split(" ")[0])) > 1 ? true : false'
- component: f7-row
config:
fill: rgba(100, 150, 200, 0.8)
r: 6
strokeWidth: 10
tag: circle
vectorEffect: non-scaling-stroke
visible: '=(Number.parseFloat(items[props.pv_leistung].state.split(" ")[0])) > 1 ? true : false'
slots:
default:
- component: f7-row
config:
calcMode: linear
dur: 4s
repeatCount: indefinite
tag: animateMotion
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path3"
- component: f7-row
config:
d: M-5 50 l10 0 c40 0 35 10 35 50 l 0 20
fill: none
id: path4
stroke: rgba(100, 150, 200, 0.8)
stroke-width: 2
tag: path
vector-effect: non-scaling-stroke
visible: '=(Number.parseFloat(items[props.netzbezug].state.split(" ")[0]) > 0) ? true : false'
- component: f7-row
config:
fill: rgba(100, 150, 200, 0.8)
r: 6
strokeWidth: 10
tag: circle
vectorEffect: non-scaling-stroke
visible: '=(Number.parseFloat(items[props.netzbezug].state.split(" ")[0]) > 0) ? true : false'
slots:
default:
- component: f7-row
config:
calcMode: linear
dur: 4s
repeatCount: indefinite
tag: animateMotion
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path4"
- component: f7-row
config:
d: M 105 50 l -10 0 c -40 0 -35 10 -35 50 l 0 20
fill: none
id: path5
stroke: rgba(100, 150, 200, 0.8)
stroke-width: 2
tag: path
vector-effect: non-scaling-stroke
visible: '=(Number.parseFloat(items[props.batterieleistung].state.split(" ")[0]) > 0) ? true : false'
- component: f7-row
config:
fill: rgba(100, 150, 200, 0.8)
r: 6
strokeWidth: 10
tag: circle
vectorEffect: non-scaling-stroke
visible: '=(Number.parseFloat(items[props.batterieleistung].state.split(" ")[0]) > 0) ? true : false'
slots:
default:
- component: f7-row
config:
calcMode: linear
dur: 4s
repeatCount: indefinite
tag: animateMotion
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path5"
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: column
height: 110px
justify-content: center
margin-top: -10px
width: 110px
slots:
default:
- component: oh-icon
config:
height: 90px
icon: inverter_fronius_gen_24
- component: Label
- component: f7-block
config:
style:
display: flex
justify-content: center
margin: 0
padding: 0
width: 100%
slots:
default:
- component: f7-row
config:
preserveAspectRatio: xMidYMid slice
style:
height: auto
width: auto
tag: svg
viewBox: 0 0 100 100
xmlns: http://www.w3.org/2000/svg
slots:
default:
- component: f7-row
config:
d: M50, 0 v100
fill: none
id: path9
stroke: rgba(100, 150, 200, 0.8)
stroke-width: 2
tag: path
vector-effect: non-scaling-stroke
visible: '=(Number.parseFloat(items[props.gesamtverbrauch].state.split(" ")[0])) < 1 ? true : false'
- component: f7-row
config:
fill: rgba(100, 150, 200, 0.8)
r: 6
strokeWidth: 10
tag: circle
vectorEffect: non-scaling-stroke
visible: '=(Number.parseFloat(items[props.gesamtverbrauch].state.split(" ")[0])) < 1 ? true : false'
slots:
default:
- component: f7-row
config:
calcMode: linear
dur: 4s
repeatCount: indefinite
tag: animateMotion
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path9"
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: column
height: 110px
margin-top: -80px
width: 110px
slots:
default:
- component: oh-icon
config:
height: 110px
icon: consumption
- component: Label
config:
style:
color: '=(Number.parseFloat(items[props.gesamtverbrauch].state.split(" ")[0]) > 0) ? "green" : "red"'
font-size: 20px
font-weight: bold
margin-top: -18px
text-align: center
white-space: nowrap
width: 100px
text: =(Number.parseFloat(items[props.gesamtverbrauch].state.split(" ")[0])).toFixed(0) + " W"
visible: '=(Number.parseFloat(items[props.gesamtverbrauch].state.split(" ")[0]) > 0) ? true : false'
- component: Label
config:
style:
color: '=(Number.parseFloat(items[props.gesamtverbrauch].state.split(" ")[0]) < 0) ? "red" : "green"'
font-size: 20px
font-weight: bold
margin-top: -18px
text-align: center
white-space: nowrap
width: 100px
text: =(Number.parseFloat(items[props.gesamtverbrauch].state.split(" ")[0]) * -1).toFixed(0) + " W"
visible: '=(Number.parseFloat(items[props.gesamtverbrauch].state.split(" ")[0]) < 0) ? true : false'
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: row
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: column
height: 110px
justify-content: center
margin-top: -40px
width: 110px
slots:
default:
- component: oh-icon
config:
height: 40em
icon: akku_0
style:
margin-top: -160px
visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) <= 12) ? true : false'
- component: oh-link
config:
style:
font-size: 20px
font-weight: bold
white-space: nowrap
text: =items[props.batterylevel].state
visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) <= 12) ? true : false'
- component: oh-icon
config:
height: 40em
icon: akku_12
style:
margin-top: -160px
visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) > 12 && Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) < 25) ? true : false'
- component: oh-link
config:
style:
font-size: 20px
font-weight: bold
white-space: nowrap
text: =items[props.batterylevel].state
visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) > 12 && Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) < 25) ? true : false'
- component: oh-icon
config:
height: 40em
icon: akku_25
style:
margin-top: -130px
visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) >= 25 && Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) < 50) ? true : false'
- component: oh-link
config:
style:
font-size: 20px
font-weight: bold
white-space: nowrap
text: =items[props.batterylevel].state
visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) >= 25 && Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) < 50) ? true : false'
- component: oh-icon
config:
height: 40em
icon: akku_50
style:
margin-top: -160px
visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) >= 50 && Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) < 75) ? true : false'
- component: oh-link
config:
style:
font-size: 20px
font-weight: bold
white-space: nowrap
text: =items[props.batterylevel].state
visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) >= 50 && Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) < 75) ? true : false'
- component: oh-icon
config:
height: 40em
icon: akku_75
style:
margin-top: -160px
visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) >= 75 && Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) < 90) ? true : false'
- component: oh-link
config:
style:
font-size: 20px
font-weight: bold
white-space: nowrap
text: =items[props.batterylevel].state
visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) >= 75 && Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) < 90) ? true : false'
- component: oh-icon
config:
height: 40em
icon: akku_90
style:
margin-top: -160px
visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) >= 90 && Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) < 99) ? true : false'
- component: oh-link
config:
style:
font-size: 20px
font-weight: bold
white-space: nowrap
text: =items[props.batterylevel].state
visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) >= 90 && Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) < 99) ? true : false'
- component: oh-icon
config:
height: 40em
icon: akku_100
style:
margin-top: -160px
visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) > 99) ? true : false'
- component: oh-link
config:
style:
font-size: 20px
font-weight: bold
white-space: nowrap
text: =items[props.batterylevel].state
visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) > 99) ? true : false'
- component: oh-icon
config:
height: 110px
icon: BATTERY_pv
style:
margin-top: -10px
- component: Label
config:
style:
color: '=(Number.parseFloat(items[props.batterieleistung].state.split(" ")[0]) > 0) ? "red" : "green"'
font-size: 20px
font-weight: bold
margin-top: 0
text-align: center
white-space: nowrap
width: 100px
text: =(Number.parseFloat(items[props.batterieleistung].state.split(" ")[0])).toFixed(0) + " W"
visible: '=(Number.parseFloat(items[props.batterieleistung].state.split(" ")[0]) > 0) ? true : false'
- component: Label
config:
style:
color: '=(Number.parseFloat(items[props.batterieleistung].state.split(" ")[0]) < 0) ? "green" : "red"'
font-size: 20px
font-weight: bold
margin-top: 0
text-align: center
white-space: nowrap
width: 100px
text: =(Number.parseFloat(items[props.batterieleistung].state.split(" ")[0]) * -1).toFixed(0) + " W"
visible: '=(Number.parseFloat(items[props.batterieleistung].state.split(" ")[0]) < 0) ? true : false'
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: column
flex-grow: 1
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: column
height: 110px
justify-content: center
margin-top: 0
width: 110px
slots:
default:
- component: Label
config:
style:
font-size: 20px
font-weight: bold
text-align: center
white-space: wrap
width: 100px
text: ="APSys"
- component: Label
config:
style:
color: orange
font-size: 20px
font-weight: bold
text-align: center
white-space: wrap
width: 100px
text: =items[props.pv_leistungapsys].displayState
- component: oh-icon
config:
height: 110px
icon: INVERTER_pv_2
style:
margin-top: -30px
- component: f7-block
config:
style:
display: flex
justify-content: center
margin: 0
padding: 0
width: 100%
slots:
default:
- component: f7-row
config:
preserveAspectRatio: xMidYMid slice
style:
height: auto
width: auto
tag: svg
viewBox: 0 0 100 300
xmlns: http://www.w3.org/2000/svg
slots:
default:
- component: f7-row
config:
d: M40 -5 v230 c0 40 -10 35 -30 35 h-20
fill: none
id: path6
stroke: rgba(100, 150, 200, 0.8)
stroke-width: 2
tag: path
vector-effect: non-scaling-stroke
visible: '=(Number.parseFloat(items[props.pv_leistungapsys].state.split(" ")[0]) > 0 ) ? true : false'
- component: f7-row
config:
fill: rgba(100, 150, 200, 0.8)
r: 6
strokeWidth: 10
tag: circle
vectorEffect: non-scaling-stroke
visible: '=(Number.parseFloat(items[props.pv_leistungapsys].state.split(" ")[0]) > 0 ) ? true : false'
slots:
default:
- component: f7-row
config:
calcMode: linear
dur: 4s
repeatCount: indefinite
tag: animateMotion
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path6"
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: column
flex-grow: 1
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: column
height: 110px
justify-content: center
margin-top: 0
width: 110px
slots:
default:
- component: Label
config:
style:
font-size: 20px
font-weight: bold
text-align: center
white-space: wrap
width: 100px
text: ="DEYE 1K"
- component: Label
config:
style:
color: orange
font-size: 20px
font-weight: bold
text-align: center
white-space: wrap
width: 100px
text: =items[props.pv_leistungdeye1k].displayState
- component: oh-icon
config:
height: 110px
icon: INVERTER_pv_2
style:
margin-top: -30px
- component: f7-block
config:
style:
display: flex
justify-content: center
margin: 0
padding: 0
width: 100%
slots:
default:
- component: f7-row
config:
preserveAspectRatio: xMidYMid slice
style:
height: auto
width: auto
tag: svg
viewBox: 0 0 100 100
xmlns: http://www.w3.org/2000/svg
slots:
default:
- component: f7-row
config:
d: M40 -5 v10 c0 40 -10 35 -30 35 h-20
fill: none
id: path7
stroke: rgba(100, 150, 200, 0.8)
stroke-width: 2
tag: path
vector-effect: non-scaling-stroke
visible: '=(Number.parseFloat(items[props.pv_leistungdeye1k].state.split(" ")[0]) > 0 ) ? true : false'
- component: f7-row
config:
fill: rgba(100, 150, 200, 0.8)
r: 6
strokeWidth: 10
tag: circle
vectorEffect: non-scaling-stroke
visible: '=(Number.parseFloat(items[props.pv_leistungdeye1k].state.split(" ")[0]) > 0 ) ? true : false'
slots:
default:
- component: f7-row
config:
calcMode: linear
dur: 4s
repeatCount: indefinite
tag: animateMotion
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path7"
- component: f7-col
config:
style:
align-items: center
display: flex
flex-direction: column
flex-grow: 1
slots:
default:
- component: f7-block
config:
style:
align-items: center
display: flex
flex-direction: column
height: 110px
justify-content: center
margin-top: 0
width: 110px
slots:
default:
- component: Label
config:
style:
font-size: 20px
font-weight: bold
text-align: center
white-space: wrap
width: 100px
text: ="DEYE 2k"
- component: Label
config:
style:
color: orange
font-size: 20px
font-weight: bold
text-align: center
white-space: wrap
width: 100px
text: =items[props.pv_leistungdeye2k].displayState
- component: oh-icon
config:
height: 110px
icon: INVERTER_pv_2
style:
margin-top: -30px
- component: f7-block
config:
style:
display: flex
justify-content: center
margin: 0
padding: 0
width: 100%
slots:
default:
- component: f7-row
config:
preserveAspectRatio: xMidYMid slice
style:
height: auto
width: auto
tag: svg
viewBox: 0 0 100 100
xmlns: http://www.w3.org/2000/svg
slots:
default:
- component: f7-row
config:
d: M40 -5 v10 c0 40 -10 35 -30 35 h-20
fill: none
id: path8
stroke: rgba(100, 150, 200, 0.8)
stroke-width: 2
tag: path
vector-effect: non-scaling-stroke
visible: '=(Number.parseFloat(items[props.pv_leistungdeye2k].state.split(" ")[0]) > 0 ) ? true : false'
- component: f7-row
config:
fill: rgba(100, 150, 200, 0.8)
r: 6
strokeWidth: 10
tag: circle
vectorEffect: non-scaling-stroke
visible: '=(Number.parseFloat(items[props.pv_leistungdeye2k].state.split(" ")[0]) > 0 ) ? true : false'
slots:
default:
- component: f7-row
config:
calcMode: linear
dur: 4s
repeatCount: indefinite
tag: animateMotion
slots:
default:
- component: f7-row
config:
tag: mpath
xlink:href: "#path8"
kind regards
Tommy / openHAB-Rookie