IDM heatpump integration via modbus (pure HA)

IDM Heatpump Modbus integration
I like to share my integration of the IDM AERO 12 Heatpump. The concepts shared here, should also work with other IDM heatpumps.

General thoughts

A lot of terms used here are in German, hope this is OK, as long as I expect that IDM-Heatpumps are mainly sold in Austria, Switzerland and Germany.

Warranty
This is a hobby project, so there is no gurantee, support or warranty at all. You are responsible if you use parts of this project.

Prepare IDM Heatpump to eanble Modbus
You need to enter the IDM settings and switch to “Fachmann Ebene” by entering the expert code (first level is OK, if you don’t know the code, look in the internet or ask your supplier).
Go to ‘Gebäudeleittechnik’, enter the setting ‘Modbus TCP’ and enable it.
2024-03-09 13_33_38-Navigator Pro

If you can’t manage this, consider to not continue with this project or ask the IDM-Support, I had really good experiences.
There is also a page ‘GLT Monitor’ to see all the available numbers and monitor/debug the values. See also these documents:

Important Note:
Make sure to not write too often if the settings via modbus as some of them are stored in EEPROM, see on page 12 modbus description!

Homeassistant
Let’s assume that you have HA already running and you have some experiences with it.
I use Visual Studio code to connect to my HA config via SSH (not described here).
I personally don’t like to put all stuff into ‘configuration.yaml’, I also don’t like to spread a project over multiple files like ‘automation.yaml’. Fortunately there is a solution to properly seperate your projects: packages.
I created a subfolder “packages” and placed my projects there. You can have the same items as in configuration.yaml in each subfile, this does a perfect job to separate the different projects. You can simply switch them on/off by just comenting one line.
Packages
This should also work with your current setup, to not mix up this new code with you existing one.

Integration
This integration uses only the standard HA configurations and integrations, there is no need to use HACS or sourcecode - just configurations, using standard HA components.

Modbus
This integration uses modbus to communicate with the IDM heatpump.
Unfortunately the IDM modbus interface uses a different Endian-Format (Big-Endian, Little-Endian). So you need to provide the option swap: word when reading float values.
When writing back such float values, you need to convert the float value by swapping the bytes again. This look ugly (see in automation definitions), but works good. If someone knows a better method, please let me know.
! Make sure to use your IP-address of your IDM device (see modbus: configuration) !

Integration

PV integration
This project needs to know the current surplus PV power. So this package needs some kind of external sensors. In my setup my converter is a solaredge system, so you might need to adapt/rename these sensors (see my configuration below).

Features
All the features described here are working great for me and my setup, you might have other ideas/preferences, so just disable or modify these parts. Only use all the features if you really understand how they work.
I’m not a heating expert, I did not found more documentation on how the heating works, so these assumptions mentioned here might be incomplete/incorrect.
The overall idea is to have a better overview on what the heatpump is doing and better understand how it works. Whenever there is enough PV power I want to use this to store energy in my buffer (850 l).
Typically the heatpump runs if there is need to do so. This means if the warm-water is below 48° (depending on the settings in IDM heatpump) it starts preparing water till appr. 53°. And if the heating is on, it will start if the heating water is no more sufficient to provide the needed temperature (Vorlauf). This is working without any integration - this is what the heatpump does itself.
If you want to ‘store’ the remaining PV power, we need to tell the heatpump to prepare warm water (more than currently needed) and store it for later use. Fortunately there is a parameter that IDM designed for that: 74. In short: if you signal that there is remaining power, the heating will use it.
In detail: the IDM will only start if there is enough energy. For my device this is about 2.1 to 2.8 kW, see the page ‘Photovoltaik/PV Leistung’ Value ‘Leistung Vorrang’. This value depends on several parameters (not sure) but for sure on the current temperature outside - 2.1 in summer, 2.8 in winter. Typically the heating starts using PV if the provided value is 500W higher than what is expected (to be sure there is enough energy). Then it will run at least 10 minutes - no matter if there is enough energy or not. It will also not start again prior a 10 minutes delay to have not too much toggles (bad for lifetime).

Happy Path:
The happy (naive) path is just provide the PV power and the heatpump uses it. It does adjust the used power, so the more you provide the more it uses - for my model 1.5-4 KW. If the water is warm enough, see settings on page ‘Photovoltaik’ (please discuss these values with your supplier/expert to not damage the device), the heatpump will stop. It will also stop ‘most times’ if the power is too low. Sometimes it keeps on running even if there is no more power reported !?
Unhappy Path:
Let’s assume there are 3000W available, the heatpump starts… If you now want to make a coffee, the available power will drop to e.g. 800W - heatpump will probably stop. Even if this is only for 2 minutes, as described above it will not start again for 10 minutes. Wouldn’t it be great if it keeps running? Coffee is just an example for any consumer like oven, washing machine, dryer, dish washer etc…
I have a battery, on rainy days sometimes I have constantly 2000W, Battery is full, but heatpump does not start, because will start when e.g. 2,4 kW + 500W at 2,9kW. But it would be fine to let it run and use the battery that can be relaoded later.
So I introduced a buffer value “Puffer für WP Überschuss”. If this value is 0W you have the happy path, the heatpump will just see what PV is delivering. If it is +1000W, the heatpump will leave a 1000W unused so this can be used for other things. If it is negative, like -2000, the system reports more power than available (might use the battery if available) but will let the hetpump run (or not stop if there is some shadow).
There is also a maximum value ‘Maximal WP Überschuss’ that limit the power usable by heatpump. The remaining power reported will include also the power the heatpump really uses, so even if providing ‘artificial’ values, the heatpump sees a response if it changes the used power.

I know, quite complex, let’s look at some examples (I add a 700W if HP is off to make it start):

| Use case                  | PV Power | Buffer | Max  | HP Usage | PV to HP|
-----------------------------------------------------------------------------
| HP is off (+700 to start) | 2800     |      0 | 5000 |        0 |    3500 |
| HP starts                 | 2800     |      0 | 5000 |     1100 |    1700 |
| HP is running             | 2800     |      0 | 5000 |     2300 |     500 |
| high PV                   | 5500     |      0 | 5000 |     2300 |    2700 |
| dawning                   | 2350     |      0 | 5000 |     2300 |      50 |
| WP adjust usage           | 2300     |      0 | 5000 |     2150 |     150 |
| dawning                   | 2000     |      0 | 5000 |     2050 |       0 |
| WP stops                  | 1800     |      0 | 5000 |        0 |    2500 |

| high PV limited           | 5000     |      0 | 3000 |     2800 |     200 |
| high PV positive buffer   | 5000     |   2100 | 3000 |     2800 |     100 |

| Force run                 | 2000     |  -4000 | 3000 |        0 |    3700 |
| HP is running             | 2000     |  -4000 | 3000 |     2200 |     800 |
| Coffee 3100W              | -1100    |  -4000 | 3000 |     2200 |     700 |

| simple case HP is running | 2800     |      0 |    0 |     2300 |     500 |

Call me crazy, but it works for my needs. To have kind of a normal behaviour, just set buffer to 0 and max to 4000. Then you will have the plain PV control as designed by IDM.
To make it even worse you can use a dummy value ‘Dummy Value 2 Überschuss’ (this is not tied to real PV power at all), they are used if the switch ‘Übertrage reale PV Werte zu WP’ is off. Typicall set it to 0.

Additional
‘Wärmepumpe ein/aus automatisch’:
shall start the heatpump once a day (after 10am) if the battery is already 70+% loaded, no matter if there is currently enough power. There should be some power, because it was enough to load the battery.
This works perfectly for summer time to avoid having the heatpump starting between 8pm and 8am in the night (without PV). So typically the HP runs around 1pm fills up warm-water to 63° which is enough till the next day :slight_smile: .
This does not really work for winter time when the heating is on :frowning: . However even when heating is needed, it makes sense to let the HP run when it is warmer and high chance of PV.
‘Anforderung Heizen/Warmwasser’ is experimental.

Let’s discuss how to do it better, or which kind of drugs might be helpful for this crazy guy.

======================================================

Code

content of packages\idm.yaml:

input_boolean:
  use_pv_values:
    name: Übertrage reale PV Werte zu WP
    initial: false
  use_prefer_wp_before_battery:
    name: Bevorzuge Wärmepumpe vor Batterie
    initial: true
  wp_on_off_automatically:
    name: Wärmepumpe ein/aus automatisch
    initial: true
  wp_did_run_today:
    name: Wärmepumpe lief heute schon
    initial: true

input_number:
  dummy_value_1:
    name: "Dummy Value 1 Power"
    initial: 0
    min: -10000
    max: 10000
    step: 100
    mode: box
    unit_of_measurement: "W"
    icon: mdi:lightning-bolt
  dummy_value_2:
    name: "Dummy Value 2 Überschuss"
    initial: 0
    min: -10000
    max: 10000
    step: 100
    mode: box
    unit_of_measurement: "W"
    icon: mdi:lightning-bolt
  wp_buffer:
    name: "Puffer für WP Überschuss"
    initial: 0
    min: -10000
    max: 10000
    step: 100
    mode: box
    unit_of_measurement: "W"
    icon: mdi:lightning-bolt
  wp_max_power:
    name: "Maximal WP Überschuss"
    initial: 2700
    min: -10000
    max: 10000
    step: 100
    mode: box
    unit_of_measurement: "W"
    icon: mdi:lightning-bolt
  idm_stopanforderungheizen:
    name: "Stop Anforderung Heizen"
    initial: 60
    min: 25
    max: 65
    step: 1
    mode: slider
    unit_of_measurement: "C"
    icon: mdi:thermometer-alert
  idm_stopanforderungwarmwasser:
    name: "Stop Anforderung Warmwasser"
    initial: 60
    min: 25
    max: 65
    step: 1
    mode: slider
    unit_of_measurement: "C"
    icon: mdi:thermometer-alert

switch:
- platform: template
  switches:
    idm_anforderungheizen:
      unique_id: "idm_anforderungheizen"
      value_template: "{{ is_state('sensor.idm_AnforderungHeizen', '1') }}"
      turn_on:
      - service: modbus.write_register
        data:
          hub: idm_wp
          unit: 1
          address: 1710
          value: 1
      turn_off:
      - service: modbus.write_register
        data:
          hub: idm_wp
          unit: 1
          address: 1710
          value: 0
- platform: template
  switches:
    idm_anforderungwarmwasser:
      unique_id: "idm_anforderungwarmwasser"
      value_template: "{{ is_state('sensor.idm_AnforderungWarmWasser', '1') }}"
      turn_on:
      - service: modbus.write_register
        data:
          hub: idm_wp
          unit: 1
          address: 1712
          value: 1
      turn_off:
      - service: modbus.write_register
        data:
          hub: idm_wp
          unit: 1
          address: 1712
          value: 0


# NEEDS RESTART !!!
modbus:
  - name: "idm_wp"
    type: tcp
    # use your own IP-Address
    host: 192.168.1.54
    port: 502
    delay: 1 # after reconnect
    # deprecated -> retries: 5
    # retry_on_empty: true
    # message_wait_milliseconds: 500
    # timeout: 10
    sensors:
    - name: "idm_gemittelteAussentemperatur"
      unique_id: "idm_gemittelteaussentemperatur"
      slave: 1
      scale: 1
      offset: 0
      unit_of_measurement: °C
      address: 1002
      data_type: float32
      scan_interval: 30
      precision: 1
      swap: word
    - name: "idm_Aussentemperatur"
      unique_id: "idm_aussentemperatur"
      slave: 1
      scale: 1
      offset: 0
      unit_of_measurement: °C
      address: 1000
      data_type: float32
      scan_interval: 30
      precision: 1
      swap: word
    - name: "idm_Leistungsaufnahme"
      unique_id: idm_Leistungsaufnahme
      slave: 1
      scale: 1
      offset: 0
      address: 4122
      data_type: float32
      scan_interval: 5
      precision: 3
      swap: word
      unit_of_measurement: kW
      device_class: power
    - name: "idm_AktuellerPhotovoltaikUeberschuss"
      unique_id: idm_AktuellerPhotovoltaikUeberschuss
      slave: 1
      scale: 1
      offset: 0
      address: 74
      data_type: float32
      scan_interval: 5
      precision: 3
      swap: word
      unit_of_measurement: kW
      device_class: power
    - name: "idm_AktuellePhotovoltaikProduktion"
      unique_id: idm_AktuellePhotovoltaikProduktion
      slave: 1
      scale: 1
      offset: 0
      unit_of_measurement: kW
      address: 78
      data_type: float32
      scan_interval: 30
      precision: 3
      swap: word
    - name: "idm_Vorlauftemperatur"
      unique_id: "idm_vorlauftemperatur"
      slave: 1
      scale: 1
      offset: 0
      unit_of_measurement: °C
      address: 1350
      data_type: float32
      scan_interval: 30
      precision: 1
      swap: word
    - name: "idm_Waermespeichertemperatur"
      unique_id: "idm_waermespeichertemperatur"
      slave: 1
      scale: 1
      offset: 0
      unit_of_measurement: °C
      address: 1008
      data_type: float32
      scan_interval: 30
      precision: 1
      swap: word
    - name: "idm_TrinkwassertemperaturUnten"
      unique_id: "idm_trinkwassertemperaturunten"
      slave: 1
      scale: 1
      offset: 0
      unit_of_measurement: °C
      address: 1012
      data_type: float32
      scan_interval: 30
      precision: 1
      swap: word
    - name: "idm_AnforderungHeizen"
      unique_id: idm_anforderungsheizen
      slave: 1
      address: 1710
      data_type: uint16
      scan_interval: 5
    - name: "idm_AnforderungWarmWasser"
      unique_id: idm_anforderungwarmwasser
      slave: 1
      address: 1712
      data_type: uint16
      scan_interval: 5

automation:
- id: solaredge_to_idm
  alias: SolarEdge to IDM
  description: Update von PV Überschuss
  trigger:
  - platform: state
    entity_id:
    - sensor.pv_uberschuss_fur_wp
    - input_boolean.use_pv_values
    # - sensor.pv_leistung_fur_wp
    from:
  condition:
    # Check if input values are defined
    - condition: template
      value_template: "{{ is_number(states('sensor.pv_uberschuss_fur_wp')) }}"
  action:
  - service: modbus.write_register
    data:
      hub: idm_wp
      unit: 1
      address: 74
      value: '[ {{ unpack(pack(states(''sensor.pv_uberschuss_fur_wp'')|float, ">f"), ">H", offset=2) }}, 
      {{  unpack(pack(states(''sensor.pv_uberschuss_fur_wp'')|float, ">f"), ">H") }} ]'
  # This is not needed, because WP dows not use this value !?
  # - service: modbus.write_register
  #   data:
  #     hub: idm_wp
  #     unit: 1
  #     address: 78
  #     value: >
  #       [ {{ unpack(pack(states("sensor.pv_leistung_fur_wp")|float, ">f"), ">H", offset=2) }}, 
  #         {{ unpack(pack(states("sensor.pv_leistung_fur_wp")|float, ">f"), ">H") }} ]
  mode: queued

### Automatische Wärmepumpensteuerung ###
# setzt das Flag, welches angibt, ob die WP schon lief zurĂźck, d.h. vor 10:00 Uhr soll die WP ohenhin nicht laufen
- id: reset_did_wp_run_totay_automation
  alias: reset did wp run totay
  description: 'Resets the WP did run flag once daily'
  trigger:
  - platform: time
    at: '10:00:00'
  condition: []
  action:
  - service: input_boolean.turn_off
    target:
      entity_id: input_boolean.wp_did_run_today
  mode: queued

# wenn WP mind. 1000W zieht, läuft sie, und das Flag WP ist gelaufen wird schon mal gesetzt
- id: update_did_wp_run_totay_automation
  alias: update did wp run totay
  description: 'Updates the WP did run flag when WP is running'
  trigger:
  - platform: state
    entity_id:
    - sensor.idm_leistungsaufnahme
  condition:
    #alias: "WP did not run today (Flag is off) AND WP is running"
    and:    
      - condition: state
        entity_id: input_boolean.wp_did_run_today
        state: "off"  
      - condition: numeric_state
        entity_id: sensor.idm_leistungsaufnahme
        value_template: "{{ state.state|float * 1000 }}"
        above: 1000
  action:
  - service: input_boolean.turn_on
    target:
      entity_id: input_boolean.wp_did_run_today
  mode: queued

# Wenn WP noch nicht gelaufen, und Speicher mind. 70% voll ist, kann die WP laufen
- id: start_wp_automation
  alias: Start WP
  condition:
    and:
      - condition: state
        entity_id: input_boolean.wp_on_off_automatically
        state: "on"  
      - condition: state
        entity_id: input_boolean.wp_did_run_today
        state: "off"
      - condition: state
        entity_id: input_boolean.use_pv_values
        state: "off"
      - condition: numeric_state
        entity_id: sensor.solaredge_battery1_state_of_charge
        above: 70     
  trigger:
  - platform: state
    entity_id:
    - sensor.solaredge_battery1_state_of_charge
  action:
  - service: input_boolean.turn_on
    target:
      entity_id: input_boolean.use_pv_values
  mode: queued

# 'WP ist gelaufen' ausschalten, wenn start_wp kommt, um nicht gleich wieder auszuschalten
- id: start_wp_auto_switchoff_wp_did_run_today
  condition:
    - condition: template
      value_template: "{{ trigger.from_state.state == 'off' and trigger.to_state.state == 'on' }}"
  trigger:
  - platform: state
    entity_id:
    - input_boolean.use_pv_values
  action:
  - service: input_boolean.turn_off
    target:
      entity_id: input_boolean.wp_did_run_today
  mode: queued

# wenn die WP schon lief und sie fertig ist (nicht mehr läuft), soll sie nicht mehr laufen 
- id: stop_wp_automation
  alias: Stop WP
  condition:
    and:
      - condition: state
        entity_id: input_boolean.wp_on_off_automatically
        state: "on"  
      - condition: state
        entity_id: input_boolean.wp_did_run_today
        state: "on"
      - condition: numeric_state
        entity_id: sensor.idm_leistungsaufnahme
        value_template: "{{ state.state|float(0) * 1000 }}"
        below: 100
  trigger:
  - platform: state
    entity_id:
    - sensor.idm_leistungsaufnahme
    - input_boolean.wp_did_run_today
  action:
  - service: input_boolean.turn_off
    target:
      entity_id: input_boolean.use_pv_values
  mode: queued

# ausschalten der Heizanforderung bei erreichen der Zieltemperatur
- id: stop_wp_heizanforderung
  alias: Stop WP HeizAnforderung
  condition:
    - condition: state
      entity_id: sensor.idm_AnforderungHeizen
      state: "1"  
    - condition: template
      value_template: "{{ states('sensor.idm_Waermespeichertemperatur')|float >= states('input_number.idm_stopanforderungheizen')|float }}"      
  trigger:
  - platform: state
    entity_id:
    - sensor.idm_Waermespeichertemperatur
    - sensor.idm_AnforderungHeizen
  action:
  - service: modbus.write_register
    data:
      hub: idm_wp
      unit: 1
      address: 1710
      value: 0
  mode: queued

# ausschalten der WarmWasserAnforderung bei erreichen der Zieltemperatur
- id: stop_wp_warmwasseranforderung
  alias: Stop WP WarmwasserAnforderung
  condition:
    - condition: state
      entity_id: sensor.idm_AnforderungWarmWasser
      state: "1"  
    - condition: template
      value_template: "{{ states('sensor.idm_trinkwassertemperaturunten')|float >= states('input_number.idm_stopanforderungwarmwasser')|float }}"      
  trigger:
  - platform: state
    entity_id:
    - sensor.idm_trinkwassertemperaturunten
    - sensor.idm_AnforderungWarmWasser
  action:
  - service: modbus.write_register
    data:
      hub: idm_wp
      unit: 1
      address: 1712
      value: 0
  mode: queued

The UI: (see .storage\lovelace.dashboard_warmepumpe)

{
  "version": 1,
  "minor_version": 1,
  "key": "lovelace.dashboard_warmepumpe",
  "data": {
    "config": {
      "views": [
        {
          "title": "Home",
          "cards": [
            {
              "type": "entities",
              "entities": [
                {
                  "entity": "input_number.dummy_value_1"
                },
                {
                  "entity": "input_number.dummy_value_2"
                },
                {
                  "entity": "input_boolean.wp_on_off_automatically"
                },
                {
                  "entity": "input_boolean.wp_did_run_today"
                },
                {
                  "entity": "input_boolean.use_pv_values"
                },
                {
                  "entity": "input_boolean.use_prefer_wp_before_battery"
                },
                {
                  "entity": "sensor.aktuelle_erzeugung"
                },
                {
                  "entity": "sensor.aktueller_verbrauch"
                },
                {
                  "entity": "sensor.aktueller_uberschuss"
                },
                {
                  "entity": "input_number.wp_max_power"
                },
                {
                  "entity": "input_number.wp_buffer"
                },
                {
                  "entity": "sensor.pv_uberschuss_fur_wp"
                },
                {
                  "entity": "sensor.idm_aktuellerphotovoltaikueberschuss"
                },
                {
                  "entity": "sensor.idm_leistungsaufnahme"
                },
                {
                  "entity": "sensor.idm_trinkwassertemperaturunten"
                },
                {
                  "entity": "sensor.idm_waermespeichertemperatur"
                },
                {
                  "entity": "sensor.idm_aussentemperatur"
                },
                {
                  "entity": "switch.idm_anforderungheizen"
                },
                {
                  "entity": "input_number.idm_stopanforderungheizen"
                },
                {
                  "entity": "switch.idm_anforderungwarmwasser"
                },
                {
                  "entity": "input_number.idm_stopanforderungwarmwasser"
                }
              ]
            },
            {
              "type": "grid",
              "cards": [
                {
                  "type": "gauge",
                  "entity": "sensor.aktuelle_erzeugung",
                  "max": 10000,
                  "needle": true,
                  "name": "Erzeugung",
                  "min": 0,
                  "severity": {
                    "green": 5000,
                    "yellow": 2000,
                    "red": 0
                  }
                },
                {
                  "type": "gauge",
                  "entity": "sensor.solaredge_battery1_power",
                  "needle": true,
                  "severity": {
                    "green": 100,
                    "yellow": -100,
                    "red": -5000
                  },
                  "min": -5000,
                  "max": 5000,
                  "name": "Power"
                },
                {
                  "type": "gauge",
                  "entity": "sensor.solaredge_battery1_state_of_charge",
                  "needle": true,
                  "severity": {
                    "green": 70,
                    "yellow": 20,
                    "red": 0
                  },
                  "name": "State of Charge"
                },
                {
                  "type": "gauge",
                  "entity": "sensor.solaredge_m1_ac_power",
                  "name": "Einspeisung",
                  "needle": true,
                  "severity": {
                    "green": 200,
                    "yellow": -200,
                    "red": -8000
                  },
                  "min": -8000,
                  "max": 8000
                },
                {
                  "type": "gauge",
                  "entity": "sensor.aktueller_verbrauch",
                  "name": "Verbrauch",
                  "needle": true,
                  "severity": {
                    "green": 0,
                    "yellow": 300,
                    "red": 1000
                  },
                  "max": 6000
                },
                {
                  "type": "gauge",
                  "entity": "sensor.idm_leistungsaufnahme",
                  "unit": "KW",
                  "name": "Wärmepumpe",
                  "max": 4,
                  "needle": true,
                  "severity": {
                    "green": 0,
                    "yellow": 2,
                    "red": 3
                  },
                  "min": 0
                }
              ]
            },
            {
              "type": "history-graph",
              "entities": [
                {
                  "entity": "sensor.idm_aktuellerphotovoltaikueberschuss"
                },
                {
                  "entity": "sensor.idm_leistungsaufnahme"
                },
                {
                  "entity": "sensor.idm_trinkwassertemperaturunten"
                },
                {
                  "entity": "sensor.idm_waermespeichertemperatur"
                }
              ],
              "hours_to_show": 5,
              "title": "WP FĂźllen"
            },
            {
              "type": "markdown",
              "content": "[WP history](/history?entity_id=sensor.idm_aktuellerphotovoltaikueberschuss%2Csensor.idm_leistungsaufnahme%2Csensor.idm_trinkwassertemperaturunten%2Csensor.idm_waermespeichertemperatur&start_date={{ as_timestamp(now() - timedelta(hours=6)) | timestamp_custom('%Y-%m-%dT%H:%M:%SZ') }})                "
            }
          ]
        },
        {
          "title": "Power",
          "path": "power",
          "icon": "mdi:air-filter",
          "badges": [],
          "cards": []
        },
        {
          "badges": [
            {
              "entity": "sensor.solaredge_ac_power"
            },
            {
              "entity": "sensor.solaredge_battery1_power"
            },
            {
              "entity": "sensor.solaredge_m1_ac_power"
            },
            {
              "entity": "sensor.solaredge_battery1_state_of_charge"
            }
          ],
          "cards": []
        }
      ]
    }
  }
}

Calculation of pv_uberschuss_fur_wp (kW)
This is really specific to my setup, just to give you an idea where/how I calculate this value, this is added here. You probably need to create you own calculation!

template:
  - sensor:
    - name: "aktueller Verbrauch"
      unique_id: "aktueller_verbrauch"
      unit_of_measurement: "W"
      state: >
        {% if states('sensor.solaredge_ac_power')|is_number and
              states('sensor.solaredge_m1_ac_power')|is_number 
        %}
          {{ states('sensor.solaredge_ac_power')|float - states('sensor.solaredge_m1_ac_power')|float }}
        {%- else -%}
          {{ -1.0 }}
        {%- endif %}
      icon: mdi:home-import-outline  
      state_class: measurement
      device_class: power
    - name: "aktuelle Erzeugung"
      unique_id: "aktuelle_erzeugung"
      unit_of_measurement: "W"
      # state: "{{ ( states('sensor.solaredge_ac_power')|float + states('sensor.solaredge_battery1_power')|float ) }}"
      state: >
        {% if states('sensor.solaredge_ac_power')|is_number and
              states('sensor.solaredge_battery1_power')|is_number 
        %}
          {{ ( states('sensor.solaredge_ac_power')|float + states('sensor.solaredge_battery1_power')|float ) }}
        {%- else -%}
          {{ -1.0 }}
        {%- endif %}
      icon: mdi:lightning-bolt  
      state_class: measurement
      device_class: power
    - name: "aktueller Überschuss"
      unique_id: "aktueller_uberschuss"
      unit_of_measurement: "W"
      state: >
        {% if states('sensor.solaredge_m1_ac_power')|is_number and
              states('sensor.solaredge_battery1_power')|is_number 
        %}
          {% if is_state("sensor.solaredge_battery1_status", "Discharging") -%}
            {{ ( states('sensor.solaredge_m1_ac_power')|float  + states('sensor.solaredge_battery1_power')|float ) }}
          {%- else -%}
            {{ states('sensor.solaredge_m1_ac_power') }}
          {%- endif %}
        {%- else -%}
          {{ -1.0 }}
        {%- endif %}
      icon: mdi:lightning-bolt  
      state_class: measurement
      device_class: power
    - name: "PV Leistung fĂźr WP"
      unique_id: "pv_leistung_fur_wp"
      unit_of_measurement: "kW"
      state: >
        {% if is_state("input_boolean.use_pv_values", "on") %}
          {{ ( max(states('sensor.aktuelle_erzeugung')|float - states('input_number.wp_buffer')|float, 0) / 1000 ) }}
        {%- else -%}
          {{ ( states('input_number.dummy_value_1')|float / 1000 ) }}
        {%- endif %}
      icon: mdi:lightning-bolt  
      state_class: measurement
      device_class: power      
    - name: "PV Überschuss für WP"
      unique_id: "pv_uberschuss_fur_wp"
      unit_of_measurement: "kW"
      # ggf. wird während die Batterie geladen wird dennoch die Batterie-Power der WP zur Verfßgung gestellt (abzßglich eines Puffers von 100)       
      # x = available power for WP
      # maxpower = limit power for WP, might include a 700 extra to trigger start
      # aktpower = current power that the WP uses
      # y = the power that we want to give to WP (the current usage is subtracted)
      # z = the power that we can give to WP (respecting the available power)
      state: >
        {% if is_state("input_boolean.use_pv_values", "on") %}
          {% set x = (states('sensor.aktueller_uberschuss')|float(0) - states('input_number.wp_buffer')|float)|float %}
          {% if is_state("input_boolean.use_prefer_wp_before_battery", "on") %}
            {% set batchargepower = states('sensor.solaredge_battery1_power')|float(0) - 100 %}
            {% if batchargepower > 0 %}
              {% set x = x + batchargepower %}
            {% endif %}
          {% endif %}
          {% set x = max(x,0) %}
          {% set maxpower = states('input_number.wp_max_power')|float %}
          {% set aktpower = states('sensor.idm_leistungsaufnahme')|float(0) * 1000 %}
          {% if aktpower <= 0 %}
            {% set maxpower = maxpower + 700 %}
          {% endif %}
          {% set y = maxpower - aktpower %}
          {% set y = max(y,0) %}
          {% set z = min(x, y) %}
          {{ z / 1000 }}
        {% else %}
          {{ ( states('input_number.dummy_value_2')|float / 1000 ) }}
        {% endif %}
      icon: mdi:lightning-bolt  
      state_class: measurement
      device_class: power
4 Likes