Skip to content

Instantly share code, notes, and snippets.

@mathieucarbou
Last active March 30, 2024 19:08
Show Gist options
  • Save mathieucarbou/70539ced8f330be6205a91897ea1c639 to your computer and use it in GitHub Desktop.
Save mathieucarbou/70539ced8f330be6205a91897ea1c639 to your computer and use it in GitHub Desktop.
OpenDTU + Home Assistant

OpenDTU + Home Assistant

Pour se procurer un DTU avec OpenDTU: http://bit.ly/opendtu

Jour:

image

Nuit:

image

Autres:

image

image

HA Config

In global config:

homeassistant:
  packages: !include_dir_named packages

Then put opendtu.yaml files in config/packages folder

view.yaml is the Lovelace card section above

energy.yaml is optional: you can take it. It shows how I compute the home consumed energy and solar consumed energy with a shelly EM. If yo utake it, you can setup some graph like that:

image

template:
# https://www.home-assistant.io/integrations/sensor/
- sensor:
- name: Solar Consumed Power
unique_id: "01e37eed-3045-4eee-a786-1249567fe303"
state_class: measurement
device_class: power
unit_of_measurement: W
availability: "{{ ['sensor.solar_production_power', 'sensor.grid_returned_power']|map('states')|map('is_number')|min }}"
state: "{{ [states.sensor.solar_production_power.state|float - states.sensor.grid_returned_power.state|float, 0] | max }}"
- name: Home Consumed Power
unique_id: BE34D1AD-AB8E-4909-ACE0-BBA7D3877105
state_class: measurement
device_class: power
unit_of_measurement: W
availability: "{{ ['sensor.solar_production_power', 'sensor.grid_power']|map('states')|map('is_number')|min }}"
state: "{{ states.sensor.solar_production_power.state|float + states.sensor.grid_power.state|float }}"
- name: Solar Consumed Energy Daily
unique_id: "01e37eed-3045-4eee-a786-1249567fe305"
state_class: total_increasing
device_class: energy
unit_of_measurement: kWh
availability: "{{ ['sensor.inverters_energy_meter_daily', 'sensor.grid_energy_returned_meter_daily']|map('states')|map('is_number')|min }}"
state: >-
{% set c = states.sensor.solar_consumed_energy_daily.state|float(0) %}
{% set p = states.sensor.inverters_energy_meter_daily.state|float %}
{% set e = states.sensor.grid_energy_returned_meter_daily.state|float %}
{{ [0 if p == 0 or p < c else c, [0, p - e] | max] | max }}
- name: Solar Autoconsumption Level Daily
unique_id: "01e37eed-3045-4eee-a786-1249567fe304"
state_class: measurement
unit_of_measurement: "%"
availability: "{{ ['sensor.grid_energy_returned_meter_daily', 'sensor.inverters_energy_meter_daily']|map('states')|map('is_number')|min and states.sensor.inverters_energy_meter_daily.state|float(0) > 0 }}"
state: "{{ [100, (100 - 100 * states.sensor.grid_energy_returned_meter_daily.state|float / states.sensor.inverters_energy_meter_daily.state|float )] | min }}"
sensor:
# https://www.home-assistant.io/integrations/integration/
- platform: integration
name: Home Consumed Energy
unique_id: E2BA4424-8CA8-4D74-9A2F-F0E5EFF84622
source: sensor.home_consumed_power
unit_prefix: k
mqtt:
# https://www.home-assistant.io/integrations/sensor.mqtt
sensor:
- name: Inverters YieldTotal
unique_id: D6A6659B-EE6A-4C3F-91F4-C0FBD46E8CF5
state_class: total_increasing
device_class: energy
unit_of_measurement: "kWh"
state_topic: "opendtu/ac/yieldtotal"
value_template: "{{ value|float }}"
availability_topic: "opendtu/ac/is_valid"
payload_available: "1"
payload_not_available: "0"
- name: Inverters YieldDay
unique_id: "01e37eed-3045-4eee-a786-1249567fe310"
state_class: total_increasing
device_class: energy
unit_of_measurement: "kWh"
state_topic: "opendtu/ac/yieldday"
value_template: "{{ value|float / 1000.0 }}"
availability_topic: "opendtu/ac/is_valid"
payload_available: "1"
payload_not_available: "0"
- name: Inverters Power
unique_id: "01e37eed-3045-4eee-a786-1249567fe315"
state_class: measurement
device_class: power
unit_of_measurement: W
state_topic: "opendtu/ac/power"
value_template: "{{ value|int }}"
availability_topic: "opendtu/ac/is_valid"
payload_available: "1"
payload_not_available: "0"
- name: Inverters PowerDC
unique_id: "01e37eed-3045-4eee-a786-1249567fe316"
state_class: measurement
device_class: power
unit_of_measurement: W
state_topic: "opendtu/dc/power"
value_template: "{{ value|int }}"
availability_topic: "opendtu/dc/is_valid"
payload_available: "1"
payload_not_available: "0"
template:
# https://www.home-assistant.io/integrations/sensor/
- sensor:
- name: Inverters Energy
unique_id: 6E14EC86-0965-463E-BFBF-6008B61B56AF
state_class: total_increasing
device_class: energy
unit_of_measurement: "kWh"
state: "{{ [states.sensor.inverters_yieldtotal.state|float(0), states.sensor.inverters_energy.state|float(0) ] | max }}"
- name: Inverter 1 Adjusted Irradiation
unique_id: C47E36DF-4FCD-40CA-B3C7-8B186A02A015
state_class: measurement
unit_of_measurement: "%"
availability: "{{ ['sensor.inverter_1_powerdc', 'sensor.inverter_1_temperature']|map('states')|map('is_number')|min }}"
state: "{{ [100, states.sensor.inverter_1_powerdc.state|float / (400 * (110 - states.sensor.inverter_1_temperature.state|float * 0.4) / 100) * 100] | min }}"
- name: Inverter 2 Adjusted Irradiation
unique_id: C0EB72EE-725E-42C0-A25F-677BB3984EFA
state_class: measurement
unit_of_measurement: "%"
availability: "{{ ['sensor.inverter_2_powerdc', 'sensor.inverter_2_temperature']|map('states')|map('is_number')|min }}"
state: "{{ [100, states.sensor.inverter_2_powerdc.state|float / (400 * (110 - states.sensor.inverter_2_temperature.state|float * 0.4) / 100) * 100] | min }}"
- name: Inverter 3 Adjusted Irradiation
unique_id: 8A61D828-4545-48AC-9CEB-80C96CEAC421
state_class: measurement
unit_of_measurement: "%"
availability: "{{ ['sensor.inverter_3_powerdc', 'sensor.inverter_3_temperature']|map('states')|map('is_number')|min }}"
state: "{{ [100, states.sensor.inverter_3_powerdc.state|float / (400 * (110 - states.sensor.inverter_3_temperature.state|float * 0.4) / 100) * 100] | min }}"
- name: Inverter 4 Adjusted Irradiation
unique_id: 5B1EB6CC-1CF4-4EBD-B476-1254951BB8EA
state_class: measurement
unit_of_measurement: "%"
availability: "{{ ['sensor.inverter_4_powerdc', 'sensor.inverter_4_temperature']|map('states')|map('is_number')|min }}"
state: "{{ [100, states.sensor.inverter_4_powerdc.state|float / (400 * (110 - states.sensor.inverter_4_temperature.state|float * 0.4) / 100) * 100] | min }}"
- name: Inverter 5 Adjusted Irradiation
unique_id: 33EBEF2B-F8C0-4E7E-A90B-7C6706F63E1E
state_class: measurement
unit_of_measurement: "%"
availability: "{{ ['sensor.inverter_5_powerdc', 'sensor.inverter_5_temperature']|map('states')|map('is_number')|min }}"
state: "{{ [100, states.sensor.inverter_5_powerdc.state|float / (400 * (110 - states.sensor.inverter_5_temperature.state|float * 0.4) / 100) * 100] | min }}"
- name: Inverter 6 Adjusted Irradiation
unique_id: B9B3BEE3-9958-43F9-80A4-06163F5B0022
state_class: measurement
unit_of_measurement: "%"
availability: "{{ ['sensor.inverter_6_powerdc', 'sensor.inverter_6_temperature']|map('states')|map('is_number')|min }}"
state: "{{ [100, states.sensor.inverter_6_powerdc.state|float / (400 * (110 - states.sensor.inverter_6_temperature.state|float * 0.4) / 100) * 100] | min }}"
# https://www.home-assistant.io/integrations/utility_meter/
utility_meter:
inverters_energy_meter_daily:
name: Inverters Energy Meter Daily
unique_id: 4C4D8D06-C9D2-4408-B21A-1274A6E0F041
source: sensor.inverters_energy
cycle: daily
type: vertical-stack
cards:
- type: conditional
conditions:
- entity: binary_sensor.inverter_1_reachable
state: 'off'
card:
square: false
columns: 2
type: grid
cards:
- type: markdown
content: |-
### 112184727305
Position: #1
- type: markdown
content: Déconnecté
style: |
ha-card {
background-color: darkred;
}
- type: conditional
conditions:
- entity: binary_sensor.inverter_1_reachable
state: 'on'
card:
square: false
columns: 8
type: grid
cards:
- type: markdown
content: >-
### 112184727305
Position: #1
{{as_local(states.sensor.inverter_1_power.last_updated).time()|string|truncate(8,
False, '')}}
- type: gauge
entity: sensor.inverter_1_temperature
unit: °C
min: 0
max: 65
needle: true
name: Température
severity:
green: 0
yellow: 45
red: 55
- type: gauge
entity: sensor.inverter_1_adjusted_irradiation
unit: '%'
min: 0
max: 100
needle: true
name: Irradiation
- type: gauge
entity: sensor.inverter_1_efficiency
unit: '%'
min: 82
max: 97
needle: true
name: Efficacité
severity:
green: 92
yellow: 87
red: 0
- type: gauge
entity: sensor.inverter_1_powerdc
unit: W
min: 0
max: 440
needle: true
name: DC
severity:
green: 100
yellow: 200
red: 300
- type: gauge
entity: sensor.inverter_1_power
unit: W
min: 0
max: 420
needle: true
name: AC
severity:
green: 100
yellow: 200
red: 300
- type: gauge
entity: sensor.inverter_1_voltage
unit: V
min: 210
max: 250
needle: true
name: Tension
severity:
green: 220
yellow: 0
red: 240
- type: markdown
content: >-
| | |
|:------|:--|
| Day: |
{{(states('sensor.inverter_1_yieldday')|float/1000)|round(2)}} kWh |
| Total: | {{states('sensor.inverter_1_yieldtotal')|float|round}}
kWh |
- type: conditional
conditions:
- entity: binary_sensor.inverter_2_reachable
state: 'off'
card:
square: false
columns: 2
type: grid
cards:
- type: markdown
content: |-
### 112184727286
Position: #2
- type: markdown
content: Déconnecté
style: |
ha-card {
background-color: darkred;
}
- type: conditional
conditions:
- entity: binary_sensor.inverter_2_reachable
state: 'on'
card:
square: false
columns: 8
type: grid
cards:
- type: markdown
content: >-
### 112184727286
Position: #2
{{as_local(states.sensor.inverter_2_power.last_updated).time()|string|truncate(8,
False, '')}}
- type: gauge
entity: sensor.inverter_2_temperature
unit: °C
min: 0
max: 65
needle: true
name: Température
severity:
green: 0
yellow: 45
red: 55
- type: gauge
entity: sensor.inverter_2_adjusted_irradiation
unit: '%'
min: 0
max: 100
needle: true
name: Irradiation
- type: gauge
entity: sensor.inverter_2_efficiency
unit: '%'
min: 82
max: 97
needle: true
name: Efficacité
severity:
green: 92
yellow: 87
red: 0
- type: gauge
entity: sensor.inverter_2_powerdc
unit: W
min: 0
max: 440
needle: true
name: DC
severity:
green: 100
yellow: 200
red: 300
- type: gauge
entity: sensor.inverter_2_power
unit: W
min: 0
max: 420
needle: true
name: AC
severity:
green: 100
yellow: 200
red: 300
- type: gauge
entity: sensor.inverter_2_voltage
unit: V
min: 210
max: 250
needle: true
name: Tension
severity:
green: 220
yellow: 0
red: 240
- type: markdown
content: >-
| | |
|:------|:--|
| Day: |
{{(states('sensor.inverter_2_yieldday')|float/1000)|round(2)}} kWh |
| Total: | {{states('sensor.inverter_2_yieldtotal')|float|round}}
kWh |
- type: conditional
conditions:
- entity: binary_sensor.inverter_3_reachable
state: 'off'
card:
square: false
columns: 2
type: grid
cards:
- type: markdown
content: |-
### 112183225593
Position: #3
- type: markdown
content: Déconnecté
style: |
ha-card {
background-color: darkred;
}
- type: conditional
conditions:
- entity: binary_sensor.inverter_3_reachable
state: 'on'
card:
square: false
columns: 8
type: grid
cards:
- type: markdown
content: >-
### 112183225593
Position: #3
{{as_local(states.sensor.inverter_3_power.last_updated).time()|string|truncate(8,
False, '')}}
- type: gauge
entity: sensor.inverter_3_temperature
unit: °C
min: 0
max: 65
needle: true
name: Température
severity:
green: 0
yellow: 45
red: 55
- type: gauge
entity: sensor.inverter_3_adjusted_irradiation
unit: '%'
min: 0
max: 100
needle: true
name: Irradiation
- type: gauge
entity: sensor.inverter_3_efficiency
unit: '%'
min: 82
max: 97
needle: true
name: Efficacité
severity:
green: 92
yellow: 87
red: 0
- type: gauge
entity: sensor.inverter_3_powerdc
unit: W
min: 0
max: 440
needle: true
name: DC
severity:
green: 100
yellow: 200
red: 300
- type: gauge
entity: sensor.inverter_3_power
unit: W
min: 0
max: 420
needle: true
name: AC
severity:
green: 100
yellow: 200
red: 300
- type: gauge
entity: sensor.inverter_3_voltage
unit: V
min: 210
max: 250
needle: true
name: Tension
severity:
green: 220
yellow: 0
red: 240
- type: markdown
content: >-
| | |
|:------|:--|
| Day: |
{{(states('sensor.inverter_3_yieldday')|float/1000)|round(2)}} kWh |
| Total: | {{states('sensor.inverter_3_yieldtotal')|float|round}}
kWh |
- type: conditional
conditions:
- entity: binary_sensor.inverter_4_reachable
state: 'off'
card:
square: false
columns: 2
type: grid
cards:
- type: markdown
content: |-
### 112183226560
Position: #4
- type: markdown
content: Déconnecté
style: |
ha-card {
background-color: darkred;
}
- type: conditional
conditions:
- entity: binary_sensor.inverter_4_reachable
state: 'on'
card:
square: false
columns: 8
type: grid
cards:
- type: markdown
content: >-
### 112183226560
Position: #4
{{as_local(states.sensor.inverter_4_power.last_updated).time()|string|truncate(8,
False, '')}}
- type: gauge
entity: sensor.inverter_4_temperature
unit: °C
min: 0
max: 65
needle: true
name: Température
severity:
green: 0
yellow: 45
red: 55
- type: gauge
entity: sensor.inverter_4_adjusted_irradiation
unit: '%'
min: 0
max: 100
needle: true
name: Irradiation
- type: gauge
entity: sensor.inverter_4_efficiency
unit: '%'
min: 82
max: 97
needle: true
name: Efficacité
severity:
green: 92
yellow: 87
red: 0
- type: gauge
entity: sensor.inverter_4_powerdc
unit: W
min: 0
max: 440
needle: true
name: DC
severity:
green: 100
yellow: 200
red: 300
- type: gauge
entity: sensor.inverter_4_power
unit: W
min: 0
max: 420
needle: true
name: AC
severity:
green: 100
yellow: 200
red: 300
- type: gauge
entity: sensor.inverter_4_voltage
unit: V
min: 210
max: 250
needle: true
name: Tension
severity:
green: 220
yellow: 0
red: 240
- type: markdown
content: >-
| | |
|:------|:--|
| Day: |
{{(states('sensor.inverter_4_yieldday')|float/1000)|round(2)}} kWh |
| Total: | {{states('sensor.inverter_4_yieldtotal')|float|round}}
kWh |
- type: conditional
conditions:
- entity: binary_sensor.inverter_5_reachable
state: 'off'
card:
square: false
columns: 2
type: grid
cards:
- type: markdown
content: |-
### 112183226985
Position: #5
- type: markdown
content: Déconnecté
style: |
ha-card {
background-color: darkred;
}
- type: conditional
conditions:
- entity: binary_sensor.inverter_5_reachable
state: 'on'
card:
square: false
columns: 8
type: grid
cards:
- type: markdown
content: >-
### 112183226985
Position: #5
{{as_local(states.sensor.inverter_5_power.last_updated).time()|string|truncate(8,
False, '')}}
- type: gauge
entity: sensor.inverter_5_temperature
unit: °C
min: 0
max: 65
needle: true
name: Température
severity:
green: 0
yellow: 45
red: 55
- type: gauge
entity: sensor.inverter_5_adjusted_irradiation
unit: '%'
min: 0
max: 100
needle: true
name: Irradiation
- type: gauge
entity: sensor.inverter_5_efficiency
unit: '%'
min: 82
max: 97
needle: true
name: Efficacité
severity:
green: 92
yellow: 87
red: 0
- type: gauge
entity: sensor.inverter_5_powerdc
unit: W
min: 0
max: 440
needle: true
name: DC
severity:
green: 100
yellow: 200
red: 300
- type: gauge
entity: sensor.inverter_5_power
unit: W
min: 0
max: 420
needle: true
name: AC
severity:
green: 100
yellow: 200
red: 300
- type: gauge
entity: sensor.inverter_5_voltage
unit: V
min: 210
max: 250
needle: true
name: Tension
severity:
green: 220
yellow: 0
red: 240
- type: markdown
content: >-
| | |
|:------|:--|
| Day: |
{{(states('sensor.inverter_5_yieldday')|float/1000)|round(2)}} kWh |
| Total: | {{states('sensor.inverter_5_yieldtotal')|float|round}}
kWh |
- type: conditional
conditions:
- entity: binary_sensor.inverter_6_reachable
state: 'off'
card:
square: false
columns: 2
type: grid
cards:
- type: markdown
content: |-
### 112183219226
Position: #6
- type: markdown
content: Déconnecté
style: |
ha-card {
background-color: darkred;
}
- type: conditional
conditions:
- entity: binary_sensor.inverter_6_reachable
state: 'on'
card:
square: false
columns: 8
type: grid
cards:
- type: markdown
content: >-
### 112183219226
Position: #6
{{as_local(states.sensor.inverter_6_power.last_updated).time()|string|truncate(8,
False, '')}}
- type: gauge
entity: sensor.inverter_6_temperature
unit: °C
min: 0
max: 65
needle: true
name: Température
severity:
green: 0
yellow: 45
red: 55
- type: gauge
entity: sensor.inverter_6_adjusted_irradiation
unit: '%'
min: 0
max: 100
needle: true
name: Irradiation
- type: gauge
entity: sensor.inverter_6_efficiency
unit: '%'
min: 82
max: 97
needle: true
name: Efficacité
severity:
green: 92
yellow: 87
red: 0
- type: gauge
entity: sensor.inverter_6_powerdc
unit: W
min: 0
max: 440
needle: true
name: DC
severity:
green: 100
yellow: 200
red: 300
- type: gauge
entity: sensor.inverter_6_power
unit: W
min: 0
max: 420
needle: true
name: AC
severity:
green: 100
yellow: 200
red: 300
- type: gauge
entity: sensor.inverter_6_voltage
unit: V
min: 210
max: 250
needle: true
name: Tension
severity:
green: 220
yellow: 0
red: 240
- type: markdown
content: >-
| | |
|:------|:--|
| Day: |
{{(states('sensor.inverter_6_yieldday')|float/1000)|round(2)}} kWh |
| Total: | {{states('sensor.inverter_6_yieldtotal')|float|round}}
kWh |
- type: grid
square: false
columns: 8
cards:
- type: markdown
content: '### Total'
- type: markdown
content: ' '
- type: markdown
content: ' '
- type: markdown
content: ' '
- type: gauge
entity: sensor.inverters_powerdc
unit: W
min: 0
max: 2520
needle: true
name: DC Total
severity:
green: 660
yellow: 1320
red: 1980
- type: gauge
entity: sensor.inverters_power
unit: W
min: 0
max: 2520
needle: true
name: AC Total
severity:
green: 630
yellow: 1260
red: 1890
- type: markdown
content: ' '
- type: markdown
content: >-
| | |
|:------|:--|
| Day: |
{{states('sensor.inverters_energy_meter_daily')|float|round(2)}} kWh |
| Total: | {{states('sensor.inverters_energy')|float|round}} kWh |
@mathieucarbou
Copy link
Author

Bonjour, bravo pour votre travail !!! et merci pour le partage... J'ai adapté votre code à mon installation et j'ai une petite question concernant la formule de calcule de "{{ [100, states.sensor.inverter_1_powerdc.state|float / (400 * (110 - states.sensor.inverter_1_temperature.state|float * 0.4) / 100) * 100] | min }}". A quoi correspondent les nombres ? Mon installation comporte des micron-onduleurs de puissances differentes ce qui m'obligera à adapter.

Merci de votre comprehension.

cordialement Christophe

idéalement il faudrait templacer 0.4 et 400 selon la puissance de vos MO. C'est optionnel et peut être enlevé. Ça sert à calculer plus précisément l'irradiation.

L'irradiation est calculée par le DTU en prenant la puissance en sortie divisée par la puissance crete (400Wc), mais cette puissance est une mesure en labo à 25 degrés. Hors la puissance crete dépend de la température. Pour les panneaux DMEGC, chaque pas de +25 degrés entraine une baisse de 10% de la puissance crete à cause de la chaleur, et vis versa: hausse de 10% à 0 degrés.

Donc cela fausse le % d'irradiation car l'hiver, openDTU va rapporter un % d'irradiation plus élevé que la réalité, car la puissance crete est souvent plus que 400Wc, et l'été, il va rapporter un % plus bas, alors qu'en fait l'irradiation est à son maximum, mais il fait tellement chaud que les panneaux ne peuvent pas sortir plus que 360W.

@crazybike63
Copy link

Merci pour vos explications extrêmement claires. Je modifier mon code en conséquence.
Encore merci pour le partage, je vous souhaite un bon week-end.

Cordialement Christophe

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment