Openhab Widget Solar/Akku grafische Anzeige

uid: zendure_premium_v14
tags: []
props:
parameters:
– context: item
label: Batterie Ladestand (z.B. 50 %)
name: itemBattery
required: false
type: TEXT
– context: item
label: Batterie Ladeleistung (Watt)
name: itemBatteryCharge
required: false
type: TEXT
– context: item
label: Batterie Entladeleistung (Watt)
name: itemBatteryDischarge
required: false
type: TEXT
– context: item
label: Solar Hub O/W (Watt)
name: itemSolarHub
required: false
type: TEXT
– context: item
label: Solar Süd (Positiv = Produktion)
name: itemSolarSouth
required: false
type: TEXT
– context: item
label: Hausverbrauch Gesamt (Echtes Item)
name: itemHouseConsumption
required: false
type: TEXT
– context: item
label: Hub Ausgang (Watt zum Haus)
name: itemHubOutput
required: false
type: TEXT
– context: item
label: Netzbezug (Smart Meter)
name: itemGrid
required: false
type: TEXT
timestamp: May 2, 2026, 11:17:30 PM
component: f7-card
config:
stylesheet: >
.energy-pulse {
animation: pulse-effect 2s infinite !important;
border: 1px solid #4cd964 !important;
}

@keyframes pulse-effect {
0% { box-shadow: 0 0 10px rgba(76, 217, 100, 0.4); transform: scale(1); }
50% { box-shadow: 0 0 40px rgba(76, 217, 100, 0.8); transform: scale(1.05); }
100% { box-shadow: 0 0 10px rgba(76, 217, 100, 0.4); transform: scale(1); }
}
style:
background: „linear-gradient(160deg, #121212 0%, #1e1e1e 100%)“
border: 1px solid rgba(255,255,255,0.08)
border-radius: 28px
box-shadow: 0px 20px 40px rgba(0,0,0,0.6)
color: white
height: 380px
slots:
default:
– component: f7-card-content
slots:
default:
– component: f7-row
slots:
default:
– component: f7-col
slots:
default:
– component: Label
config:
style:
fontSize: 11px
fontWeight: „800“
letterSpacing: 1.5px
opacity: 0.4
text: ENERGY KONTROLLE
– component: f7-block
config:
style:
align-items: center
display: flex
height: 240px
justify-content: space-around
margin: 0
position: relative
slots:
default:
– component: svg
config:
preserveAspectRatio: none
style:
height: 100%
left: 0
pointer-events: none
position: absolute
top: 0
width: 100%
viewBox: 0 0 100 100
slots:
default:
– component: path
config:
d: M 20,30 Q 35,50 50,50
fill: none
id: pathHub
stroke: rgba(255, 204, 0, 0.1)
stroke-width: 0.5
– component: circle
config:
fill: „#FFCC00“
r: 1
visible: =(items[props.itemSolarHub].numericState > 0)
slots:
default:
– component: animateMotion
config:
calcMode: linear
dur: 3s
repeatCount: indefinite
slots:
default:
– component: mpath
config:
xlink:href: „#pathHub“
– component: path
config:
d: M 20,70 Q 35,50 50,50
fill: none
id: pathSouth
stroke: rgba(255, 221, 85, 0.1)
stroke-width: 0.5
– component: circle
config:
fill: „#FFDD55“
r: 1
visible: =(items[props.itemSolarSouth].numericState > 0)
slots:
default:
– component: animateMotion
config:
calcMode: linear
dur: 3s
repeatCount: indefinite
slots:
default:
– component: mpath
config:
xlink:href: „#pathSouth“
– component: path
config:
d: M 80,30 Q 65,50 50,50
fill: none
id: pathBattOut
stroke: rgba(76, 217, 100, 0.1)
stroke-width: 0.5
– component: circle
config:
fill: „#4cd964“
r: 1
visible: =(Math.abs(items[props.itemBatteryDischarge].numericState) > 1)
slots:
default:
– component: animateMotion
config:
calcMode: linear
dur: 3s
repeatCount: indefinite
slots:
default:
– component: mpath
config:
xlink:href: „#pathBattOut“
– component: circle
config:
fill: „#4cd964“
r: 1
visible: =(items[props.itemBatteryCharge].numericState > 0)
slots:
default:
– component: animateMotion
config:
calcMode: linear
dur: 3s
keyPoints: 1;0
keyTimes: 0;1
repeatCount: indefinite
slots:
default:
– component: mpath
config:
xlink:href: „#pathBattOut“
– component: path
config:
d: M 50,50 Q 65,50 80,70
fill: none
id: pathHouse
stroke: rgba(0, 122, 255, 0.1)
stroke-width: 0.5
– component: circle
config:
fill: „#007AFF“
r: 1
visible: =(items[props.itemHouseConsumption].numericState > 0)
slots:
default:
– component: animateMotion
config:
calcMode: linear
dur: 2s
repeatCount: indefinite
slots:
default:
– component: mpath
config:
xlink:href: „#pathHouse“
– component: f7-col
config:
style:
textAlign: center
zIndex: 2
slots:
default:
– component: div
config:
style:
marginBottom: 40px
slots:
default:
– component: oh-icon
config:
color: „#FFCC00“
height: 28
icon: f7:sun_max_fill
– component: Label
config:
style:
fontSize: 14px
fontWeight: „700“
text: =items[props.itemSolarHub].state + ‚ W‘
– component: Label
config:
style:
fontSize: 8px
opacity: 0.4
text: O/W PANELE
– component: div
slots:
default:
– component: oh-icon
config:
color: „#FFDD55“
height: 28
icon: f7:cloud_sun_fill
– component: Label
config:
style:
fontSize: 14px
fontWeight: „700“
text: „=(items[props.itemSolarSouth].numericState > 0) ?
Math.round(items[props.itemSolarSouth].numeri\
cState) + ‚ W‘ : ‚0 W'“
– component: Label
config:
style:
fontSize: 8px
opacity: 0.4
text: SÜD PANEL
– component: div
config:
class: „=(items[props.itemSolarHub].numericState > 1 ||
Math.abs(items[props.itemBatteryDischarge].numericState) >
1) ? ‚energy-pulse‘ : ““
style:
align-items: center
background: rgba(255,255,255,0.03)
border: 1px solid rgba(76, 217, 100, 0.3)
border-radius: 50%
display: flex
height: 80px
justify-content: center
width: 80px
zIndex: 2
slots:
default:
– component: oh-icon
config:
color: „#4cd964“
height: 35
icon: f7:bolt_fill
– component: f7-col
config:
style:
textAlign: center
zIndex: 2
slots:
default:
– component: div
config:
style:
marginBottom: 40px
slots:
default:
– component: oh-icon
config:
color: „#4cd964“
height: 28
icon: „=(items[props.itemBattery].numericState > 20) ? ‚f7:battery_100‘ :
‚f7:battery_25′“
– component: Label
config:
style:
fontSize: 14px
fontWeight: „700“
text: =items[props.itemBattery].state + ‚ %‘
– component: Label
config:
style:
color: „#4cd964“
fontSize: 12px
fontWeight: „600“
marginTop: 2px
text: =‘ + ‚ + items[props.itemBatteryCharge].state + ‚ W‘
visible: =(items[props.itemBatteryCharge].numericState > 0)
– component: Label
config:
style:
color: „#ff9500“
fontSize: 12px
fontWeight: „600“
marginTop: 2px
text: =‘ – ‚ + items[props.itemBatteryDischarge].state + ‚ W‘
visible: =(Math.abs(items[props.itemBatteryDischarge].numericState) > 0.1)
– component: Label
config:
style:
fontSize: 8px
opacity: 0.4
text: BATTERIE
– component: div
slots:
default:
– component: oh-icon
config:
color: „#007AFF“
height: 28
icon: f7:house_alt_fill
– component: Label
config:
style:
color: „#007AFF“
fontSize: 14px
fontWeight: „700“
text: =items[props.itemHouseConsumption].state + ‚ W‘
– component: Label
config:
style:
fontSize: 8px
opacity: 0.4
text: HAUS VERBRAUCH
– component: f7-row
config:
style:
background: rgba(255,255,255,0.04)
border: 1px solid rgba(255,255,255,0.05)
border-radius: 20px
margin-top: 10px
padding: 15px
slots:
default:
– component: f7-col
slots:
default:
– component: Label
config:
style:
fontSize: 10px
opacity: 0.5
text: SOLAR TOTAL
– component: Label
config:
style:
color: „#FF9500“
fontSize: 15px
fontWeight: „700“
text: „=((items[props.itemSolarHub].numericState || 0) +
(items[props.itemSolarSouth].numericState > 0 ?
items[props.itemSolarSouth].numericState :
0)).toFixed(0) + ‚ W'“
– component: f7-col
config:
style:
textAlign: right
slots:
default:
– component: Label
config:
style:
fontSize: 10px
opacity: 0.5
text: NETZBEZUG
– component: Label
config:
style:
color: „=(items[props.itemGrid].numericState > 0) ? ‚#ff3b30‘ : ‚#4cd964′“
fontSize: 15px
fontWeight: „700“
text: =items[props.itemGrid].state + ‚ W‘

Openhab HABPanel Widget Solar/Akku

Widgets für Habpanel


<style>
/* Puls-Animation Definition */
@keyframes pulse-effect {
0% { box-shadow: 0 0 10px rgba(76, 217, 100, 0.4); transform: scale(1); }
50% { box-shadow: 0 0 45px rgba(76, 217, 100, 0.9); transform: scale(1.05); }
100% { box-shadow: 0 0 10px rgba(76, 217, 100, 0.4); transform: scale(1); }
}

.pulse-active {
animation: pulse-effect 2s infinite !important;
border: 2px solid #4cd964 !important;
}
</style>

<div style=“position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: linear-gradient(160deg, #121212 0%, #1e1e1e 100%);
color: white;
padding: 15px;
font-family: sans-serif;
display: flex;
flex-direction: column;
overflow: hidden;
box-sizing: border-box;“>

<!– Header –>
<div style=“height: 20px; font-size: 11px; font-weight: 800; letter-spacing: 1.5px; opacity: 0.4; text-transform: uppercase;“>
Zendure System Kontrolle
</div>

<!– SVG Animationen –>
<svg viewBox=“0 0 100 100″ preserveAspectRatio=“none“
style=“position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1;“>

<!– PFADE: Deine angepassten Koordinaten –>
<path id=“pathHub“ d=“M 25,35 Q 37,25 50,45″ fill=“none“ stroke=“rgba(255, 204, 0, 0.1)“ stroke-width=“0.5″ />
<path id=“pathSouth“ d=“M 25,60 Q 37,70 50,45″ fill=“none“ stroke=“rgba(255, 221, 85, 0.1)“ stroke-width=“0.5″ />
<path id=“pathBattOut“ d=“M 75,35 Q 62,25 50,45″ fill=“none“ stroke=“rgba(76, 217, 100, 0.1)“ stroke-width=“0.5″ />
<path id=“pathHouse“ d=“M 50,45 Q 62,70 75,60″ fill=“none“ stroke=“rgba(0, 122, 255, 0.1)“ stroke-width=“0.5″ />

<!– Animationen (Punkte) –>
<!– Solar O/W –>
<circle ng-if=“itemValue(config.itemSolarHub).split(‚ ‚)[0]*1 > 1″ r=“1.2″ fill=“#FFCC00″>
<animateMotion dur=“3s“ repeatCount=“indefinite“><mpath xlink:href=“#pathHub“ /></animateMotion>
</circle>
<!– Solar Süd –>
<circle ng-if=“itemValue(config.itemSolarSouth).split(‚ ‚)[0]*1 > 1″ r=“1.2″ fill=“#FFDD55″>
<animateMotion dur=“3s“ repeatCount=“indefinite“><mpath xlink:href=“#pathSouth“ /></animateMotion>
</circle>
<!– Entladung (Batterie -> Mitte) –>
<circle ng-if=“itemValue(config.itemBatteryDischarge).split(‚ ‚)[0]*1 > 1″ r=“1.2″ fill=“#4cd964″>
<animateMotion dur=“3s“ repeatCount=“indefinite“><mpath xlink:href=“#pathBattOut“ /></animateMotion>
</circle>
<!– Ladung (Mitte -> Batterie) –>
<circle ng-if=“itemValue(config.itemBatteryCharge).split(‚ ‚)[0]*1 > 1″ r=“1.2″ fill=“#4cd964″>
<animateMotion dur=“3s“ repeatCount=“indefinite“ keyPoints=“1;0″ keyTimes=“0;1″ calcMode=“linear“><mpath xlink:href=“#pathBattOut“ /></animateMotion>
</circle>
<!– Hausverbrauch –>
<circle ng-if=“itemValue(config.itemHouseConsumption).split(‚ ‚)[0]*1 > 1″ r=“1.2″ fill=“#007AFF“>
<animateMotion dur=“2s“ repeatCount=“indefinite“><mpath xlink:href=“#pathHouse“ /></animateMotion>
</circle>
</svg>

<!– Content Grid –>
<div style=“flex-grow: 1; display: flex; justify-content: space-around; align-items: center; position: relative; z-index: 2;“>

<!– Links: Solar –>
<div style=“text-align: center; width: 30%;“>
<div style=“margin-bottom: 20%;“>
<img ng-src=“/icon/solarplant?format=svg“ style=“width: 40px; height: 40px;“ />
<div style=“font-size: 1.2vw; font-weight: 700;“>{{ (itemValue(config.itemSolarHub).split(“ „)[0] | number:0) }} W</div>
<div style=“font-size: 0.7vw; opacity: 0.4;“>O/W PANELE</div>
</div>
<div>
<img ng-src=“/icon/solarplant?format=svg“ style=“width: 40px; height: 40px;“ />
<div style=“font-size: 1.2vw; font-weight: 700;“>{{ (itemValue(config.itemSolarSouth).split(“ „)[0] | number:0) }} W</div>
<div style=“font-size: 0.7vw; opacity: 0.4;“>SÜD PANEL</div>
</div>
</div>

<!– Mitte: GEFÜLLTER KREIS (Mit Puls-Logik) –>
<div ng-class=“{‚pulse-active‘: itemValue(config.itemSolarHub).split(‚ ‚)[0]*1 > 1 || itemValue(config.itemBatteryDischarge).split(‚ ‚)[0]*1 > 1}“
style=“width: 8vw; height: 8vw; max-width: 80px; max-height: 80px; border-radius: 50%; background: #1a3320; border: 2px solid #4cd964; display: flex; justify-content: center; align-items: center;“>
<img ng-src=“/icon/movecontrol?format=svg“ style=“width: 50%; height: 50%;“ />
</div>

<!– Rechts: Batterie & Haus –>
<div style=“text-align: center; width: 30%;“>
<div style=“margin-bottom: 20%;“>
<img ng-src=“/icon/battery?state={{itemValue(config.itemBattery)}}&format=svg“ style=“width: 40px; height: 40px;“ />
<div style=“font-size: 1.2vw; font-weight: 700;“>{{ (itemValue(config.itemBattery).split(“ „)[0] | number:0) }} %</div>

<!– Lade-Leistung (Grün) –>
<div ng-if=“itemValue(config.itemBatteryCharge).split(‚ ‚)[0]*1 > 0.5″ style=“font-size: 0.9vw; font-weight: 600; color: #4cd964;“>
+ {{ (itemValue(config.itemBatteryCharge).split(“ „)[0] | number:0) }} W
</div>
<!– Entlade-Leistung (Orange) –>
<div ng-if=“itemValue(config.itemBatteryDischarge).split(‚ ‚)[0]*1 > 0.5″ style=“font-size: 0.9vw; font-weight: 600; color: #ff9500;“>
– {{ (itemValue(config.itemBatteryDischarge).split(“ „)[0] | number:0) }} W
</div>

<div style=“font-size: 0.7vw; opacity: 0.4;“>BATTERIE</div>
</div>
<div>
<img ng-src=“/icon/group?format=svg“ style=“width: 40px; height: 40px;“ />
<div style=“font-size: 1.2vw; font-weight: 700; color: #007AFF;“>{{ (itemValue(config.itemHouseConsumption).split(“ „)[0] | number:0) }} W</div>
<div style=“font-size: 0.7vw; opacity: 0.4;“>HAUS VERBRAUCH</div>
</div>
</div>
</div>

<!– Footer –>
<div style=“height: 60px; background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.05); border-radius: 20px; padding: 10px; display: flex; justify-content: space-between; align-items: center; z-index: 2;“>
<div style=“display: flex; align-items: center;“>
<img ng-src=“/icon/sun_clouds?format=svg“ style=“width: 30px; height: 30px; margin-right: 10px;“ />
<div>
<div style=“font-size: 0.7vw; opacity: 0.5;“>SOLAR TOTAL</div>
<div style=“color: #FF9500; font-size: 1.3vw; font-weight: 700;“>{{ (1*itemValue(config.itemSolarHub).split(“ „)[0] + 1*itemValue(config.itemSolarSouth).split(“ „)[0]) | number:0 }} W</div>
</div>
</div>
<div style=“text-align: right; display: flex; align-items: center;“>
<div style=“margin-right: 10px;“>
<div style=“font-size: 0.7vw; opacity: 0.5;“>NETZBEZUG</div>
<div ng-style=“{‚color‘: (itemValue(config.itemGrid).split(‚ ‚)[0]*1 > 0) ? ‚#ff3b30‘ : ‚#4cd964‘}“ style=“font-size: 1.3vw; font-weight: 700;“>
{{ (itemValue(config.itemGrid).split(“ „)[0] | number:0) }} W
</div>
</div>
<img ng-src=“/icon/energy?format=svg“ style=“width: 30px; height: 30px;“ />
</div>
</div>
</div>