Solar Plant with Battery Widget

Based on inspirations here in the community. I created a widget for a PV solar plant with battery.

Changelog

Version 0.3

  • Introduced text: =items[props.item_grid].displayState || items[props.item_grid].state as suggested by DiegoDf (Thx!).

Version 0.2

  • removed default value for threshold to allow import via marketplace

Version 0.1

  • initial release

Resources

uid: solar_plant_state
tags:
  - cell
  - solar
props:
  parameters:
    - description: Name of the solar plant
      label: Name
      name: prop_name
      required: false
      type: TEXT
    - context: item
      description: Item holding the current grid power (+ = green; - = red)
      label: Grid Power
      name: item_grid
      required: false
      type: TEXT
    - context: item
      description: Item holding the current house power Consumption
      label: House Power
      name: item_house
      required: false
      type: TEXT
    - context: item
      description: Item holding the current solar power
      label: Solar Power
      name: item_solar
      required: false
      type: TEXT
    - context: item
      description: Item holding the current battery power (+ = green; - = red)
      label: Battery Power
      name: item_bat
      required: false
      type: TEXT
    - context: item
      description: Item holding the battery level
      label: Battery Level
      name: item_soc
      required: false
      type: TEXT
    - description: Treshold for Pause
      label: Treshold
      name: prop_tres
      required: true
      type: INTEGER
  parameterGroups:
    - name: action1
      context: action
      label: Action, when items clicked
component: f7-card
config:
  title: =props.prop_name
slots:
  default:
    - component: f7-row
      slots:
        default:
          - component: f7-col
            slots:
              default:
                - component: oh-button
                  config:
                    actionPropsParameterGroup: action1
                    class:
                      - display-flex
                      - justify-content-center
                    color: "=(themeOptions.dark === 'light') ? 'black' : 'white'"
                    style:
                      font-size: 16px
                      font-weight: bold
                    text: =items[props.item_grid].displayState  || items[props.item_grid].state
                - component: f7-row
                  slots:
                    default:
                      - component: f7-col
                        config:
                          class:
                            - display-flex
                            - justify-content-center
                        slots:
                          default:
                            - component: f7-icon
                              config:
                                f7: power
                                size: 40
                      - component: f7-col
                        config:
                          class:
                            - display-flex
                            - justify-content-center
                        slots:
                          default:
                            - component: f7-icon
                              config:
                                color: "=(Number.parseInt(items[props.item_grid].state) > props.prop_tres) ? 'dark_red' : (Number.parseInt(items[props.item_grid].state) < -1 * props.prop_tres) ? 'green' : (themeOptions.dark === 'light') ? 'black' : 'white'"
                                f7: "=(Number.parseInt(items[props.item_grid].state) > props.prop_tres) ? 'arrow_right_circle' : (Number.parseInt(items[props.item_grid].state) < -1 * props.prop_tres) ? 'arrow_left_circle' : 'pause_circle'"
                                size: 40
          - component: f7-col
            config:
              class:
                - display-flex
                - flex-direction-column
            slots:
              default:
                - component: oh-button
                  config:
                    actionPropsParameterGroup: action1
                    class:
                      - display-flex
                      - justify-content-center
                    color: "=themeOptions.dark === 'light' ? 'black' : 'white'"
                    style:
                      font-size: 16px
                      font-weight: bold
                    text: =items[props.item_house].displayState || items[props.item_house].state
                - component: f7-icon
                  config:
                    class:
                      - align-self-center
                    f7: house_alt
                    size: 60
                - component: f7-icon
                  config:
                    class:
                      - align-self-center
                    color: "=(Number.parseInt(items[props.item_bat].state) > props.prop_tres) ? 'dark_red' : (Number.parseInt(items[props.item_bat].state) < -1 * props.prop_tres) ? 'green' : (themeOptions.dark === 'light') ? 'black' : 'white'"
                    f7: "=(Number.parseInt(items[props.item_bat].state) > props.prop_tres) ? 'arrow_up_circle' : (Number.parseInt(items[props.item_bat].state) < -1 * props.prop_tres) ? 'arrow_down_circle' : 'pause_circle'"
                    size: 40
                - component: oh-icon
                  config:
                    class:
                      - display-flex
                      - justify-content-center
                    icon: battery
                    state: =items[props.item_soc].state
                    style:
                      height: 60px
                - component: oh-button
                  config:
                    actionPropsParameterGroup: action1
                    class:
                      - display-flex
                      - justify-content-center
                    color: "=themeOptions.dark === 'light' ? 'black' : 'white'"
                    style:
                      font-size: 16px
                      font-weight: bold
                    text: =items[props.item_bat].displayState || items[props.item_bat].state
          - component: f7-col
            slots:
              default:
                - component: oh-button
                  config:
                    actionPropsParameterGroup: action1
                    class:
                      - display-flex
                      - justify-content-center
                    color: "=themeOptions.dark === 'light' ? 'black' : 'white'"
                    style:
                      font-size: 16px
                      font-weight: bold
                    text: =items[props.item_solar].displayState || items[props.item_solar].state
                - component: f7-row
                  slots:
                    default:
                      - component: f7-col
                        config:
                          class:
                            - display-flex
                            - justify-content-center
                        slots:
                          default:
                            - component: f7-icon
                              config:
                                color: "=(Number.parseInt(items[props.item_solar].state) > props.prop_tres) ? 'green' : (themeOptions.dark === 'light') ? 'black' : 'white'"
                                f7: "=(Number.parseInt(items[props.item_solar].state) > props.prop_tres) ? 'arrow_left_circle' : 'pause_circle'"
                                size: 40
                      - component: f7-col
                        config:
                          class:
                            - display-flex
                            - justify-content-center
                        slots:
                          default:
                            - component: f7-icon
                              config:
                                f7: sun_max
                                size: 40

4 Likes

Hello,

Unfortunately the widget can no longer be installed under Openhab 3.3 M1. It always runs against an error.

Could you please show the error


On the UI, this error comes after I click on ADD.

Installation of add-on 130502 failed

/var/log/openhab/openhab.log

2022-02-04 18:04:15.026 [ERROR] [munity.CommunityUIWidgetAddonHandler] - Widget from marketplace is invalid: Unable to parse YAML
2022-02-04 18:04:36.160 [ERROR] [munity.CommunityUIWidgetAddonHandler] - Unable to parse YAML: Unrecognized field “default” (class org.openhab.core.config.core.dto.ConfigDescriptionParameterDTO), not marked as ignorable (22 known properties: “readOnly”, “max”, “limitToOptions”, “groupName”, “name”, “stepsize”, “context”, “defaultValue”, “min”, “label”, “filterCriteria”, “verify”, “type”, “description”, “options”, “required”, “advanced”, “unit”, “multipleLimit”, “pattern”, “multiple”, “unitLabel”])
at [Source: (StringReader); line: 40, column: 20] (through reference chain: org.openhab.core.ui.components.RootUIComponent[“props”]->org.openhab.core.config.core.dto.ConfigDescriptionDTO[“parameters”]->java.util.ArrayList[6]->org.openhab.core.config.core.dto.ConfigDescriptionParameterDTO[“default”])

There is the issue, happend to one of my widgets as well.
Needs to be renamed to „defaultValue“.
@Hoecki Could you please change your widget.

When I try to change it in my Openhab 3.2 Installation, it changes automatically back in the yaml-Editor to “default”.
It think its best not to change it here yet, b/c it may break the functionality for 3.2 - Users. I’m not able to test with Milestone-Builds.
@Christian_Thiele I suggest to manually copy the yaml-code to your installation and change line 42 as suggested by hmerk until release of 3.3.

It is not connected to the Milestone build, changes in core happened early 2021

@ysc Is there an UI issue, as you said earlier it is a leftover.

it’s been changed from defaultValue to default in

however it applies only to (de)serialization to/from JSON, I just realized the YAML deserializer (also in core, to import the marketplace entry) might not be aware of that mapping.

I removed the “critical” parameter. It’s not necessary, just comfort. Please try again.

1 Like

For me, the numeric values were not displayed. The reason was, that for my file based items there was no displayState. In this discussion it appears that there is not always a displayState available for each item.

The solution is simple. The line:

text: =items[props.item_grid].displayState

should be replaced by:

text: =items[props.item_grid].displayState  || items[props.item_grid].state

The other lines with numeric values should be modified too.

You can test your items with the “Widgets Expression Tester”:
Expression_tester

Expression_tester2

2 Likes

The widget is working fine now. I.e. the Installtion went without problems and also the values are displayed. Only the arrows (red/green) are not displayed. Here are only pause characters to see.

Bildschirmfoto vom 2022-02-07 15-26-47

You need to set a threshold value, e.g. 50.

Thanks for the answer. Works. I have one more request. I have from the MPPT two values for the battery. Once for charging (so solar to battery) and once discharging (from battery to house).
Could you include another item here? So charging power and discharging power?

I suggest to use a proxy item, which is calculated from the two MPPT-items by a rule.
Result has to be negative for discharging and positive for charging.
I think it’s just the sum of the two with the correct prefix.
That’s the easiest solution. In the widget it would be some effort to handle prefix and the two different conditions (1 vs. 2 items).

Hi is there a way to add a second battery and an car? so that i have all the informations in this overview?

Thanks for the widget. I like the simplicity a lot. I modified it to some degree for my setup.

solar_plant

Code:

uid: Solar_Plant_Widget
tags: []
props:
  parameters:
    - context: item
      label: Netzleistung
      name: grid_power
      required: true
      type: TEXT
    - context: item
      label: Gesamtverbrauch
      name: load_power
      required: true
      type: TEXT
    - context: item
      label: PV Leistung
      name: solar_power
      required: true
      type: TEXT
    - context: item
      label: Batterieleistung
      name: battery_power
      required: true
      type: TEXT
    - context: item
      label: Batterie Ladezustand
      name: battery_soc
      required: true
      type: TEXT
    - description: Minimale Leistung
      label: Minimale Leistung
      name: min_power
      required: true
      type: INTEGER
    - context: item
      label: Autarkie
      name: autonomy
      required: true
      type: TEXT
    - context: item
      label: Eigenverbrauch
      name: self_consumption
      required: true
      type: TEXT
  parameterGroups:
    - name: action1
      context: action
      label: Action, when items clicked
timestamp: Jan 5, 2024, 6:38:14 AM
component: f7-card
config:
  class:
    - display-flex
    - flex-direction-column
    - align-items-center
  style:
    border-radius: var(--f7-card-expandable-border-radius)
    box-shadow: 5px 5px 10px 1px rgba(0,0,0,0.1)
    margin-left: 5px
    margin-right: 5px
    noShadow: false
    padding: 0px
    height: 210px
slots:
  content:
    - component: f7-block
      config:
        style:
          align-items: center
          justify-content: center
          margin-top: -10px
          width: 350px
      slots:
        default:
          - component: f7-row
            config:
              style:
                align-items: center
            slots:
              default:
                - component: f7-col
                - component: f7-col
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - justify-content-center
                      - flex-direction-column
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          class:
                            - align-self-center
                          f7: sun_max_fill
                          size: 60
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - justify-content-center
                      - flex-direction-column
                  slots:
                    default:
                      - component: oh-button
                        config:
                          class:
                            - display-flex
                            - justify-content-center
                            - align-self-center
                          color: "=themeOptions.dark === 'light' ? 'black' : 'white'"
                          style:
                            font-size: 16px
                          text: =@props.solar_power
                - component: f7-col
          - component: f7-row
            config:
              style:
                align-items: center
            slots:
              default:
                - component: f7-col
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - justify-content-center
                      - flex-direction-column
                  slots:
                    default:
                      - component: oh-button
                        config:
                          class:
                            - display-flex
                            - justify-content-center
                            - align-self-center
                          color: "=themeOptions.dark === 'light' ? 'black' : 'white'"
                          style:
                            font-size: 16px
                          text: =@props.autonomy
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - justify-content-center
                      - flex-direction-column
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          class:
                            - align-self-center
                          color: "=(Number.parseInt(@props.solar_power) > props.min_power) ? 'green' : (themeOptions.dark === 'light') ? 'black' : 'white'"
                          f7: "=(Number.parseInt(@props.solar_power) > props.min_power) ? 'arrow_down_circle' : 'pause_circle'"
                          size: 40
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - justify-content-center
                      - flex-direction-column
                  slots:
                    default:
                      - component: oh-button
                        config:
                          class:
                            - display-flex
                            - justify-content-center
                            - align-self-center
                          color: "=themeOptions.dark === 'light' ? 'black' : 'white'"
                          style:
                            font-size: 16px
                          text: =@props.self_consumption
                - component: f7-col
          - component: f7-row
            config:
              style:
                align-items: center
            slots:
              default:
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - justify-content-center
                      - flex-direction-column
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          class:
                            - align-self-center
                          f7: bolt_circle
                          size: 60
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - justify-content-center
                      - flex-direction-column
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          class:
                            - align-self-center
                          color: "=(Number.parseInt(@props.grid_power) > props.min_power) ? 'red' : (Number.parseInt(@props.grid_power) < -props.min_power) ? 'green' : (themeOptions.dark === 'light') ? 'black' : 'white'"
                          f7: "=(Number.parseInt(@props.grid_power) > props.min_power) ? 'arrow_right_circle' : (Number.parseInt(@props.grid_power) < -props.min_power) ? 'arrow_left_circle' : 'pause_circle'"
                          size: 40
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - justify-content-center
                      - flex-direction-column
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          class:
                            - align-self-center
                          f7: house
                          size: 60
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - justify-content-center
                      - flex-direction-column
                  slots:
                    default:
                      - component: f7-icon
                        config:
                          class:
                            - align-self-center
                          color: "=(Number.parseInt(@props.battery_power) > props.min_power) ? 'red' : (Number.parseInt(@props.battery_power) < -props.min_power) ? 'green' : (themeOptions.dark === 'light') ? 'black' : 'white'"
                          f7: "=(Number.parseInt(@props.battery_power) > props.min_power) ? 'arrow_left_circle' : (Number.parseInt(@props.battery_power) < -props.min_power) ? 'arrow_right_circle' : 'pause_circle'"
                          size: 40
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - justify-content-center
                      - flex-direction-column
                  slots:
                    default:
                      - component: oh-button
                        config:
                          actionPropsParameterGroup: action1
                          class:
                            - display-flex
                            - justify-content-center
                            - align-items-center
                          color: "=Number.parseFloat(@props.battery_soc) < 20 ? 'red' : (Number.parseFloat(@props.battery_soc) < 60 ? 'orange' : 'green')"
                          style:
                            font-size: 16px
                          text: =@props.battery_soc
                      - component: oh-icon
                        config:
                          class:
                            - display-flex
                            - justify-content-center
                            - align-items-center
                          icon: battery
                          state: =Number.parseFloat(@props.battery_soc)
                          style:
                            margin-top: -15px
                            height: 50px
          - component: f7-row
            config:
              style:
                align-items: center
            slots:
              default:
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - justify-content-center
                      - flex-direction-column
                  slots:
                    default:
                      - component: oh-button
                        config:
                          actionPropsParameterGroup: action1
                          class:
                            - display-flex
                            - justify-content-center - align-self-center
                          color: "=Number.parseFloat(@props.grid_power) < 0 ? 'green' : Number.parseFloat(@props.grid_power) > 0 ? 'red' : themeOptions.dark === 'light' ? 'black' : 'white'"
                          style:
                            font-size: 16px
                          text: =Math.abs(Number.parseInt(@props.grid_power)) + ' W'
                - component: f7-col
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - justify-content-center
                      - flex-direction-column
                  slots:
                    default:
                      - component: oh-button
                        config:
                          actionPropsParameterGroup: action1
                          class:
                            - display-flex
                            - justify-content-center
                            - align-self-center
                          color: "=themeOptions.dark === 'light' ? 'black' : 'white'"
                          style:
                            font-size: 16px
                          text: =Math.abs(Number.parseInt(@props.load_power)) + ' W'
                - component: f7-col
                - component: f7-col
                  config:
                    class:
                      - display-flex
                      - justify-content-center
                      - flex-direction-column
                  slots:
                    default:
                      - component: oh-button
                        config:
                          actionPropsParameterGroup: action1
                          class:
                            - display-flex
                            - justify-content-center
                            - align-self-center
                          color: "=Number.parseFloat(@props.battery_power) < 0 ? 'green' : Number.parseFloat(@props.battery_power) > 0 ? 'red' : themeOptions.dark === 'light' ? 'black' : 'white'"
                          style:
                            font-size: 16px
                          text: =Math.abs(Number.parseInt(@props.battery_power)) + ' W'