|
## |
|
# Automatically limit inverters based on grid excess with Home Assistant and OpenDTU |
|
# by Mathieu Carbou |
|
# Ref: https://gist.github.com/mathieucarbou/382556f1279d612962e03232544692d1 |
|
## |
|
|
|
# https://www.home-assistant.io/integrations/input_number |
|
input_number: |
|
# Inverters nominal power, usually 400W, 500W, 1000W, etc |
|
inverters_nominal_power: |
|
name: Inverters Nominal Power |
|
unit_of_measurement: W |
|
min: 0 |
|
max: 2000 |
|
step: 1 |
|
mode: box |
|
# Manual control of the production limit of inverters |
|
inverters_power_limit: |
|
name: Inverters Power Limit |
|
unit_of_measurement: W |
|
min: 0 |
|
max: 1000 |
|
step: 1 |
|
mode: slider |
|
# Target excess or import to stay close to |
|
inverters_excess_setpoint: |
|
name: Inverters Excess Setpoint |
|
unit_of_measurement: W |
|
min: -10000 |
|
max: 10000 |
|
step: 1 |
|
mode: box |
|
# Total number of inverters. Inverters should be named Inverter 1, Inverter 2, etc |
|
inverters_count: |
|
name: Inverters Count |
|
min: 0 |
|
max: 30 |
|
step: 1 |
|
mode: box |
|
|
|
# https://www.home-assistant.io/integrations/rest |
|
rest: |
|
# Get the 3ERL trend (https://3erl.fr) for 3ERL subscribers |
|
- resource: https://3erl.fr/api.json |
|
scan_interval: 60 |
|
binary_sensor: |
|
- name: "3ERL: Bridage Demandé" |
|
icon: "mdi:car-speed-limiter" |
|
unique_id: 347A6F4D-6B09-4A20-9C2C-D611ED23EF4B |
|
value_template: "{{ value_json['Bridage'] }}" |
|
sensor: |
|
- name: "3ERL: Tendance du jour" |
|
icon: "mdi:trending-up" |
|
unique_id: 31F1BED4-8100-44A4-88BA-DB45450611CF |
|
# multiply by 10 because the value is in c€/kWh |
|
value_template: | |
|
{% set data = value_json['PREP_Profile'] %} |
|
{% if data == '3+' %} 🟢🟢🟢 |
|
{% elif data == '2+' %} 🟢🟢 |
|
{% elif data == '1+' %} 🟢 |
|
{% elif data == '0' %} ⚠️ |
|
{% elif data == '1-' %} ⛔️ |
|
{% elif data == '2-' %} ⛔️⛔️ |
|
{% elif data == '3-' %} ⛔️⛔️⛔️ |
|
{% else %} ⁉️ |
|
{% endif %} |
|
|
|
# Get the electricity market price trend from RTE |
|
- resource_template: https://www.services-rte.com/cms/open_data/v1/price/table?startDate={{ now().strftime('%d%%2F%m%%2F%Y') }} |
|
scan_interval: 60 |
|
sensor: |
|
- name: "Électricité: Prix de règlement des écarts positifs" |
|
icon: "mdi:currency-eur" |
|
unique_id: EA2D2A8C-5327-47C8-92EF-C16E9BE7A4C5 |
|
state_class: measurement |
|
unit_of_measurement: "€/MWh" |
|
value_template: "{{ value_json['values'][0]['pre']['positive'] | float }}" |
|
- name: "Électricité: Prix de règlement des écarts négatifs" |
|
icon: "mdi:currency-eur" |
|
unique_id: 95AE2165-7E9A-40BA-A555-1C7B7B93B26D |
|
value_template: "{{ value_json['values'][0]['pre']['negative'] | float }}" |
|
state_class: measurement |
|
unit_of_measurement: "€/MWh" |
|
|
|
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 Produced 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" |
|
|
|
- name: Inverters Produced 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" |
|
|
|
template: |
|
# https://www.home-assistant.io/integrations/sensor/ |
|
- sensor: |
|
# Compute the number of inverters currently producing power |
|
- name: Inverters Producing Count |
|
unique_id: 7FAAECB4-2105-4F86-B63E-A1962F7FC81E |
|
state: >- |
|
{{ ['1410A01EC916', '1410A01ED6CA', '1410A01ED5A9', '1410A01ED5F0', '1410A01F092D', '1410A01ED604', '1410A01F010C']|map('regex_replace', '(.+)', "sensor.inverter_\\1_power")|map('states')|map('float', 0)|select('gt', 0)|list|count }} |
|
|
|
# Fix OpenDTU YieldTotal |
|
- 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')|float(0), states('sensor.inverters_energy')|float(0) ] | max }}" |
|
|
|
# Shelly EM clamp based |
|
- name: Solar Production Power |
|
unique_id: "01e37eed-3045-4eee-a786-1249567fe300" |
|
state_class: measurement |
|
device_class: power |
|
unit_of_measurement: W |
|
state: "{{ states.sensor.solar_plant_group_a_power.state|float + states.sensor.solar_plant_group_b_power.state|float }}" |
|
|
|
# Shelly EM clamp based |
|
- 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 }}" |
|
|
|
# Shelly EM clamp based |
|
- 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 }}" |
|
|
|
# c == this sensor last value (consumed solar production) |
|
# p == daily solar production |
|
# e == daily return to grid (loss) |
|
# we should always have: p >= c and p >= e |
|
# At midnight, yield day resets but not at the same time so we can have p < c or p < e |
|
# When not at midnight, we compare last value of c with newly computed value (c == p - e) |
|
- name: Solar Consumed Energy Daily |
|
unique_id: "01e37eed-3045-4eee-a786-1249567fe305" |
|
state_class: total_increasing |
|
device_class: energy |
|
unit_of_measurement: kWh |
|
state: >- |
|
{% set p = states.sensor.inverters_energy_meter_daily.state|float(0) %} |
|
{% set c = states.sensor.solar_consumed_energy_daily.state|float(0) %} |
|
{% set e = states.sensor.grid_energy_returned_meter_daily.state|float(0) %} |
|
{{ [0 if p == 0 or p < c or p < e 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: "{{ states('sensor.inverters_energy_meter_daily')|float(0) > 0 }}" |
|
state: "{{ [100, (100 - 100 * states('sensor.grid_energy_returned_meter_daily')|float(0) / states('sensor.inverters_energy_meter_daily')|float )] | min }}" |
|
|
|
sensor: |
|
# https://www.home-assistant.io/integrations/integration/ |
|
# Shelly EM clamp based |
|
- platform: integration |
|
name: Solar Production Energy |
|
unique_id: E85A7E482-7937-4ABC-A0C6-1B9790DF417F |
|
source: sensor.solar_production_power |
|
unit_prefix: k |
|
# Shelly EM clamp based |
|
- platform: integration |
|
name: Home Consumed Energy |
|
unique_id: E2BA4424-8CA8-4D74-9A2F-F0E5EFF84622 |
|
source: sensor.home_consumed_power |
|
unit_prefix: k |
|
|
|
# https://www.home-assistant.io/integrations/utility_meter/ |
|
utility_meter: |
|
# Compute the daily yield of all inverters |
|
inverters_energy_meter_daily: |
|
name: Inverters Energy Meter Daily |
|
unique_id: 4C4D8D06-C9D2-4408-B21A-1274A6E0F041 |
|
source: sensor.inverters_energy |
|
always_available: true |
|
cycle: daily |
|
|
|
# https://www.home-assistant.io/docs/automation/ |
|
automation: |
|
# Detect changes to "Inverters Power Limit" input and propagate it to imverters |
|
- id: "0000000000038" |
|
alias: "Solar: Propagate power limit change to inverters" |
|
trigger: |
|
- trigger: state |
|
entity_id: |
|
- input_number.inverters_power_limit |
|
condition: [] |
|
action: |
|
- action: number.set_value |
|
data: |
|
value: "{{states('input_number.inverters_power_limit')|int(0)}}" |
|
target: |
|
entity_id: |
|
- number.inverter_1410A01EC916_limit_nonpersistent_absolute |
|
- number.inverter_1410A01ED6CA_limit_nonpersistent_absolute |
|
- number.inverter_1410A01ED5A9_limit_nonpersistent_absolute |
|
- number.inverter_1410A01ED5F0_limit_nonpersistent_absolute |
|
- number.inverter_1410A01F092D_limit_nonpersistent_absolute |
|
- number.inverter_1410A01ED604_limit_nonpersistent_absolute |
|
- number.inverter_1410A01F010C_limit_nonpersistent_absolute |
|
|
|
# Each 2 minutes, compute the new limit to set to inverters |
|
- id: "0000000000039" |
|
alias: "Solar: Auto adjust power limits" |
|
trigger: |
|
- trigger: time_pattern |
|
minutes: /1 |
|
# seconds: /30 |
|
condition: |
|
- condition: state |
|
entity_id: binary_sensor.opendtu_ff4930_status |
|
state: "on" |
|
action: |
|
- if: |
|
- condition: numeric_state |
|
entity_id: sensor.inverters_producing_count |
|
above: 0 |
|
then: |
|
- variables: |
|
new_limit: >- |
|
{% set producing = states('sensor.inverters_producing_count')|int(0) %} |
|
{% set nominalPower = states('input_number.inverters_nominal_power')|int(0) %} |
|
{% if producing <= 0 %} |
|
{{nominalPower}} |
|
{% else %} |
|
{% set grid = states('sensor.grid_power')|float(0) %} |
|
{% set setpoint = states('input_number.inverters_excess_setpoint')|int(0) %} |
|
{% set limit = states('input_number.inverters_power_limit')|int(nominalPower) %} |
|
{% set miss = grid - setpoint %} |
|
{% set error = miss / producing %} |
|
{{ [nominalPower, [10, limit + error]|max]|min|round }} |
|
{% endif %} |
|
- action: input_number.set_value |
|
data: |
|
value: "{{ new_limit|int(0) }}" |
|
target: |
|
entity_id: |
|
- input_number.inverters_power_limit |
|
else: |
|
- action: input_number.set_value |
|
data: |
|
value: "{{ states('input_number.inverters_nominal_power')|int(0) }}" |
|
target: |
|
entity_id: |
|
- input_number.inverters_power_limit |
|
|
|
# For 3ERL subscribers, activate or deactivate the automation to automatically limit the inverters when 3ERL asks for it |
|
- id: "0000000000040" |
|
alias: "Solar: Auto activate 3ERL Zero-Inject" |
|
triggers: |
|
- trigger: state |
|
entity_id: |
|
- binary_sensor.3erl_bridage_demande |
|
to: "on" |
|
- trigger: homeassistant |
|
event: start |
|
conditions: |
|
- condition: state |
|
entity_id: binary_sensor.3erl_bridage_demande |
|
state: "on" |
|
actions: |
|
- action: notify.whatsapp_mathieu |
|
data: |
|
message: "[SOLAR] 3RL Bridage: ON" |
|
- action: automation.turn_on |
|
target: |
|
entity_id: automation.solar_auto_adjust_power_limits |
|
|
|
- id: "0000000000052" |
|
alias: "Solar: Auto deactivate 3ERL Zero-Inject" |
|
triggers: |
|
- trigger: state |
|
entity_id: |
|
- binary_sensor.3erl_bridage_demande |
|
from: "on" |
|
to: "off" |
|
conditions: [] |
|
actions: |
|
- action: notify.whatsapp_mathieu |
|
data: |
|
message: "[SOLAR] 3RL Bridage: OFF" |
|
- action: automation.turn_off |
|
target: |
|
entity_id: automation.solar_auto_adjust_power_limits |
|
- action: input_number.set_value |
|
data: |
|
value: "{{ states('input_number.inverters_nominal_power')|int(0) }}" |
|
target: |
|
entity_id: |
|
- input_number.inverters_power_limit |
|
# - action: input_number.set_value |
|
# metadata: {} |
|
# data: |
|
# value: -3000 |
|
# target: |
|
# entity_id: input_number.inverters_excess_setpoint |
|
|
|
- id: "0000000000041" |
|
alias: "Solar: Auto update Setpoint" |
|
triggers: |
|
- trigger: state |
|
entity_id: |
|
- binary_sensor.3erl_bridage_demande |
|
- binary_sensor.openevse_vehicle_connected |
|
- sensor.openevse_vehicle_battery_level |
|
- trigger: homeassistant |
|
event: start |
|
conditions: |
|
- condition: state |
|
entity_id: binary_sensor.3erl_bridage_demande |
|
state: "on" |
|
actions: |
|
- if: |
|
- condition: state |
|
entity_id: binary_sensor.openevse_vehicle_connected |
|
state: "on" |
|
- condition: numeric_state |
|
entity_id: sensor.openevse_vehicle_battery_level |
|
below: 100 |
|
then: |
|
- action: input_number.set_value |
|
metadata: {} |
|
data: |
|
value: -600 |
|
target: |
|
entity_id: input_number.inverters_excess_setpoint |
|
else: |
|
- action: input_number.set_value |
|
metadata: {} |
|
data: |
|
value: -100 |
|
target: |
|
entity_id: input_number.inverters_excess_setpoint |
|
|
|
- id: "0000000000042" |
|
alias: "Solar: Notify of high grid voltage" |
|
trigger: |
|
- trigger: numeric_state |
|
entity_id: |
|
- sensor.grid_voltage |
|
above: 250 |
|
action: |
|
- action: notify.whatsapp_mathieu |
|
data: |
|
message: "[GRID] High Voltage (> 250V)" |
|
- delay: |
|
hours: 0 |
|
minutes: 1 |
|
seconds: 0 |
|
milliseconds: 0 |
|
mode: single |
|
max_exceeded: silent |
|
|
|
- id: "0000000000043" |
|
alias: "Solar: Notify of inverter producing count" |
|
trigger: |
|
- trigger: state |
|
entity_id: |
|
- sensor.inverters_producing_count |
|
to: null |
|
action: |
|
- action: notify.whatsapp_mathieu |
|
data: |
|
message: "[SOLAR] Inverters producing: {{ states('sensor.inverters_producing_count')|int(0) }}" |
|
mode: single |
|
max_exceeded: silent |
ok merci
j'avais déjà crée la ligne packages dans configuration.yaml
opendtu.yaml se charge je pense car j'ai les capteurs qui se sont crée dans l'aperçu général (non fonctionnel pour la plupart car je n'ai pas modifie leurs id dans votre script)
par contre view.yaml et opendtu_3erl.yaml ne se charge pas ou je ne sait pas par ou y accéder
j'ai la vérifié les .yaml dans outils de développement HA ne trouve pas d'erreur ...