Animated Energy Widget

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

Hi all.

Thanks for all your contributions to this fancy widget!

A little bit off-topic but:
Does anyone have an icon for a swimming-pool (or a pool pump) in the style of the other icons used on this widget (meaning: square 3D ground plate with shadow plus swimming-pool or pool-pump)?

Thanks and kind regards,
Ralph…

Hi, thanks for this really nice widget. As always, some things need to be adapted for my own system:

  • I have one single value for the power going between house and grid, the sign gives the direction.
  • I use apple equipment, not being capable for auto-sizing
  • I want to see an extra value if the car charges. Therefore, I have a car icon below the house with the power going to the car.
  • I want to see time-prints for each signal. I filled my whole OH page with these time-prints, but finally simply added them to the widget. Unfortunately, it’s not that easy to get the values via the setup - you have to hard-code them in the widget-code - what I finally did. It’s not nice in the code, but it looks and works very nicely!
    Thus, if anybody wants benefit from my effort, like I did from yours, here is my code:
uid: SMA_widget
tags: []
props:
  parameters:
    - context: item
      label: Netzeinspeisung
      name: netzeinspeisung
      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: Batterieleistung
      name: batterieleistung
      required: true
      type: TEXT
    - context: item
      label: Batterie Ladezustand
      name: batterylevel
      required: true
      type: TEXT
    - context: item
      label: Autoleistung
      name: autoleistung
      required: true
      type: TEXT
  parameterGroups: []
timestamp: Jun 17, 2023, 12:34:45 PM
component: f7-card
config:
  class:
    - display-flex
    - flex-direction-column
    - align-items-center
  style:
    height: 413px
    width: 383px
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: sma_grid_2
                          action: analyzer
                          actionAnalyzerItems: props.netzeinspeisung
                          actionAnalyzerCoordSystem: time
                      - component: oh-link
                        config:
                          action: analyzer
                          actionAnalyzerItems:
                            - ModbusSM_R_Value_as_Number
                            - ModbusSM_S_Value_as_Number
                            - ModbusSM_T_Value_as_Number
                          actionAnalyzerCoordSystem: time
                          style:
                            color: red
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            width: 100px
                          text: =Number.parseInt(-1*items[props.netzeinspeisung].state)+ ' W'
                          visible: '=(Number.parseInt(items[props.netzeinspeisung].state.split(" ")[0]) <= 0) ? true : false'
                      - component: oh-link
                        config:
                          action: analyzer
                          actionAnalyzerItems:
                            - ModbusSM_R_Value_as_Number
                            - ModbusSM_S_Value_as_Number
                            - ModbusSM_T_Value_as_Number
                          actionAnalyzerCoordSystem: time
                          style:
                            color: green
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            width: 100px
                          text: =Number.parseInt(items[props.netzeinspeisung].state)+ ' W'
                          visible: '=(Number.parseInt(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: oh-link
                        config:
                          action: analyzer
                          actionAnalyzerItems:
                            - PV1
                            - PV2
                          actionAnalyzerCoordSystem: time
                          style:
                            color: grey
                            font-size: 25px
                            font-weight: bold
                            text-align: center
                            width: 100px
                          text: =Number.parseInt(items[props.pv_leistung].state)+ ' W'
                      - component: oh-icon
                        config:
                          height: 110px
                          icon: sma_pv_2
                          style:
                            margin-top: -20px
                - 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: 100
                            width: 100
                          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: '=(Number.parseInt(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: '=(Number.parseInt(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.parseInt(items[props.netzeinspeisung].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.parseInt(items[props.netzeinspeisung].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.parseInt(items[props.pv_leistung].state.split(" ")[0]) - (Number.parseInt(items[props.netzeinspeisung].state.split(" ")[0]) + Math.abs(Number.parseInt(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.parseInt(items[props.pv_leistung].state.split(" ")[0]) - (Number.parseInt(items[props.netzeinspeisung].state.split(" ")[0]) + Math.abs(Number.parseInt(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: "#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.parseInt(items[props.netzeinspeisung].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.parseInt(items[props.netzeinspeisung].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.parseInt(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.parseInt(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: -20px
                      width: 110px
                  slots:
                    default:
                      - component: oh-icon
                        config:
                          color: orange
                          height: 110px
                          icon: sma_consumption_2
                      - component: oh-link
                        config:
                          action: analyzer
                          actionAnalyzerItems:
                            - HausVerbrauch
                          actionAnalyzerCoordSystem: time
                          style:
                            color: grey
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            width: 100px
                          text: =Number.parseInt(Number.parseInt(items[props.gesamtverbrauch].state)-1000*Number.parseFloat(items[props.autoleistung].state))+ ' W'
                      - component: oh-link
                        config:
                          action: analyzer
                          actionAnalyzerItems:
                            - Wallbox_Total_Power
                          actionAnalyzerCoordSystem: time
                          iconColor: orange
                          iconF7: car_fill
                          iconSize: 33px
                          style:
                            color: grey
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            width: 100px
                          text: =Number.parseInt(1000*Number.parseFloat(items[props.autoleistung].state))+ ' W'
                          visible: '=(Number.parseInt(items[props.autoleistung].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-link
                        config:
                          iconColor: red
                          iconF7: battery_0
                          iconSize: 33px
                          action: analyzer
                          actionAnalyzerItems:
                            - HausBatterie
                          actionAnalyzerCoordSystem: time
                          style:
                            font-size: 25px
                            font-weight: bold
                            white-space: nowrap
                          text: =items[props.batterylevel].state
                          visible: '=(Number.parseInt(items[props.batterylevel].state.split(" ")[0]) < 10) ? true : false'
                      - component: oh-link
                        config:
                          iconColor: orange
                          iconF7: battery_25
                          iconSize: 33px
                          action: analyzer
                          actionAnalyzerItems:
                            - HausBatterie
                          actionAnalyzerCoordSystem: time
                          style:
                            color: grey
                            font-size: 25px
                            font-weight: bold
                            white-space: nowrap
                          text: =items[props.batterylevel].state
                          visible: '=(Number.parseInt(items[props.batterylevel].state.split(" ")[0]) >= 10 && Number.parseInt(items[props.batterylevel].state.split(" ")[0]) < 75) ? true : false'
                      - component: oh-link
                        config:
                          iconColor: green
                          iconF7: battery_100
                          iconSize: 33px
                          action: analyzer
                          actionAnalyzerItems:
                            - HausBatterie
                          actionAnalyzerCoordSystem: time
                          style:
                            color: grey
                            font-size: 25px
                            font-weight: bold
                            white-space: nowrap
                          text: =items[props.batterylevel].state
                          visible: '=(Number.parseInt(items[props.batterylevel].state.split(" ")[0]) >= 75) ? true : false'
                      - component: oh-icon
                        config:
                          height: 110px
                          icon: sma_battery_2
                          style:
                            margin-top: -20px
                      - component: oh-link
                        config:
                          action: analyzer
                          actionAnalyzerItems:
                            - HausbatteryCharge
                          actionAnalyzerCoordSystem: time
                          style:
                            color: '=(Number.parseInt(items[props.batterieleistung].state.split(" ")[0]) > 0) ? "red" : "green"'
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            white-space: nowrap
                            width: 100px
                          text: =Math.abs(Number.parseInt(items[props.batterieleistung].state.split(" ")[0])) + ' W'
                          visible: '=(Number.parseInt(items[props.batterieleistung].state.split(" ")[0]) !== 0) ? true : false'

This is my solution for three inverters

uid: SMA_widget
tags: []
props:
  parameters:
    - context: item
      label: PV Wechselrichter 1
      name: power_inverter_1
      required: true
      type: TEXT
    - context: item
      label: PV Wechselrichter 2
      name: power_inverter_2
      required: true
      type: TEXT
    - context: item
      label: PV Wechselrichter 3
      name: power_inverter_4
      required: true
      type: TEXT
    - context: item
      label: PV Wechselrichter
      name: power_inverter
      required: true
      type: TEXT
    - context: item
      label: Netzeinspeisung
      name: power_grid_to
      required: true
      type: TEXT
    - context: item
      label: Netzbezug
      name: power_grid_from
      required: true
      type: TEXT
    - context: item
      label: Gesamtverbrauch
      name: power_load
      required: true
      type: TEXT
    - context: item
      label: Batterieleistung
      name: power_battery
      required: true
      type: TEXT
    - context: item
      label: Batterie Ladezustand
      name: battery_soc
      required: true
      type: TEXT
  parameterGroups: []
timestamp: Jul 6, 2023, 1:16:38 PM
component: f7-card
config:
  class:
    - display-flex
    - flex-direction-column
    - align-items-center
  style:
    height: 590px
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: sma_pv_2
                      - component: Label
                        config:
                          style:
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            width: 100px
                          text: = Math.round(Number.parseFloat(items[props.power_inverter_2].state.split(" ")[0])) + ' ᵂ'
          - 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: 25px
                            font-weight: bold
                            text-align: center
                            width: 100px
                          text: = Math.round(Number.parseFloat(items[props.power_inverter_1].state.split(" ")[0])) + ' ᵂ'
                      - component: oh-icon
                        config:
                          height: 110px
                          icon: sma_pv_2
                          style:
                            margin-top: -20px
                - 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: 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: 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: false
                            - component: f7-row
                              config:
                                fill: rgba(100, 150, 200, 0.8)
                                r: 6
                                strokeWidth: 10
                                tag: circle
                                vectorEffect: non-scaling-stroke
                                visible: 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.power_inverter_1].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.power_inverter_1].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: "#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.power_inverter_2].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.power_inverter_2].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.power_inverter_4].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.power_inverter_4].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-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: sma_pv_2
                      - component: Label
                        config:
                          style:
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            width: 100px
                          text: = Math.round(Number.parseFloat(items[props.power_inverter_4].state.split(" ")[0])) + ' ᵂ'


    - 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: sma_grid_2
                      - component: Label
                        config:
                          style:
                            color: red
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            width: 100px
                          text: = Math.round(Number.parseFloat(items[props.power_grid_from].state.split(" ")[0])) + ' ᵂ'
                          visible: '=(Number.parseFloat(items[props.power_grid_to].state.split(" ")[0]) == 0) ? true : false'
                      - component: Label
                        config:
                          style:
                            color: green
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            width: 100px
                          text: = Math.round(Number.parseFloat(items[props.power_grid_to].state.split(" ")[0])) + ' ᵂ'
                          visible: '=(Number.parseFloat(items[props.power_grid_to].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: oh-icon
                        config:
                          height: 110px
                          icon: sma_pv_2
                          style:
                            margin-top: -35px
                      - component: Label
                        config:
                          style:
                            font-size: 25px
                            font-weight: bold
                            text-align: center
                            margin-right: -200px
                            margin-top: -70px
                            width: 100px
                          text: = Math.round(Number.parseFloat(items[props.power_inverter].state.split(" ")[0])) + ' ᵂ'
                - 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: '=(Number.parseFloat(items[props.power_battery].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: '=(Number.parseFloat(items[props.power_battery].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.power_grid_to].state.split(" ")[0]) > 0 && Number.parseFloat(items[props.power_grid_from].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.power_grid_to].state.split(" ")[0]) > 0 && Number.parseFloat(items[props.power_grid_from].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.power_inverter].state.split(" ")[0]) - (Number.parseFloat(items[props.power_grid_to].state.split(" ")[0]) + Math.abs(Number.parseFloat(items[props.power_battery].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.power_inverter].state.split(" ")[0]) - (Number.parseFloat(items[props.power_grid_to].state.split(" ")[0]) + Math.abs(Number.parseFloat(items[props.power_battery].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: "#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.power_grid_from].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.power_grid_from].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.power_battery].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.power_battery].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:
                          color: orange
                          height: 110px
                          icon: sma_consumption_2
                      - component: Label
                        config:
                          style:
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            width: 100px
                          text: =Math.round(Number.parseFloat(items[props.power_load].state.split(" ")[0])) + ' ᵂ'
          - 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-link
                        config:
                          iconColor: red
                          iconF7: battery_0
                          iconSize: 33px
                          style:
                            font-size: 25px
                            font-weight: bold
                            white-space: nowrap
                          text: =items[props.battery_soc].state.split(" ")[0] + ' ᵂ'
                          visible: '=(Number.parseFloat(items[props.battery_soc].state.split(" ")[0]) < 10) ? true : false'
                      - component: oh-link
                        config:
                          iconColor: orange
                          iconF7: battery_25
                          iconSize: 33px
                          style:
                            font-size: 25px
                            font-weight: bold
                            white-space: nowrap
                          text: =items[props.battery_soc].state.split(" ")[0] + ' ᵂ'
                          visible: '=(Number.parseFloat(items[props.battery_soc].state.split(" ")[0]) >= 10 && Number.parseFloat(items[props.battery_soc].state.split(" ")[0]) < 75) ? true : false'
                      - component: oh-link
                        config:
                          iconColor: green
                          iconF7: battery_100
                          iconSize: 33px
                          style:
                            font-size: 25px
                            font-weight: bold
                            white-space: nowrap
                          text: =items[props.battery_soc].state.split(" ")[0] + ' ᵂ'
                          visible: '=(Number.parseFloat(items[props.battery_soc].state.split(" ")[0]) >= 75) ? true : false'
                      - component: oh-icon
                        config:
                          height: 110px
                          icon: sma_battery_2
                          style:
                            margin-top: -20px
                          visible: '=(Number.parseFloat(items[props.power_battery].state.split(" ")[0]) !== 0) ? true : false'
                      - component: Label
                        config:
                          style:
                            color: '=(Number.parseFloat(items[props.power_battery].state.split(" ")[0]) > 0) ? "red" : "green"'
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            white-space: nowrap
                            width: 100px
                          text: =Math.abs(Number.parseFloat(items[props.power_battery].state.split(" ")[0])) + ' ᵂ'
                          visible: '=(Number.parseFloat(items[props.power_battery].state.split(" ")[0]) !== 0) ? true : false'

i did also some update for battery. if you have no battery in your system it won’t be shown

3 Likes

Hello,
i managed to adjust your basic widget to my needs and it works great! The only thing is, the animated lines, where the dot “drives” on, does not work on the android OH App.

On my phone entering the OH Dashboard via chrome app → Lines and Animation works.
In the App the are not visible, so the App might be the problem.

Is it working for you?

Bravo @Sebastian_Neu !
I just added this widget to my OH4 install.
Two questions, if you are willing:

  1. In my experience, there is no difference between the Netzleistung and Netzbezug. I speak a little Deutsch, so i translated all the variables to English, and when I spun up the widget, these two routed to the same item (Tesla binding-> Instantaneous Grid Power). I understand the difference from a terminology standpoint, but can you elaborate on why there are two different variables for this, and what the impact of that is?

  2. I’d like to add another card to the widget, but have 0 clue here. I’ve tried to reverse engineer the existing widget, but am at a loss as to how i can add an EV which would only receive power from the house. This would be great to add on for me, as I can tell when and where power is going at a glance.
    Any tips would be massively appreciated.

Thanks!
chapo!

This widget is great. That’s exactly what I was looking for. Unfortunately, I only get the charge level of my battery displayed. The other items are actually set up in the same way. The only difference is that they were created as number:power.

I would be very grateful for your help.

I use the widget on Windows where everything is working out fine. I tried on IOS but there the energy flow lines disappeared.

Has anybody a solution for this?

Thanks to @svenr for this hint. It also resolved my IOS issue.

I have used the openHAB internal “batterylevel” icon instead of the Framework 7 icons. Here is the related code section of the widget:

                      - component: oh-icon
                        config:
                          icon: oh:batterylevel
                          state: =items.Modbus_Data_SMA_Batterie_Ladezustand_Value_as_Number.state
                          width: 30
                      - component: oh-link
                        config:
                          style:
                            font-size: 15px
                            font-weight: bold
                            white-space: nowrap
                          text: =items[props.batterylevel].state + ' %'

Please replace my battery level item name “Modbus_Data_SMA_Batterie_Ladezustand_Value_as_Number” against yours. This icon changes its state and color (red, orange and green) and updates level in 10 steps of 10%.

Sharing my variant based on @demichve version

image

Key differences:

  • English item names
  • The animation speed is dependent on the power consumption… more consumption, faster movement.
  • Includes the battery again
uid: SMA_widget5
tags: []
props:
  parameters:
    - context: item
      label: Power Import
      name: power_import
      required: true
      type: TEXT
    - context: item
      label: Power Export
      name: power_export
      required: true
      type: TEXT
    - context: item
      label: Total Power Consumption
      name: totalconsumption
      required: true
      type: TEXT
    - context: item
      label: PV Production
      name: pv_production
      required: true
      type: TEXT
    - context: item
      label: Export Today
      name: export_today
      required: true
      type: TEXT
    - context: item
      label: Import Today
      name: import_today
      required: true
      type: TEXT
    - context: item
      label: PV Production Total
      name: pv_productiontotal
      required: true
      type: TEXT
    - context: item
      label: PV Production Today
      name: pv_productionday
      required: true
      type: TEXT
    - context: item
      label: Battery Power
      name: batterypower
      required: true
      type: TEXT
    - context: item
      label: Battery Level
      name: batterylevel
      required: true
      type: TEXT
    - default: 5000
      label: Animation Speed
      name: animationspeed
      required: true
      type: TEXT
  parameterGroups: []
timestamp: Dec 18, 2023, 8:26:23 PM
component: f7-card
config:
  class:
    - display-flex
    - flex-direction-column
    - align-items-center
  style:
    height: 365px
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
                text-align: left
            slots:
              default:
                - component: f7-block
                  config:
                    style:
                      align-items: left
                      display: flex
                      flex-direction: column
                      height: 140px
                      justify-content: left
                      margin-right: -10px
                      width: 140px
                      text-align: left
                      top: -25px
                  slots:
                    default:
                      - component: Label
                        config:
                          style:
                            color: red
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            width: 110px
                          text: =Math.abs(Number.parseFloat(items[props.power_import].state.split(" ")[0])).toFixed(0) + ' ᵂ'
                          visible: '= Number.parseFloat(items[props.power_import].state.split(" ")[0]) > 0 ? true : false'
                      - component: Label
                        config:
                          style:
                            color: green
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            width: 110px
                          text: = '-' + Math.abs(Number.parseFloat(items[props.power_import].state.split(" ")[0])).toFixed(0) + ' ᵂ'
                          visible: '= Number.parseFloat(items[props.power_import].state.split(" ")[0]) <= 0 ? true : false'
                      - component: oh-icon
                        config:
                          height: 110px
                          icon: sma_grid_2
                          width: 110px
                      - component: oh-link
                        config:
                          iconColor: green
                          iconF7: arrow_turn_up_left
                          iconSize: 20px
                          style:
                            font-size: 15px
                            font-weight: bold
                            left: 0px
                            margin-top: -10px
                            align: left
                            top: 0px
                            white-space: nowrap
                          text: =Math.abs(Number.parseFloat(items[props.export_today].state.split(" ")[0])).toFixed(0) + ' kWh'
                          visible: "true"
                      - component: oh-link
                        config:
                          iconColor: red
                          iconF7: arrow_turn_down_right
                          iconSize: 20px
                          style:
                            font-size: 15px
                            font-weight: bold
                            align: left
                            left: 0px
                            top: 0px
                            white-space: nowrap
                          text: =Math.abs(Number.parseFloat(items[props.import_today].state.split(" ")[0])).toFixed(0) + ' kWh'
                          visible: "true"
          - 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:
                            color: green
                            font-size: 25px
                            font-weight: bold
                            text-align: center
                            width: 100px
                          text: =Math.abs(Number.parseFloat(items[props.pv_production].state.split(" ")[0])).toFixed(0) + ' ᵂ'
                      - component: oh-icon
                        config:
                          height: 110px
                          icon: sma_pv_2
                          style:
                            margin-top: -20px
                - 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: 100px
                            width: 100px
                          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: "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: "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.power_import].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.power_import].state.split(" ")[0]) < 0  ? true : false'
                              slots:
                                default:
                                  - component: f7-row
                                    config:
                                      calcMode: linear
                                      dur: '=(Number.parseFloat(items[props.power_import].state.split(" ")[0]) > 0 ? props.animationspeed / Number.parseFloat(items[props.power_import].state.split(" ")[0])  : 0)+"s"'
                                      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_production].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_production].state.split(" ")[0]) > 0 ? true : false'
                              slots:
                                default:
                                  - component: f7-row
                                    config:
                                      calcMode: linear
                                      dur: '=(Number.parseFloat(items[props.pv_production].state.split(" ")[0]) > 0 ? props.animationspeed / Number.parseFloat(items[props.pv_production].state.split(" ")[0])  : 0)+"s"'
                                      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.power_import].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.power_import].state.split(" ")[0]) > 0 ? true : false'
                              slots:
                                default:
                                  - component: f7-row
                                    config:
                                      calcMode: linear
                                      dur: '=(Number.parseFloat(items[props.power_import].state.split(" ")[0]) > 0 ? props.animationspeed / Number.parseFloat(items[props.power_import].state.split(" ")[0])  : 0)+"s"'
                                      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.batterypower].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.batterypower].state.split(" ")[0]) > 0) ? true : false'
                              slots:
                                default:
                                  - component: f7-row
                                    config:
                                      calcMode: linear
                                      dur: '=(Number.parseFloat(items[props.batterypower].state.split(" ")[0]) > 0 ? props.animationspeed / Number.parseFloat(items[props.batterypower].state.split(" ")[0])  : 0)+"s"'
                                      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:
                          color: orange
                          height: 110px
                          icon: sma_consumption_2
                      - component: Label
                        config:
                          style:
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            width: 100px
                          text: =Math.abs(Number.parseFloat(items[props.totalconsumption].state.split(" ")[0])).toFixed(0) + ' ᵂ'
          - component: f7-col
            config:
              style:
                align-items: center
                display: flex
                flex-direction: row
            slots:
              default:
                - component: f7-block
                  config:
                    style:
                      align-items: left
                      display: flex
                      flex-direction: column
                      height: 110px
                      justify-content: center
                      margin-top: -100px
                      width: 110px
                  slots:
                    default:
                      - component: oh-link
                        config:
                          iconAlign: left
                          iconColor: black
                          iconF7: sum
                          iconSize: 15px
                          style:
                            font-size: 15px
                            font-weight: bold
                            left: 0px
                            margin-left: -200px
                            position: absolute
                            text-align: right
                            top: -20px
                            white-space: nowrap
                          text: =Math.abs(Number.parseFloat(items[props.pv_productiontotal].state.split(" ")[0])).toFixed(0) + ' kWh'
                          visible: "true"
                      - component: oh-link
                        config:
                          iconAlign: left
                          iconColor: black
                          iconF7: calendar_today
                          iconSize: 15px
                          style:
                            font-size: 15px
                            font-weight: bold
                            left: 0px
                            margin-left: -200px
                            position: absolute
                            text-align: right
                            top: -40px
                            white-space: nowrap
                          text: =Math.abs(Number.parseFloat(items[props.pv_productionday].state.split(" ")[0])).toFixed(0) + ' kWh'
                          visible: "true"
                      - component: oh-link
                        config:
                          iconColor: red
                          iconF7: battery_0
                          iconSize: 33px
                          style:
                            font-size: 25px
                            font-weight: bold
                            white-space: nowrap
                          text: =items[props.batterylevel].state
                          visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) < 10) ? true : false'
                      - component: oh-link
                        config:
                          iconColor: orange
                          iconF7: battery_25
                          iconSize: 33px
                          style:
                            font-size: 25px
                            font-weight: bold
                            white-space: nowrap
                          text: =items[props.batterylevel].state
                          visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) >= 10 && Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) < 75) ? true : false'
                      - component: oh-link
                        config:
                          iconColor: green
                          iconF7: battery_100
                          iconSize: 33px
                          style:
                            font-size: 25px
                            font-weight: bold
                            white-space: nowrap
                          text: =items[props.batterylevel].state
                          visible: '=(Number.parseFloat(items[props.batterylevel].state.split(" ")[0]) >= 75) ? true : false'
                      - component: oh-icon
                        config:
                          height: 110px
                          icon: sma_battery_2
                          style:
                            margin-top: -20px
                      - component: Label
                        config:
                          style:
                            color: '=(Number.parseFloat(items[props.batterypower].state.split(" ")[0]) > 0) ? "red" : "green"'
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            white-space: nowrap
                            width: 100px
                          text: =Math.abs(Number.parseFloat(items[props.batterypower].state.split(" ")[0])) + ' ᵂ'
                          visible: '=(Number.parseFloat(items[props.batterypower].state.split(" ")[0]) !== 0) ? true : false'


1 Like

Thanks for all our inputs. I started custom widgets this week and I need to say, “its a strange development”. Difficult to keep the versions. I copy ALL into VS Code and use GIT from time to time.
I have no documentation how the editor works. A version with VS Code like former items in V2 would be great !!
But with all the nice examples I will build up my experience and continue building the UI.
Her is my example of ‘Home power’ implementation.

1 Like

Sharing a new adapted version of the widget (based on my requirements):

Key differences:

  • Integration of charging using a wallbox
  • Integration of EVCC for smart charging (can be actived/deactivated by clicking)
  • Manual charging settings for the wallbox (in case EVCC is deactivated)
  • Some other click navigations to analyse the data
  • New icons

Attention: The integration of the wallbox requires some changes in the logic to determine the current power values. In addition there are several additional openhab items integrated. Please check, if this fits into your scenario.

uid: Power_Widget_2
tags: []
props:
  parameters:
    - context: item
      label: Aktuelle Grid Leistung (W)
      name: netzeinspeisung
      required: true
      type: TEXT
    - context: item
      label: Aktueller Eigenverbrauch (W)
      name: gesamtverbrauch
      required: true
      type: TEXT
    - context: item
      label: Aktuelle PV Leistung (W)
      name: pv_leistung
      required: true
      type: TEXT
    - context: item
      label: Gesamt Stromeinspeisung (kWh)
      name: stromeinspeisung
      required: true
      type: TEXT
    - context: item
      label: Gesamt Strombezug (kWh)
      name: strombezug
      required: true
      type: TEXT
    - context: item
      label: PV Gesamtproduktion (kWh)
      name: gesamtproduktion
      required: true
      type: TEXT
    - context: item
      label: PV Tagesproduktion (kWh)
      name: tagesproduktion
      required: true
      type: TEXT
    - context: item
      label: Aktuelle Wallbox Leistung (kW)
      name: wallboxleistung
      required: true
      type: TEXT
    - context: item
      label: Wallboxleistung über EVCC (kW)
      name: wallboxleistung_evcc
      required: true
      type: TEXT
    - context: item
      label: Wallbox Einstellung (kW)
      name: wallboxeinstellung
      required: true
      type: TEXT
    - context: item
      label: Schalter Überschussladen
      name: wallboxueberschuss
      required: true
      type: TEXT
  parameterGroups: []
timestamp: Jan 1, 2024, 5:10:57 PM
component: f7-card
config:
  class:
    - display-flex
    - flex-direction-column
    - align-items-center
  style:
    height: 365px
    text-align: left
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
                text-align: left
            slots:
              default:
                - component: f7-block
                  config:
                    style:
                      align-items: left
                      display: flex
                      flex-direction: column
                      height: 100px
                      justify-content: left
                      margin-right: -10px
                      text-align: left
                      top: -25px
                      width: 130px
                  slots:
                    default:
                      - component: oh-link
                        config:
                          action: analyzer
                          actionAnalyzerItem:
                            - Strom_Monatseinspeisung
                          style:
                            color: red
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            width: 110px
                          text: =Math.abs(Number.parseFloat(items[props.netzeinspeisung].state.split(" ")[0])).toFixed(0) + ' ᵂ'
                          visible: '= Number.parseFloat(items[props.netzeinspeisung].state.split(" ")[0]) > 0 ? true : false'
                      - component: oh-link
                        config:
                          action: analyzer
                          actionAnalyzerItems:
                            - Strom_Monatseinspeisung
                          style:
                            color: green
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            width: 110px
                          text: = '-' + Math.abs(Number.parseFloat(items[props.netzeinspeisung].state.split(" ")[0])).toFixed(0) + ' ᵂ'
                          visible: '= Number.parseFloat(items[props.netzeinspeisung].state.split(" ")[0]) <= 0 ? true : false'
                      - component: oh-icon
                        config:
                          height: 70px
                          icon: powergrid_1
                          style:
                            margin-left: 20px
                            margin-top: 0px
                          width: 70px
                      - component: oh-link
                        config:
                          action: analyzer
                          actionAnalyzerItems:
                            - Strom_Monatseinspeisung
                          iconColor: green
                          iconF7: arrow_turn_up_left
                          iconSize: 20px
                          style:
                            align: left
                            font-size: 15px
                            font-weight: bold
                            left: 0px
                            margin-top: 10px
                            top: 0px
                            white-space: nowrap
                          text: =Math.abs(Number.parseFloat(items[props.stromeinspeisung].state.split(" ")[0])).toFixed(0) + ' ᵏᵂʰ'
                          visible: "true"
                      - component: oh-link
                        config:
                          action: analyzer
                          actionAnalyzerItems:
                            - Strom_Monatsverbrauch
                          iconColor: red
                          iconF7: arrow_turn_down_right
                          iconSize: 20px
                          style:
                            align: left
                            font-size: 15px
                            font-weight: bold
                            left: 0px
                            top: 0px
                            white-space: nowrap
                          text: =Math.abs(Number.parseFloat(items[props.strombezug].state.split(" ")[0])).toFixed(0) + ' ᵏᵂʰ'
                          visible: "true"
          - 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: oh-link
                        config:
                          action: analyzer
                          actionAnalyzerItems:
                            - inverter1ActivePower
                          style:
                            font-size: 25px
                            font-weight: bold
                            text-align: center
                            width: 100px
                          text: =Math.abs(Number.parseFloat(items[props.pv_leistung].state.split(" ")[0])).toFixed(0) + ' ᵂ'
                      - component: oh-icon
                        config:
                          height: 60px
                          icon: solarpanel
                          style:
                            margin-top: -1px
                - 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: 100px
                            width: 100px
                          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: '= (Number.parseFloat(items[props.pv_leistung].state.split(" ")[0]) > 0 && Number.parseFloat(items[props.wallboxleistung].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: '= (Number.parseFloat(items[props.pv_leistung].state.split(" ")[0]) > 0 && Number.parseFloat(items[props.wallboxleistung].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  ? 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  ? 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])  > 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_leistung].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: "#path3"
                            - component: f7-row
                              config:
                                d: M0 45 200 45
                                fill: none
                                id: path8
                                stroke: rgba(100, 150, 200, 0.8)
                                stroke-width: 2
                                style:
                                  margin-top: 150px
                                tag: path
                                vector-effect: non-scaling-stroke
                                visible: '= (Number.parseFloat(items[props.netzeinspeisung].state.split(" ")[0]) > 0 && Number.parseFloat(items[props.wallboxleistung].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.wallboxleistung].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"
                            - 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.netzeinspeisung].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 ? 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: "false"
                            - component: f7-row
                              config:
                                fill: rgba(100, 150, 200, 0.8)
                                r: 6
                                strokeWidth: 10
                                tag: circle
                                vectorEffect: non-scaling-stroke
                                visible: "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:
                          color: orange
                          height: 80px
                          icon: haus_power
                      - component: Label
                        config:
                          style:
                            font-size: 25px
                            font-weight: bold
                            margin-left: 8px
                            margin-top: -5px
                            text-align: center
                            width: 100px
                          text: =Math.abs(Number.parseFloat(items[props.gesamtverbrauch].state.split(" ")[0]) - Number.parseFloat(items[props.wallboxleistung_evcc].state.split(" ")[0])).toFixed(0) + ' ᵂ'
                          visible: '= items[props.wallboxueberschuss].displayState == "Aktiv" ? true : false'
                      - component: Label
                        config:
                          style:
                            font-size: 25px
                            font-weight: bold
                            margin-left: 8px
                            margin-top: -5px
                            text-align: center
                            width: 100px
                          text: =Math.abs(Number.parseFloat(items[props.gesamtverbrauch].state.split(" ")[0]) - Number.parseFloat(items[props.wallboxleistung].state.split(" ")[0])).toFixed(0) + ' ᵂ'
                          visible: '= items[props.wallboxueberschuss].displayState == "Inaktiv" ? true : false'
          - component: f7-col
            config:
              style:
                align-items: center
                display: flex
                flex-direction: row
            slots:
              default:
                - component: f7-block
                  config:
                    style:
                      align-items: left
                      display: flex
                      flex-direction: column
                      height: 110px
                      justify-content: center
                      margin-top: -250px
                      width: 110px
                  slots:
                    default:
                      - component: oh-link
                        config:
                          iconAlign: left
                          iconColor: black
                          iconF7: sum
                          iconSize: 15px
                          style:
                            font-size: 15px
                            font-weight: bold
                            left: 40px
                            margin-left: -50px
                            position: absolute
                            text-align: right
                            top: 40px
                            white-space: nowrap
                          text: =Math.abs(Number.parseFloat(items[props.gesamtproduktion].state.split(" ")[0])).toFixed(0) + ' ᵏᵂʰ'
                          visible: "true"
                      - component: oh-link
                        config:
                          iconAlign: left
                          iconColor: black
                          iconF7: calendar_today
                          iconSize: 15px
                          style:
                            font-size: 15px
                            font-weight: bold
                            left: 40px
                            margin-left: -50px
                            position: absolute
                            text-align: right
                            top: 60px
                            white-space: nowrap
                          text: =Math.abs(Number.parseFloat(items[props.tagesproduktion].state.split(" ")[0])).toFixed(0) + ' ᵏᵂʰ'
                          visible: "true"
                      - component: oh-link
                        config:
                          action: options
                          actionItem: Flag_Ueberschuss
                          actionOptions: ON=Aktiv, OFF=Inaktiv
                          style:
                            font-size: 10px
                            font-weight: bold
                            margin-left: -20px
                            margin-top: 260px
                            text-align: right
                            white-space: nowrap
                            width: 100px
                          text: Überschussladen
                          visible: "true"
                      - component: oh-link
                        config:
                          action: options
                          actionItem: Flag_Ueberschuss
                          actionOptions: ON=Aktiv, OFF=Inaktiv
                          height: 20
                          iconAlign: left
                          iconColor: green
                          iconF7: checkmark_rectangle_fill
                          iconSize: 20px
                          style:
                            font-size: 12px
                            font-weight: bold
                            margin-left: -20px
                            margin-top: 0px
                            text-align: right
                            white-space: nowrap
                            width: 100px
                          text: = items[props.wallboxueberschuss].displayState
                          visible: '= items[props.wallboxueberschuss].displayState == "Aktiv" ? true : false'
                      - component: oh-link
                        config:
                          action: options
                          actionItem: Flag_Ueberschuss
                          actionOptions: ON=Aktiv, OFF=Inaktiv
                          height: 20
                          iconAlign: left
                          iconColor: red
                          iconF7: minus_rectangle_fill
                          iconSize: 20px
                          style:
                            font-size: 12px
                            font-weight: bold
                            margin-left: -20px
                            margin-top: 0px
                            text-align: right
                            white-space: nowrap
                            width: 100px
                          text: = items[props.wallboxueberschuss].displayState
                          visible: '= items[props.wallboxueberschuss].displayState == "Inaktiv" ? true : false'
                      - component: oh-icon
                        config:
                          action: url
                          actionUrl: http://192.168.178.70:7070
                          height: 100
                          icon: wallbox_auto
                          style:
                            margin-left: -15px
                            margin-top: -20px
                          visible: '= items[props.wallboxueberschuss].displayState == "Aktiv" ? true : false'
                          width: 100
                      - component: oh-icon
                        config:
                          height: 100
                          icon: wallbox_auto
                          style:
                            margin-left: -15px
                            margin-top: -20px
                          visible: '= items[props.wallboxueberschuss].displayState == "Inaktiv" ? true : false'
                          width: 100
                      - component: oh-link
                        config:
                          action: options
                          actionItem: Easee_Circuit_Dynamic_Phases
                          actionOptions: 0;0;0 = 0 kW , 6;0;0 = 1.4 kW , 8;0;0 = 1.8 kW , 10;0;0 = 2.3 kW , 13;0;0 = 3.0 kW ,  16;0;0 = 3.7 kW , 6;6;6=4.2 kW (3P), 8;8;8=5.5 kW (3P), 10;10;10=6.9 kW (3P), 12;12;12=8.3 kW (3P), 14;14;14=9.7 kW (3P), 16;16;16=11.0 kW (3P)
                          style:
                            font-size: 25px
                            font-weight: bold
                            margin-left: -20px
                            margin-top: -20px
                            text-align: right
                            white-space: nowrap
                            width: 100px
                          text: =Math.abs(Number.parseFloat(items[props.wallboxleistung].displayState.split(" ")[0])) + ' ᵏᵂ'
                          visible: '= items[props.wallboxueberschuss].displayState == "Inaktiv" ? true : false'
                      - component: Label
                        config:
                          style:
                            font-size: 25px
                            font-weight: bold
                            margin-left: -20px
                            margin-top: -20px
                            text-align: center
                            white-space: nowrap
                            width: 100px
                          text: =Math.abs(Number.parseFloat(items[props.wallboxleistung_evcc].displayState.split(" ")[0])) + ' ᵏᵂ'
                          visible: '= items[props.wallboxueberschuss].displayState == "Aktiv" ? true : false'

5 Likes

Nice… Where are the icons :grin:
Is there a battery icon too?
Greets

Is this widget or a similar one also available for HABPanel

Hmm, what is the meaning (and translation) of these words in the original post:

Not clear:

  1. label: Netzeinspeisung → ? Import power?
  2. label: Netzbezug → ? what is the difference to 1.

These seem to be clear…

  1. label: Gesamtverbrauch → total load power? what is being consumed right now.
  2. label: PV Leistung – solar power
  3. label: Batterieleistung → battery power
  4. label: Batterie Ladezustand → state of charge

Thanks.


Also… are the calculations, like these:

visible: '=(Number.parseFloat(items[props.netzeinspeisung].state.split(" ")[0]) > 0) ? true : false'

… expecting a unit of measure? E.g. Number:Power?
… meaning, if I do not have just numbers, there is no need to split these?!

It seems to me that visibility expects true|false, but can also have an expression?!

Given I have no clue about this type of UI config, it looks like there will be a steep learning curve :face_with_spiral_eyes:

  1. Exported power
  2. Imported power

Thanks :slight_smile:

I read a few times through this threat but can’t remember it all.
It was already translated here

What is worse, I grew up in Germany and don’t get the language anymore :frowning:

After hours of battling to make this work… here a link with some ideas to avoid the most fundamental problems I encountered, to prevent newbies from mucking about for hours, in order to adopt the widget from post #1.

Thanks a lot for creating this beautiful widget!

If you are interested I share with you my version where I fixed some minor quirks of the original, changed the behaviour a bit and added a bit of extra functionality. All in all its still very close to the original compared to some of the other nice adaptions. As far as I remember these were the changes:

  1. Missing paths between grid and battery and vice versa were added
  2. Props are now English
  3. Grid power is now a single prop like battery power and expects a signed power value instead of two separate values (a negative value means power goes to grid)
  4. Grid and Battery icons are now vertically aligned
  5. 0 W Values are always shown (in white) - this fixes “jumping” icons
  6. Clicking the battery icon now opens the item analyzer
  7. The widget no longer relies on the displayState of items but uses its own style to display values
  8. Simplified some boolean expressions and removed some duplicated code by using more expressions

Bildschirmaufzeichnung vom 19.04.2024, 23_38_02

I’m pretty sure that my adaption is still not 100% bug free and I’m also pretty sure I did not cover all possible edge cases for the energy flow. If you’re using it please let me know if you spot any bugs, thank you!

uid: PV_widget
tags: []
props:
  parameters:
    - context: item
      label: Grid power
      name: gridpower
      required: true
      type: TEXT
    - context: item
      label: Load
      name: load
      required: true
      type: TEXT
    - context: item
      label: Solar power
      name: solarpower
      required: true
      type: TEXT
    - context: item
      label: Battery power
      name: batterypower
      required: true
      type: TEXT
    - context: item
      label: Battery level
      name: batterylevel
      required: true
      type: TEXT
  parameterGroups: []
timestamp: Apr 20, 2024, 9:45:36 PM
component: f7-card
config:
  class:
    - display-flex
    - flex-direction-column
    - align-items-center
  style:
    height: 383px
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
                      width: 110px
                  slots:
                    default:
                      - component: oh-icon
                        config:
                          height: 110px
                          icon: sma_grid_2
                      - component: Label
                        config:
                          style:
                            color: '=items[props.gridpower].state.split(" ")[0] > 0 ? "red" : items[props.gridpower].state.split(" ")[0] == 0 ? "white" : "green"'
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            width: 100px
                          text: =Math.abs(items[props.gridpower].state.split(" ")[0]) + ' ᵂ'
          - 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: 25px
                            font-weight: bold
                            text-align: center
                            width: 100px
                          text: =items[props.solarpower].state.split(" ")[0] + ' ᵂ'
                      - component: oh-icon
                        config:
                          height: 110px
                          icon: sma_pv_2
                          style:
                            margin-top: -20px
                - 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: 100px
                            width: 100px
                          tag: svg
                          viewBox: 0 0 100 100
                          xmlns: http://www.w3.org/2000/svg
                        slots:
                          default:
                            - component: f7-row
                              config:
                                d: M60 -10 v10 c0 40  10 35  30  35  h20
                                fill: none
                                id: topright
                                stroke: rgba(100, 150, 200, 0.8)
                                stroke-width: 2
                                tag: path
                                vector-effect: non-scaling-stroke
                                visible: =items[props.batterypower].state.split(" ")[0] < 0 && items[props.solarpower].state.split(" ")[0] > 0
                            - 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.batterypower].state.split(" ")[0] < 0 && items[props.solarpower].state.split(" ")[0] > 0
                              slots:
                                default:
                                  - component: f7-row
                                    config:
                                      calcMode: linear
                                      dur: 4s
                                      repeatCount: indefinite
                                      tag: animateMotion
                                    slots:
                                      default:
                                        - component: f7-row
                                          config:
                                            tag: mpath
                                            xlink:href: "#topright"
                            - component: f7-row
                              config:
                                d: M40 -10 v10 c0 40 -10 35 -30 35 h-20
                                fill: none
                                id: topleft
                                stroke: rgba(100, 150, 200, 0.8)
                                stroke-width: 2
                                tag: path
                                vector-effect: non-scaling-stroke
                                visible: =items[props.solarpower].state.split(" ")[0] > 0 && items[props.gridpower].state.split(" ")[0] < 0
                            - component: f7-row
                              config:
                                fill: rgba(100, 150, 200, 0.8)
                                r: 6
                                strokeWidth: 10
                                tag: circle
                                vectorEffect: non-scaling-stroke
                                visible: =items[props.solarpower].state.split(" ")[0] > 0 && items[props.gridpower].state.split(" ")[0] < 0
                              slots:
                                default:
                                  - component: f7-row
                                    config:
                                      calcMode: linear
                                      dur: 4s
                                      repeatCount: indefinite
                                      tag: animateMotion
                                    slots:
                                      default:
                                        - component: f7-row
                                          config:
                                            tag: mpath
                                            xlink:href: "#topleft"
                            - component: f7-row
                              config:
                                d: M50, 0 v100
                                fill: none
                                id: vertical
                                stroke: rgba(100, 150, 200, 0.8)
                                stroke-width: 2
                                tag: path
                                vector-effect: non-scaling-stroke
                                visible: =items[props.solarpower].state.split(" ")[0] > 0
                            - component: f7-row
                              config:
                                fill: rgba(100, 150, 200, 0.8)
                                r: 6
                                strokeWidth: 10
                                tag: circle
                                vectorEffect: non-scaling-stroke
                                visible: =items[props.solarpower].state.split(" ")[0] > 0
                              slots:
                                default:
                                  - component: f7-row
                                    config:
                                      calcMode: linear
                                      dur: 4s
                                      repeatCount: indefinite
                                      tag: animateMotion
                                    slots:
                                      default:
                                        - component: f7-row
                                          config:
                                            tag: mpath
                                            xlink:href: "#vertical"
                            - component: f7-row
                              config:
                                d: M-5 55 l10 0 c40 0 35 10 35 50 l0 20
                                fill: none
                                id: botleft
                                stroke: rgba(100, 150, 200, 0.8)
                                stroke-width: 2
                                tag: path
                                vector-effect: non-scaling-stroke
                                visible: =items[props.gridpower].state.split(" ")[0] > 0
                            - component: f7-row
                              config:
                                fill: rgba(100, 150, 200, 0.8)
                                r: 6
                                strokeWidth: 10
                                tag: circle
                                vectorEffect: non-scaling-stroke
                                visible: =items[props.gridpower].state.split(" ")[0] > 0
                              slots:
                                default:
                                  - component: f7-row
                                    config:
                                      calcMode: linear
                                      dur: 4s
                                      repeatCount: indefinite
                                      tag: animateMotion
                                    slots:
                                      default:
                                        - component: f7-row
                                          config:
                                            tag: mpath
                                            xlink:href: "#botleft"
                            - component: f7-row
                              config:
                                d: '=items[props.gridpower].state.split(" ")[0] > 0 ? "M0, 45 h100" : "M100, 45 h-100"'
                                fill: none
                                id: horizontal
                                stroke: rgba(100, 150, 200, 0.8)
                                stroke-width: 2
                                tag: path
                                vector-effect: non-scaling-stroke
                                visible: =(items[props.gridpower].state.split(" ")[0] > 0 && items[props.solarpower].state.split(" ")[0] < Math.abs(Math.min(0, items[props.batterypower].state.split(" ")[0]))) || (items[props.batterypower].state.split(" ")[0] > 0 && items[props.gridpower].state.split(" ")[0] < 0 && items[props.solarpower].state.split(" ")[0] <= 0)
                            - component: f7-row
                              config:
                                fill: rgba(100, 150, 200, 0.8)
                                r: 6
                                strokeWidth: 10
                                tag: circle
                                vectorEffect: non-scaling-stroke
                                visible: =(items[props.gridpower].state.split(" ")[0] > 0 && items[props.solarpower].state.split(" ")[0] < Math.abs(Math.min(0, items[props.batterypower].state.split(" ")[0]))) || (items[props.batterypower].state.split(" ")[0] > 0 && items[props.gridpower].state.split(" ")[0] < 0 && items[props.solarpower].state.split(" ")[0] <= 0)
                              slots:
                                default:
                                  - component: f7-row
                                    config:
                                      calcMode: linear
                                      dur: 4s
                                      repeatCount: indefinite
                                      tag: animateMotion
                                    slots:
                                      default:
                                        - component: f7-row
                                          config:
                                            tag: mpath
                                            xlink:href: "#horizontal"
                            - component: f7-row
                              config:
                                d: M 105 55 l-10 0 c-40 0 -35 10 -35 50 l0 20
                                fill: none
                                id: botright
                                stroke: rgba(100, 150, 200, 0.8)
                                stroke-width: 2
                                tag: path
                                vector-effect: non-scaling-stroke
                                visible: =items[props.batterypower].state.split(" ")[0] > 0
                            - component: f7-row
                              config:
                                fill: rgba(100, 150, 200, 0.8)
                                r: 6
                                strokeWidth: 10
                                tag: circle
                                vectorEffect: non-scaling-stroke
                                visible: =items[props.batterypower].state.split(" ")[0] > 0
                              slots:
                                default:
                                  - component: f7-row
                                    config:
                                      calcMode: linear
                                      dur: 4s
                                      repeatCount: indefinite
                                      tag: animateMotion
                                    slots:
                                      default:
                                        - component: f7-row
                                          config:
                                            tag: mpath
                                            xlink:href: "#botright"
                - 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: 110px
                          icon: sma_consumption_2
                      - component: Label
                        config:
                          style:
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            width: 100px
                          text: =items[props.load].state.split(" ")[0] + ' ᵂ'
          - 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
                      width: 110px
                  slots:
                    default:
                      - component: oh-link
                        config:
                          action: analyzer
                          actionAnalyzerCoordSystem: time
                          actionAnalyzerItems: =[props.batterylevel]
                          iconColor: '=items[props.batterylevel].state.split(" ")[0] < 75 ? items[props.batterylevel].state.split(" ")[0] < 10 ? "red" : "orange" : "green"'
                          iconF7: '=items[props.batterylevel].state.split(" ")[0] < 75 ? items[props.batterylevel].state.split(" ")[0] < 10 ? "battery_0" : "battery_25" : "battery_100"'
                          iconSize: 33px
                          style:
                            font-size: 25px
                            font-weight: bold
                            position: absolute
                            top: -25px
                            white-space: nowrap
                          text: =items[props.batterylevel].state.split(" ")[0] + '%'
                      - component: oh-icon
                        config:
                          height: 110px
                          icon: sma_battery_2
                      - component: Label
                        config:
                          style:
                            color: '=items[props.batterypower].state.split(" ")[0] > 0 ? "red" : items[props.batterypower].state.split(" ")[0] == 0 ? "white" : "green"'
                            font-size: 25px
                            font-weight: bold
                            margin-top: -10px
                            text-align: center
                            white-space: nowrap
                            width: 100px
                          text: =Math.abs(items[props.batterypower].state.split(" ")[0]) + ' ᵂ'
1 Like