Skip to content

Instantly share code, notes, and snippets.

@mathieucarbou
Last active September 5, 2024 10:30
Show Gist options
  • Save mathieucarbou/f9215b311a9018623c1579ab5c2cad7a to your computer and use it in GitHub Desktop.
Save mathieucarbou/f9215b311a9018623c1579ab5c2cad7a to your computer and use it in GitHub Desktop.
Home Assistant Solar Diverter (Router)

Home Assistant Solar Diverter (Router)

An alternative to use Home Assistant instead of a Shelly EM Pro for the Shelly Router.

Refs:

Setup

Put the solar_router.yaml file below inside the packages folder

Add in your global config:

homeassistant:
  packages: !include_dir_named packages

lovelace-view.yaml is the yaml for the view below.

Read carefully the commments in the solar_router.yaml file to configure!

You need several sensors:

  • grid power
  • grid voltage
  • shelly dimmer
  • optionally, if you want to see the real measurements a sensor for the output power and power factor (shelly EM clamp) that will also measure the energy.
# How to use:
#
# - Edit this script to add your sensors:
#   * sensor.grid_power => Measured Grid Power (import/export, positive/negative)
#   * sensor.grid_voltage => Measured Grid Voltage
#   * sensor.shelly_pro_em_regulator_output_power => Measured LSA Output Power (when routing)
#   * sensor.shelly_pro_em_regulator_output_power_factor => Measured LSA Output Power Factor (when routing)
#   * light.shelly_dimmer => Your Shelly Dimmer, controlling the LSA volatge regulator
#
# - Add widgets in HA for all these inputs
#
# - Initialize them:
#   * solar_router_mode => Off
#   * solar_router_pid_setpoint => 0
#   * solar_router_pid_kp => 1
#   * solar_router_output_resistance => your measured resistance value
#
#  - Calibrate your dimmer before: you the Shelly Dimmer remapping function to corrctly set the 0% and 100%.
#    * For the LSA and LCTC voltage regulators, I found 9-75 to be good values

Config

  • Set your resistance value
  • Set your target power (usually 0 W)
  • Set the PID settings (Kp to 1 to start with)

Update the yaml file to set your sensor for grid power, grid voltage, shelly dimmer.

Screenshots

Off Mode

Screenshot 2024-09-05 at 12 04 49

Automatic Mode

Screenshot 2024-09-05 at 12 05 53

Manual Mode

Screenshot 2024-09-05 at 12 27 32

Example when setting a setpoint to 1000 W

Screenshot 2024-09-05 at 12 05 04

- title: Solar Router
path: solar-router
icon: mdi:water-boiler-auto
type: sections
max_columns: 4
sections:
- type: grid
cards:
- type: entities
entities:
- entity: sensor.solar_router_grid_power
name: Grid Power
- entity: input_number.solar_router_output_resistance
name: Resistance (ohms)
- entity: input_number.solar_router_pid_setpoint
name: Setpoint
- entity: input_number.solar_router_pid_kp
name: Kp
- type: entities
entities:
- entity: input_select.solar_router_mode
secondary_info: none
name: ' '
show_header_toggle: false
- features:
- type: light-brightness
type: tile
entity: light.shelly_dimmer
layout_options:
grid_columns: 4
grid_rows: 2
visibility:
- condition: state
entity: input_select.solar_router_mode
state: Manual Routing
- type: tile
entity: light.shelly_dimmer
layout_options:
grid_columns: 4
grid_rows: 2
visibility:
- condition: state
entity: input_select.solar_router_mode
state: Automatic Routing
icon_tap_action:
action: none
tap_action:
action: none
- type: entities
entities:
- entity: sensor.shelly_dimmer_temperature
name: Dimmer Temperature
show_header_toggle: false
state_color: false
visibility:
- condition: or
conditions:
- condition: state
entity: input_select.solar_router_mode
state: Automatic Routing
- condition: state
entity: input_select.solar_router_mode
state: Manual Routing
title: Control
- type: grid
cards:
- type: entities
entities:
- entity: sensor.solar_router_output_power
name: Output Power
- entity: sensor.solar_router_output_voltage
name: Output Voltage
- entity: sensor.solar_router_output_current
name: Output Current
- entity: sensor.solar_router_output_apparent_power
name: Output Apparent Power
- entity: sensor.solar_router_output_power_factor
name: Output Power Factor
- entity: sensor.solar_router_output_thdi
name: Output THDi
- type: gauge
entity: sensor.solar_router_output_duty_cycle
min: 0
max: 100
name: Duty Cycle
title: Expected Output Compensation
- type: grid
cards:
- type: entities
entities:
- entity: sensor.solar_router_measured_output_power
name: Output Power
- entity: sensor.solar_router_measured_output_voltage
name: Output Voltage
- entity: sensor.solar_router_measured_output_current
name: Output Current
- entity: sensor.solar_router_measured_output_apparent_power
name: Output Apparent Power
- entity: sensor.solar_router_measured_output_power_factor
name: Output Power Factor
- entity: sensor.solar_router_measured_output_thdi
name: Output THDi
show_header_toggle: false
title: Output Measurements
- type: grid
cards:
- type: history-graph
entities:
- entity: sensor.solar_router_grid_power
name: Grid Power
- entity: sensor.solar_router_output_power
name: Expected Output Power
- entity: sensor.solar_router_measured_output_power
name: Measured Output Power
hours_to_show: 1
- type: history-graph
entities:
- entity: sensor.solar_router_grid_voltage
name: Grid Voltage
- entity: sensor.solar_router_output_voltage
name: Expected Output Voltage
- entity: sensor.solar_router_measured_output_voltage
name: Measured Output Voltage
hours_to_show: 1
title: Graphs
cards: []
badges: []
# How to use:
#
# - Edit this script to add your sensors:
# * sensor.grid_power => Measured Grid Power (import/export, positive/negative)
# * sensor.grid_voltage => Measured Grid Voltage
# * sensor.shelly_pro_em_regulator_output_power => Measured LSA Output Power (when routing)
# * sensor.shelly_pro_em_regulator_output_power_factor => Measured LSA Output Power Factor (when routing)
# * light.shelly_dimmer => Your Shelly Dimmer, controlling the LSA volatge regulator
#
# - Add widgets in HA for all these inputs
#
# - Initialize them:
# * solar_router_mode => Off
# * solar_router_pid_setpoint => 0
# * solar_router_pid_kp => 1
# * solar_router_output_resistance => your measured resistance value
#
# - Calibrate your dimmer before: you the Shelly Dimmer remapping function to corrctly set the 0% and 100%.
# * For the LSA and LCTC voltage regulators, I found 9-75 to be good values
# https://www.home-assistant.io/integrations/input_select
input_select:
solar_router_mode:
name: Solar Router Mode
options:
- "Off"
- "Automatic Routing"
- "Manual Routing"
# https://www.home-assistant.io/integrations/input_number
input_number:
# Grid value to target
solar_router_pid_setpoint:
name: Solar Router PID Setpoint (W)
min: -5000
max: 5000
step: 1
mode: box
# Kp value for PID
solar_router_pid_kp:
name: Solar Router PID Kp
min: 0
max: 1
step: 0.1
mode: box
# Resistance value connected to output in Ohms
solar_router_output_resistance:
name: Solar Router Output Resistance (ohms)
min: 0
max: 100
step: 1
mode: box
# Hidden variable for computation
solar_router_output_power:
name: Solar Router Output Power
min: 0
max: 5000
step: 1
mode: box
template:
# https://www.home-assistant.io/integrations/sensor/
- sensor:
- name: Solar Router Grid Power
unique_id: 463E2D5D-820F-4F5E-9D0D-2D831CF20AB0
state_class: measurement
device_class: power
unit_of_measurement: W
state: "{{ states('sensor.grid_power')|float(0) }}"
- name: Solar Router Grid Voltage
unique_id: 875C11B3-ED66-47BD-838C-06A0D5814770
state_class: measurement
device_class: voltage
unit_of_measurement: V
state: "{{ states('sensor.grid_voltage')|float(0) }}"
- name: Solar Router Output Max Power
unique_id: DFE76DF3-78E6-46D2-BB40-2CD3BDCE3E4A
state_class: measurement
device_class: power
unit_of_measurement: W
state: >-
{% set r = states('input_number.solar_router_output_resistance')|float(0) %}
{% set v = states('sensor.solar_router_grid_voltage')|float(0) %}
{{ v * v / r if r > 0 else 0 }}
- name: Solar Router Output Power
unique_id: BEF8B3D3-0E11-4958-86C1-3BB3C5B197C7
state_class: measurement
device_class: power
unit_of_measurement: W
state: "{{ states('input_number.solar_router_output_power')|float(0) }}"
- name: Solar Router Output Duty Cycle
unique_id: 1922626F-C333-45C2-AE9C-46E504E333B5
state_class: measurement
unit_of_measurement: "%"
state: >-
{% set ouput = states('sensor.solar_router_output_power')|float(0) %}
{% set maxPower = states('sensor.solar_router_output_max_power')|float(0) %}
{{ ouput / maxPower * 100 if maxPower > 0 else 0 }}
- name: Solar Router Output Power Factor
unique_id: 370C7099-8FBB-459D-AE53-2B0BFC4F1D10
state_class: measurement
device_class: power_factor
state: "{{ (states('sensor.solar_router_output_duty_cycle')|float(0) / 100) ** 0.5 }}"
- name: Solar Router Output Voltage
unique_id: BFF33154-A266-4D24-9ED6-EA9B6FB69893
state_class: measurement
device_class: voltage
unit_of_measurement: V
state: "{{ states('sensor.solar_router_output_power_factor')|float(0) * states('sensor.solar_router_grid_voltage')|float(0) }}"
- name: Solar Router Output Current
unique_id: D68B83E8-9700-4437-AC0B-799BBBED46DB
state_class: measurement
device_class: current
unit_of_measurement: A
state: >-
{% set r = states('input_number.solar_router_output_resistance')|float(0) %}
{% set v = states('sensor.solar_router_output_voltage')|float(0) %}
{{ v / r if r > 0 else 0 }}
- name: Solar Router Output Apparent Power
unique_id: 2E220105-B2E4-45CF-8B24-1D2674C1F74B
state_class: measurement
device_class: apparent_power
unit_of_measurement: VA
state: "{{ states('sensor.solar_router_output_current')|float(0) * states('sensor.solar_router_grid_voltage')|float(0) }}"
- name: Solar Router Output THDi
unique_id: E850385D-A05A-44F4-B620-CCCDAECF3613
state_class: measurement
unit_of_measurement: "%"
state: >-
{% set dutyCycle = states('sensor.solar_router_output_duty_cycle')|float(0) / 100 %}
{{ 100 * ((1 / dutyCycle - 1) ** 0.5) if dutyCycle > 0 else 0 }}
- name: Solar Router Measured Output Power
unique_id: C8C5E317-484A-457F-B5C0-6D11C1718DF2
state_class: measurement
device_class: power
unit_of_measurement: W
state: "{{ states('sensor.shelly_pro_em_regulator_output_power')|float(0) }}"
- name: Solar Router Measured Output Power Factor
unique_id: 30454640-9177-4590-B079-2A09989D2A49
state_class: measurement
device_class: power_factor
state: "{{ states('sensor.shelly_pro_em_regulator_output_power_factor')|float(0) }}"
- name: Solar Router Measured Output Apparent Power
unique_id: 3F6A3D88-018B-4221-AA62-BF5FFC7C9C62
state_class: measurement
device_class: apparent_power
unit_of_measurement: VA
state: >-
{% set pf = states('sensor.solar_router_measured_output_power_factor')|float(0) %}
{% set p = states('sensor.solar_router_measured_output_power')|float(0) %}
{{ p / pf if pf > 0 else 0 }}
- name: Solar Router Measured Output Voltage
unique_id: 94FC4D20-C956-438E-88C6-AA61B418D1A6
state_class: measurement
device_class: voltage
unit_of_measurement: V
state: >-
{% set r = states('input_number.solar_router_output_resistance')|float(0) %}
{% set p = states('sensor.solar_router_measured_output_power')|float(0) %}
{{ (p * r) ** 0.5 }}
- name: Solar Router Measured Output Current
unique_id: DA53F339-F609-437C-97E9-103BFBC2676E
state_class: measurement
device_class: current
unit_of_measurement: A
state: >-
{% set r = states('input_number.solar_router_output_resistance')|float(0) %}
{% set p = states('sensor.solar_router_measured_output_power')|float(0) %}
{{ (p / r) ** 0.5 if r > 0 else 0 }}
- name: Solar Router Measured Output THDi
unique_id: 4481B5A3-4CC8-4D26-980A-BEC2756566A4
state_class: measurement
unit_of_measurement: "%"
state: >-
{% set pf = states('sensor.solar_router_measured_output_power_factor')|float(0) %}
{{ 100 * ((1 / (pf * pf) - 1) ** 0.5) if pf > 0 else 0 }}
automation:
- alias: "Solar Router - Mode Updated"
description: ""
mode: single
trigger:
- platform: state
entity_id:
- input_select.solar_router_mode
condition: []
action:
- choose:
- conditions:
- condition: or
conditions:
- condition: state
entity_id: input_select.solar_router_mode
state: Automatic Routing
- condition: state
entity_id: input_select.solar_router_mode
state: Manual Routing
sequence:
- action: light.turn_on
target:
entity_id: light.shelly_dimmer
data:
transition: 0
default:
- action: light.turn_off
metadata: {}
data:
transition: 0
target:
entity_id: light.shelly_dimmer
- alias: "Solar Router - Routing"
description: ""
mode: single
trigger:
- platform: state
entity_id:
- sensor.solar_router_grid_power
condition: []
action:
- choose:
- conditions:
- condition: state
entity_id: input_select.solar_router_mode
state: Automatic Routing
sequence:
- variables:
output_power: >-
{% set setpoint = states('input_number.solar_router_pid_setpoint')|float(0) %}
{% set kp = states('input_number.solar_router_pid_kp')|float(1) %}
{% set maxPower = states('sensor.solar_router_output_max_power')|float(0) %}
{% set grid = states('sensor.solar_router_grid_power')|float(0) %}
{% set ouput = states('input_number.solar_router_output_power')|float(0) %}
{{ [ [ 0, ouput + (setpoint - grid) * kp ] | max, maxPower ] | min }}
duty_cycle: >-
{% set setpoint = states('input_number.solar_router_pid_setpoint')|float(0) %}
{% set kp = states('input_number.solar_router_pid_kp')|float(1) %}
{% set maxPower = states('sensor.solar_router_output_max_power')|float(0) %}
{% set grid = states('sensor.solar_router_grid_power')|float(0) %}
{% set ouput = states('input_number.solar_router_output_power')|float(0) %}
{{ ( [ [ 0, ouput + (setpoint - grid) * kp ] | max, maxPower ] | min ) / maxPower * 100 if maxPower > 0 else 0 }}
- action: input_number.set_value
metadata: {}
data:
value: "{{ output_power }}"
target:
entity_id: input_number.solar_router_output_power
- if:
- condition: template
value_template: "{{ duty_cycle < 1 }}"
then:
- action: light.turn_off
metadata: {}
data:
transition: 0
target:
entity_id: light.shelly_dimmer
else:
- action: light.turn_on
metadata: {}
data:
transition: 0
brightness_pct: "{{ duty_cycle }}"
target:
entity_id: light.shelly_dimmer
- conditions:
- condition: state
entity_id: input_select.solar_router_mode
state: "Off"
sequence:
- action: input_number.set_value
metadata: {}
data:
value: 0
target:
entity_id: input_number.solar_router_output_power
- action: light.turn_off
metadata: {}
data:
transition: 0
target:
entity_id: light.shelly_dimmer
default:
- action: input_number.set_value
metadata: {}
data:
value: 0
target:
entity_id: input_number.solar_router_output_power
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment