1486 lines
47 KiB
YAML
1486 lines
47 KiB
YAML
# Sungrow integration
|
|
# Based on https://github.com/mkaiser/Sungrow-SHx-Inverter-Modbus-Home-Assistant by Martin Kaiser
|
|
# Heavily modified to work around quirks in WiNet-S and SH5.0RS firmwares
|
|
|
|
# Commented out sensors are because the registers throw errors when they are read
|
|
|
|
# - id: "24321413553543" # random number
|
|
# alias: update battery charge discharge cmd
|
|
# description: "Updates Sungrow holding register for battery charge discharge command"
|
|
# trigger:
|
|
# - platform: state
|
|
# entity_id:
|
|
# - input_select.set_sg_battery_charge_discharge_cmd
|
|
# condition: []
|
|
# action:
|
|
# - service: modbus.write_register
|
|
# data_template:
|
|
# address: 13050 # 13051
|
|
# slave: 1
|
|
# # 0xAA: 170 Charge
|
|
# # 0xBB: 187 Discharge
|
|
# # 0xCC: 204 Stop (Default)
|
|
# # don't know how to compare the integer values in hexadecimal format in following decoder statement...
|
|
# value: "{% if is_state('input_select.set_sg_battery_charge_discharge_cmd' , 'Stop (default)') %} 204
|
|
# {% elif is_state('input_select.set_sg_battery_charge_discharge_cmd' , 'Force charge') %} 170
|
|
# {% elif is_state('input_select.set_sg_battery_charge_discharge_cmd' , 'Force discharge') %} 187
|
|
# {% else %} 204 {% endif %}"
|
|
# hub: SungrowSHx
|
|
# mode: single
|
|
|
|
input_boolean:
|
|
inverter_charging_schedule_enabled:
|
|
initial: true
|
|
name: Inverter charging schedule enabled
|
|
inverter_charging_schedule_2_enabled:
|
|
initial: true
|
|
name: Inverter charging schedule 2 enabled
|
|
input_datetime:
|
|
inverter_charging_schedule_start:
|
|
has_time: true
|
|
name: Inverter charging schedule start
|
|
initial: "13:30:00"
|
|
inverter_charging_schedule_end:
|
|
has_time: true
|
|
name: Inverter charging schedule end
|
|
initial: "15:00:00"
|
|
inverter_charging_schedule_2_start:
|
|
has_time: true
|
|
name: Inverter charging schedule 2 start
|
|
initial: "00:00:00"
|
|
inverter_charging_schedule_2_end:
|
|
has_time: true
|
|
name: Inverter charging schedule 2 end
|
|
initial: "00:00:00"
|
|
input_number:
|
|
inverter_charging_schedule_target_soc:
|
|
name: Inverter charging schedule target state of charge
|
|
min: 0
|
|
max: 100
|
|
unit_of_measurement: "%"
|
|
initial: 85
|
|
mode: box
|
|
inverter_charging_schedule_2_target_soc:
|
|
name: Inverter charging schedule 2 target state of charge
|
|
min: 0
|
|
max: 100
|
|
unit_of_measurement: "%"
|
|
initial: 0
|
|
mode: box
|
|
inverter_battery_reserve:
|
|
name: Inverter battery reserve
|
|
min: 0
|
|
max: 100
|
|
initial: 5
|
|
unit_of_measurement: "%"
|
|
mode: box
|
|
|
|
automation:
|
|
- id: e7df7dc23815acacdd8c
|
|
alias: Inverter - apply charging schedule
|
|
mode: restart
|
|
trigger:
|
|
- platform: state
|
|
entity_id:
|
|
# Explicit enables
|
|
- input_boolean.inverter_charging_schedule_enabled
|
|
- input_boolean.inverter_charging_schedule_2_enabled
|
|
|
|
# Schedule 1 details
|
|
- input_datetime.inverter_charging_schedule_start
|
|
- input_datetime.inverter_charging_schedule_end
|
|
- input_number.inverter_charging_schedule_target_soc
|
|
|
|
# Schedule 2 details
|
|
- input_datetime.inverter_charging_schedule_2_start
|
|
- input_datetime.inverter_charging_schedule_2_end
|
|
- input_number.inverter_charging_schedule_2_target_soc
|
|
not_from:
|
|
- unknown
|
|
- unavailable
|
|
not_to:
|
|
- unknown
|
|
- unavailable
|
|
|
|
# I have a theory that being in a schedule window prevents the battery from discharging, EVEN IF the SoC is above
|
|
# the target. As such, this automation will also run when the battery level crosses any threshold here and the
|
|
# `enabled_1` and `enabled_2` variables below will take this into consideration. In other words, the schedules
|
|
# will be automatically turned off when the charge level reaches target, and switched back on if it falls below.
|
|
- platform: numeric_state
|
|
entity_id: sensor.inverter_battery_level
|
|
above: input_number.inverter_charging_schedule_target_soc
|
|
- platform: numeric_state
|
|
entity_id: sensor.inverter_battery_level
|
|
above: input_number.inverter_charging_schedule_2_target_soc
|
|
- platform: numeric_state
|
|
entity_id: sensor.inverter_battery_level
|
|
below: input_number.inverter_charging_schedule_target_soc
|
|
- platform: numeric_state
|
|
entity_id: sensor.inverter_battery_level
|
|
below: input_number.inverter_charging_schedule_2_target_soc
|
|
variables:
|
|
# Enable each schedule only if battery level is below target, it is explicitly enabled, and the dates have values.
|
|
# NOTE: It would be better to take into consideration if the schedule is active (timewise) but in effect disabling
|
|
# it unconditionally when battery level is higher doesn't matter, since we also trigger when it is lower and
|
|
# it will become re-enabled again.
|
|
enabled_1: |
|
|
{{ is_state('input_boolean.inverter_charging_schedule_enabled', 'on') and
|
|
states('input_number.inverter_charging_schedule_target_soc') | float(default = 0) > states('sensor.inverter_battery_level') | float(default = 0) and
|
|
not is_state('input_datetime.inverter_charging_schedule_start', 'unknown') and
|
|
not is_state('input_datetime.inverter_charging_schedule_end', 'unknown')
|
|
}}
|
|
enabled_2: |
|
|
{{ is_state('input_boolean.inverter_charging_schedule_2_enabled', 'on') and
|
|
states('input_number.inverter_charging_schedule_2_target_soc') | float(default = 0) > states('sensor.inverter_battery_level') | float(default = 0) and
|
|
not is_state('input_datetime.inverter_charging_schedule_2_start', 'unknown') and
|
|
not is_state('input_datetime.inverter_charging_schedule_2_end', 'unknown')
|
|
}}
|
|
action:
|
|
- service: script.apply_charging_schedule
|
|
data_template:
|
|
soc_1: |
|
|
{% if enabled_1 %}
|
|
{{ states('input_number.inverter_charging_schedule_target_soc') | int }}
|
|
{% else %}
|
|
0
|
|
{% endif %}
|
|
start_time_1: "{{ states('input_datetime.inverter_charging_schedule_start') | replace('unknown','00:00') }}"
|
|
end_time_1: "{{ states('input_datetime.inverter_charging_schedule_end') | replace('unknown','00:00') }}"
|
|
soc_2: |
|
|
{% if enabled_2 %}
|
|
{{ states('input_number.inverter_charging_schedule_2_target_soc') | int }}
|
|
{% else %}
|
|
0
|
|
{% endif %}
|
|
start_time_2: "{{ states('input_datetime.inverter_charging_schedule_2_start') | replace('unknown','00:00') }}"
|
|
end_time_2: "{{ states('input_datetime.inverter_charging_schedule_2_end') | replace('unknown','00:00') }}"
|
|
|
|
- id: 7b93d325bfe632a4e890
|
|
alias: Inverter - update battery reserve
|
|
mode: restart
|
|
trigger:
|
|
- platform: state
|
|
entity_id:
|
|
- input_number.inverter_battery_reserve
|
|
not_from:
|
|
- unknown
|
|
- unavailable
|
|
not_to:
|
|
- unknown
|
|
- unavailable
|
|
action:
|
|
- service: script.inverter_set_battery_reserve
|
|
data_template:
|
|
reserved_percentage: >-
|
|
{{ states('input_number.inverter_battery_reserve') | int }}
|
|
|
|
# The inverter can only generate 5kW of AC power. IFF the battery is not-full, it can generate 5kW of AC _and_ charge
|
|
# battery at up to 6.6kW, which saturates our 8.46 kW of PV
|
|
#
|
|
# So, preventing the battery from getting full too early on a sunny day will increase our overall yield, because the
|
|
# inverter won't have to derate the PV power to 5kW.
|
|
#
|
|
# Possible approaches:
|
|
#
|
|
# 1. Set general charge/discharge limits or start power for charging from PV[1][2]
|
|
# Unfortunately, it seems like these registers don't work on my inverter SH5.0RS, so this avenue is out.
|
|
# 2. When PV is >5.0kW and battery is not full (but not too low), set forced charging mode and set the charging power
|
|
# to be `PV power - 5.0kW` to maintain 5kW of AC constantly. Unfortunately, forced charge/discharge power register
|
|
# (13052) can't be set over Modbus (just ignored). So this option is out _at least until_ this is fixed or I have a
|
|
# way to programmatically set this using the SunGather HTTP method (i.e. WiNet-S)
|
|
# 3. Set battery mode to Stop when all of:
|
|
# * Cloud cover is low / weather is sunny
|
|
# * PV power is higher than household demand (by some margin, like 1.5x to minimise grid buying)
|
|
# * battery is not too low nor full
|
|
# * the forecast has enough remaining in the day to fill battery AND cover remaining household usage (or a proxy
|
|
# for this like, `forecast > 2*kWh_till_battery_full`)
|
|
#
|
|
# [1]: https://discord.com/channels/936031869001158666/1008992991643455529
|
|
# [2]: https://discord.com/channels/936031869001158666/936031869001158669/1011882768021590036
|
|
- id: 05bdc8eb58714c26c2fe
|
|
alias: Inverter - maximise output
|
|
mode: restart
|
|
trigger:
|
|
- platform: numeric_state
|
|
entity_id: sensor.inverter_pv_power
|
|
above: 4900
|
|
for:
|
|
minutes: 1
|
|
- platform: state
|
|
entity_id:
|
|
- sensor.inverter_battery_level
|
|
- sensor.inverter_active_power
|
|
- sensor.home_weather_cloud_coverage
|
|
- sensor.home_weather_forecast_cloud_coverage
|
|
- sensor.solcast_forecast_remaining_today
|
|
# - sensor.home_weather_forecast_condition
|
|
# - sensor.home_weather_condition
|
|
# - weather.home
|
|
- weather.home_hourly # can use attributes on this one to make decisions about the coming hours
|
|
# - weather.home_weather
|
|
- sun.sun # use `next_setting` attribute to ensure battery is online at least an hour before sunset
|
|
not_to:
|
|
- unavailable
|
|
- unknown
|
|
variables:
|
|
kwh_until_full: >
|
|
{{ 12.8 * ((100 - states('sensor.inverter_battery_level') | float)/100) }}
|
|
sunsetting: >
|
|
{{ now() + timedelta(hours = 1) > state_attr('sun.sun', 'next_setting')| as_datetime }}
|
|
should_slow_battery: >
|
|
{{ states('sensor.inverter_pv_power') | float > 5100 and
|
|
states('sensor.inverter_active_power') | float < 4200 }}
|
|
enough_in_day: >
|
|
{{2*kwh_until_full < states('sensor.solcast_forecast_remaining_today') | float}}
|
|
condition: []
|
|
action:
|
|
- choose:
|
|
- conditions:
|
|
- "{{ should_slow_battery and not sunsetting and enough_in_day }}"
|
|
sequence:
|
|
- service: script.inverter_force_battery_charge # with low charge rate -- which i have to manually set for now
|
|
- conditions:
|
|
- "{{ states('sensor.inverter_pv_power') | float < 4900 or not enough_in_day or sunsetting }}"
|
|
sequence:
|
|
- service: script.inverter_self_consumption
|
|
default: []
|
|
|
|
script:
|
|
inverter_set_battery_reserve:
|
|
alias: "Set inverter battery reserve"
|
|
mode: restart
|
|
fields:
|
|
reserved_percentage:
|
|
name: "Percentage"
|
|
description: "Percentage of battery reserved for emergency power supply"
|
|
required: true
|
|
selector:
|
|
number:
|
|
min: 0
|
|
max: 100
|
|
step: 1
|
|
unit_of_measurement: "%"
|
|
sequence:
|
|
- service: modbus.write_register
|
|
data_template:
|
|
address: 13099 # 13100
|
|
slave: 1
|
|
value: "{{ [ reserved_percentage | int ] }}"
|
|
hub: SungrowSHx
|
|
|
|
# inverter_set_battery_mode:
|
|
# alias: Set inverter battery mode
|
|
# fields:
|
|
# battery_power:
|
|
# name: "Charge/discharge power"
|
|
# description: "Charge/discharge power"
|
|
# required: false
|
|
# selector:
|
|
# number:
|
|
# min: 0
|
|
# max: 6600
|
|
# step: 1
|
|
# unit_of_measurement: "W"
|
|
|
|
# battery_mode:
|
|
# name: "Battery mode"
|
|
# description: "Battery mode"
|
|
# required: true
|
|
# selector:
|
|
# select:
|
|
# options:
|
|
# - label: Self-consumption
|
|
# value: [0, 0xCC]
|
|
# - label: Force charge
|
|
# value: [2, 0xAA]
|
|
# - label: Force discharge
|
|
# value: [2, 0xBB]
|
|
# - label: Stop
|
|
# value: [2, 0xCC]
|
|
# sequence:
|
|
# - service: modbus.write_register
|
|
# data_template:
|
|
# address: 13049 # 13050-13051
|
|
# slave: 1
|
|
# # value: "{{ battery_mode }}"
|
|
# value: |
|
|
# {% if battery_power %}
|
|
# {{ battery_mode + [battery_power|int] }}
|
|
# {% else %}
|
|
# {{ battery_mode }}
|
|
# {% endif %}
|
|
# hub: SungrowSHx
|
|
|
|
inverter_force_battery_charge:
|
|
alias: "Inverter - force battery charge"
|
|
mode: restart
|
|
sequence:
|
|
- service: modbus.write_register
|
|
data_template:
|
|
address: 13049 # 13050-13051
|
|
slave: 1
|
|
value: [2, 0xAA]
|
|
hub: SungrowSHx
|
|
inverter_force_battery_discharge:
|
|
alias: "Inverter - force battery discharge"
|
|
mode: restart
|
|
sequence:
|
|
- service: modbus.write_register
|
|
data_template:
|
|
address: 13049 # 13050-13051
|
|
slave: 1
|
|
value: [2, 0xBB]
|
|
hub: SungrowSHx
|
|
inverter_force_battery_stop:
|
|
alias: "Inverter - force battery stop"
|
|
mode: restart
|
|
sequence:
|
|
- service: modbus.write_register
|
|
data_template:
|
|
address: 13049 # 13050-13051
|
|
slave: 1
|
|
value: [2, 0xCC]
|
|
hub: SungrowSHx
|
|
inverter_self_consumption:
|
|
alias: "Inverter - self consumption"
|
|
mode: restart
|
|
sequence:
|
|
- service: modbus.write_register
|
|
data_template:
|
|
address: 13049 # 13050-13051
|
|
slave: 1
|
|
value: [0, 0xCC]
|
|
hub: SungrowSHx
|
|
|
|
# https://github.com/bohdan-s/SunGather/pull/63#issuecomment-1195049341
|
|
apply_charging_schedule:
|
|
alias: "Inverter - apply charging schedule"
|
|
|
|
# Q: is this evaluated _after_ field values are captured or before?
|
|
variables:
|
|
enable_value: 0xAA
|
|
disable_value: 0x55
|
|
every_day_value: 1
|
|
is_enabled: "{{ (soc_1 is defined and soc_1 | int > 0) or (soc_2 is defined and soc_2 | int > 0) }}"
|
|
sched_1: >
|
|
{% if soc_1 is defined and soc_1 | int > 0 %}
|
|
{{ [
|
|
today_at(start_time_1).hour,
|
|
today_at(start_time_1).minute,
|
|
today_at(end_time_1).hour,
|
|
today_at(end_time_1).minute,
|
|
soc_1
|
|
] }}
|
|
{% else %}
|
|
{{ [0, 0, 0, 0, 0] }}
|
|
{% endif %}
|
|
sched_2: >
|
|
{% if soc_2 is defined and soc_2 | int > 0 %}
|
|
{{ [
|
|
today_at(start_time_2).hour,
|
|
today_at(start_time_2).minute,
|
|
today_at(end_time_2).hour,
|
|
today_at(end_time_2).minute,
|
|
soc_2
|
|
] }}
|
|
{% else %}
|
|
{{ [0, 0, 0, 0, 0] }}
|
|
{% endif %}
|
|
bytes: >
|
|
{% if is_enabled %}
|
|
{{ [enable_value, every_day_value] + sched_1 + sched_2 }}
|
|
{% else %}
|
|
{{ [disable_value] }}
|
|
{% endif %}
|
|
|
|
fields:
|
|
start_time_1:
|
|
name: Schedule 1 Start Time
|
|
default: "13:30:00"
|
|
selector:
|
|
time:
|
|
end_time_1:
|
|
name: Schedule 1 End Time
|
|
default: "14:59:00" # 3PM is on-peak charging
|
|
selector:
|
|
time:
|
|
soc_1:
|
|
name: Schedule 1 Target State-of-Charge
|
|
default: 85
|
|
selector:
|
|
number:
|
|
min: 0
|
|
max: 100
|
|
unit_of_measurement: "%"
|
|
start_time_2:
|
|
name: Schedule 2 Start Time
|
|
default: "0:00:00"
|
|
selector:
|
|
time:
|
|
end_time_2:
|
|
name: Schedule 2 End Time
|
|
default: "00:00:00"
|
|
selector:
|
|
time:
|
|
soc_2:
|
|
name: Schedule 2 Target State-of-Charge
|
|
default: 0
|
|
selector:
|
|
number:
|
|
min: 0
|
|
max: 100
|
|
unit_of_measurement: "%"
|
|
|
|
sequence:
|
|
- service: modbus.write_register
|
|
data_template:
|
|
address: 33207 # 33208 - ...
|
|
slave: 1
|
|
value: "{{ bytes | list }}"
|
|
hub: SungrowSHx
|
|
|
|
modbus:
|
|
- name: SungrowSHx
|
|
type: tcp
|
|
host: !secret solar_inverter_ip
|
|
port: 502
|
|
retry_on_empty: true
|
|
# retries: 10
|
|
# close_comm_on_error: true
|
|
delay: 5
|
|
#timeout: 5
|
|
sensors:
|
|
# - name: Sungrow Device type code
|
|
# slave: 1
|
|
# address: 4999 # 5000
|
|
# input_type: input
|
|
# count: 1
|
|
# data_type: uint16
|
|
# swap: word
|
|
# scan_interval: 60
|
|
|
|
- name: Inverter output energy today
|
|
unique_id: d1a3ad60e978aaea9407
|
|
slave: 1
|
|
address: 5002
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter output energy total
|
|
unique_id: e28068b742fd20919aea
|
|
slave: 1
|
|
address: 5003
|
|
input_type: input
|
|
count: 2
|
|
data_type: uint32
|
|
swap: word
|
|
unit_of_measurement: kWh
|
|
precision: 1
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter temperature
|
|
unique_id: a29ef61bc181d9b95ef7
|
|
slave: 1
|
|
address: 5007
|
|
input_type: input
|
|
count: 1
|
|
data_type: int16
|
|
precision: 1
|
|
unit_of_measurement: °C
|
|
device_class: temperature
|
|
state_class: measurement
|
|
scale: 0.1
|
|
scan_interval: 10
|
|
|
|
- name: Inverter grid frequency
|
|
unique_id: 489e85158f95e8bd71fb
|
|
slave: 1
|
|
address: 5035
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 2
|
|
unit_of_measurement: Hz
|
|
device_class: frequency
|
|
state_class: measurement
|
|
scale: 0.01 # docs say 0.1 but WiNet-S implementation differs
|
|
scan_interval: 10
|
|
|
|
- name: Inverter phase A voltage
|
|
unique_id: c892eb3b2a51b37ffab3
|
|
slave: 1
|
|
address: 5018
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: V
|
|
device_class: voltage
|
|
state_class: measurement
|
|
scale: 0.1
|
|
scan_interval: 10
|
|
|
|
- name: Inverter phase A current
|
|
unique_id: 5963c0d0bf24ad5412ff
|
|
slave: 1
|
|
address: 13030
|
|
input_type: input
|
|
count: 1
|
|
data_type: int16
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: A
|
|
device_class: current
|
|
state_class: measurement
|
|
scale: 0.1
|
|
scan_interval: 10
|
|
|
|
- name: Inverter MPPT1 voltage
|
|
unique_id: 024b2df03fb2d724277c
|
|
slave: 1
|
|
address: 5010
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: V
|
|
device_class: voltage
|
|
state_class: measurement
|
|
scale: 0.1
|
|
scan_interval: 10
|
|
|
|
- name: Inverter MPPT1 current
|
|
unique_id: a5179dc512ce97cd1543
|
|
slave: 1
|
|
address: 5011
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 2
|
|
unit_of_measurement: A
|
|
device_class: current
|
|
scale: 0.1
|
|
scan_interval: 10
|
|
|
|
- name: Inverter MPPT2 voltage
|
|
unique_id: 0b856f1678a3afb1002f
|
|
slave: 1
|
|
address: 5012
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: V
|
|
device_class: voltage
|
|
state_class: measurement
|
|
scale: 0.1
|
|
scan_interval: 10
|
|
|
|
- name: Inverter MPPT2 current
|
|
unique_id: f732afc7332efa49be11
|
|
slave: 1
|
|
address: 5013
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 2
|
|
unit_of_measurement: A
|
|
device_class: current
|
|
state_class: measurement
|
|
scale: 0.1
|
|
scan_interval: 10
|
|
|
|
- name: Inverter PV power
|
|
unique_id: 4af1ff47ed7fd1bad213
|
|
slave: 1
|
|
address: 5016
|
|
input_type: input
|
|
count: 2
|
|
data_type: uint32
|
|
swap: word
|
|
precision: 0
|
|
unit_of_measurement: W
|
|
device_class: power
|
|
state_class: measurement
|
|
scale: 1
|
|
scan_interval: 5
|
|
|
|
- name: Inverter active power
|
|
unique_id: a3ee41f78c6c55377c00
|
|
slave: 1
|
|
address: 13033
|
|
input_type: input
|
|
count: 2
|
|
data_type: int32
|
|
swap: word
|
|
precision: 0
|
|
unit_of_measurement: W
|
|
device_class: power
|
|
state_class: measurement
|
|
scale: 1
|
|
scan_interval: 5
|
|
|
|
- name: Inverter reactive power
|
|
unique_id: 5a58fe975877eec6d37c
|
|
slave: 1
|
|
address: 5032
|
|
input_type: input
|
|
count: 2
|
|
data_type: int32
|
|
swap: word
|
|
precision: 0
|
|
unit_of_measurement: var
|
|
device_class: reactive_power
|
|
state_class: measurement
|
|
scale: 1
|
|
scan_interval: 10
|
|
|
|
- name: Inverter power factor
|
|
unique_id: 29099a467ed9fec02cb1
|
|
slave: 1
|
|
address: 5034
|
|
input_type: input
|
|
count: 1
|
|
data_type: int16
|
|
swap: word
|
|
unit_of_measurement: "%"
|
|
device_class: power_factor
|
|
state_class: measurement
|
|
# scale: 0.001 # according to docs...
|
|
scale: 0.1
|
|
# precision: 3
|
|
precision: 1
|
|
scan_interval: 10
|
|
|
|
# - name: BDC rated power
|
|
# slave: 1
|
|
# address: 5627 #5628
|
|
# input_type: input
|
|
# count: 1
|
|
# data_type: uint16
|
|
# swap: word
|
|
# unit_of_measurement: "W"
|
|
# device_class: power
|
|
# state_class: measurement
|
|
# scale: 100
|
|
# scan_interval: 10
|
|
|
|
- name: Inverter system state (raw)
|
|
slave: 1
|
|
address: 12999
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 0
|
|
scale: 1
|
|
scan_interval: 5
|
|
|
|
# Currently this only ever returns 0x00 over Modbus :/
|
|
- name: Inverter running state (raw)
|
|
slave: 1
|
|
address: 13000
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 0
|
|
scale: 1
|
|
scan_interval: 5
|
|
|
|
- name: Inverter PV generation today
|
|
unique_id: 27953d57c315260a7983
|
|
slave: 1
|
|
address: 13001
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter PV generation total
|
|
unique_id: 885db873746c92fcdf2d
|
|
slave: 1
|
|
address: 13002
|
|
input_type: input
|
|
count: 2
|
|
data_type: uint32
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter exported energy from PV today
|
|
unique_id: 08454b6e9f7061180795
|
|
slave: 1
|
|
address: 13004
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter exported energy from PV total
|
|
unique_id: 00efcf01e33337d01b5f
|
|
slave: 1
|
|
address: 13005
|
|
input_type: input
|
|
count: 2
|
|
data_type: uint32
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter load power
|
|
unique_id: 9777fe694d687a4f30df
|
|
slave: 1
|
|
address: 13007
|
|
input_type: input
|
|
count: 2
|
|
data_type: int32
|
|
swap: word
|
|
precision: 0
|
|
unit_of_measurement: W
|
|
device_class: power
|
|
state_class: measurement
|
|
scale: 1
|
|
scan_interval: 5
|
|
|
|
- name: Inverter export power
|
|
unique_id: 4c3bac29a87561796c06
|
|
slave: 1
|
|
address: 13009
|
|
input_type: input
|
|
count: 2
|
|
data_type: int32
|
|
swap: word
|
|
precision: 0
|
|
unit_of_measurement: W
|
|
device_class: power
|
|
state_class: measurement
|
|
scale: 1
|
|
scan_interval: 5
|
|
|
|
- name: Inverter battery charge from PV today
|
|
unique_id: d496459e40e0d49f5c11
|
|
slave: 1
|
|
address: 13011
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter battery charge from PV total
|
|
unique_id: d743fb021ad5ffd4eaec
|
|
slave: 1
|
|
address: 13012
|
|
input_type: input
|
|
count: 2
|
|
data_type: uint32
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter direct energy consumption today
|
|
unique_id: 31666be0c3b9c9b1046c
|
|
slave: 1
|
|
address: 13016
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter direct energy consumption total
|
|
unique_id: 1e52906bf8fb43bd584e
|
|
slave: 1
|
|
address: 13017
|
|
input_type: input
|
|
count: 2
|
|
data_type: uint32
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter battery voltage
|
|
unique_id: d847a32343d531d39de9
|
|
slave: 1
|
|
address: 13019
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 0
|
|
unit_of_measurement: V
|
|
device_class: voltage
|
|
state_class: measurement
|
|
scale: 0.1
|
|
scan_interval: 10
|
|
|
|
- name: Inverter battery current
|
|
unique_id: 211c77af04532163e7b0
|
|
slave: 1
|
|
address: 13020
|
|
input_type: input
|
|
count: 1
|
|
# data_type: uint16
|
|
data_type:
|
|
int16 # docs say unsigned but I'm getting overflows when battery is charging
|
|
# changing to int shows negative amperage which makes sense.
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: A
|
|
device_class: current
|
|
state_class: measurement
|
|
scale: 0.1
|
|
scan_interval: 5
|
|
|
|
- name: Inverter battery power (raw)
|
|
unique_id: 4f7dacbf06d004b547d9
|
|
slave: 1
|
|
address: 13021
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 0
|
|
unit_of_measurement: W
|
|
device_class: power
|
|
state_class: measurement
|
|
scale: 1
|
|
scan_interval: 5
|
|
|
|
- name: Inverter battery level
|
|
unique_id: 61e9d0508f0e75a3f25c
|
|
slave: 1
|
|
address: 13022
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: "%"
|
|
device_class: battery
|
|
state_class: measurement
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter battery health
|
|
slave: 1
|
|
address: 13023
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 0
|
|
unit_of_measurement: "%"
|
|
state_class: measurement
|
|
scale: 0.1
|
|
scan_interval: 10
|
|
|
|
- name: Inverter battery temperature
|
|
slave: 1
|
|
address: 13024
|
|
input_type: input
|
|
count: 1
|
|
data_type: int16
|
|
precision: 1
|
|
unit_of_measurement: °C
|
|
device_class: temperature
|
|
state_class: measurement
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter battery discharge today
|
|
unique_id: aa16dda43d9420767429
|
|
slave: 1
|
|
address: 13025
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter battery discharge total
|
|
unique_id: c69ba5e6d4b5233e1d4b
|
|
slave: 1
|
|
address: 13026
|
|
input_type: input
|
|
count: 2
|
|
data_type: uint32
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 10
|
|
|
|
# NOTE: this is broken over modbus and only ever returns 0x00
|
|
# - name: Grid state raw
|
|
# slave: 1
|
|
# address: 13029
|
|
# input_type: input
|
|
# count: 1
|
|
# data_type: uint16
|
|
# swap: word
|
|
# precision: 0
|
|
# scan_interval: 10
|
|
|
|
- name: Inverter imported energy today
|
|
unique_id: b2b294f51055baee4d83
|
|
slave: 1
|
|
address: 13035
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter imported energy total
|
|
unique_id: 3b0efbeb671df362890c
|
|
slave: 1
|
|
address: 13036
|
|
input_type: input
|
|
count: 2
|
|
data_type: uint32
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter battery charge today
|
|
unique_id: 88a0d3dadb8aa103728d
|
|
slave: 1
|
|
address: 13039
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter battery charge total
|
|
unique_id: ac30fabc192dd714df73
|
|
slave: 1
|
|
address: 13040
|
|
input_type: input
|
|
count: 2
|
|
data_type: uint32
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter exported energy today
|
|
unique_id: 68e619a9b5ee8d444486
|
|
slave: 1
|
|
address: 13044
|
|
input_type: input
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter exported energy total
|
|
unique_id: 6a4ef5fdd89be709656a
|
|
slave: 1
|
|
address: 13045
|
|
input_type: input
|
|
count: 2
|
|
data_type: uint32
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: kWh
|
|
device_class: energy
|
|
state_class: total_increasing
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
# # holding registers
|
|
# - name: Inverter Start Stop
|
|
# slave: 1
|
|
# address: 12999 # 13000
|
|
# input_type: holding
|
|
# count: 1
|
|
# data_type: uint16
|
|
# swap: word
|
|
# precision: 0
|
|
# scan_interval: 10
|
|
# - name: EMS Mode Selection raw
|
|
# slave: 1
|
|
# address: 13049 # 13050
|
|
# input_type: holding
|
|
# count: 1
|
|
# data_type: uint16
|
|
# swap: word
|
|
# scan_interval: 10
|
|
# - name: Inverter charge command (raw)
|
|
# unique_id: d1158bbfa40d73933a72
|
|
# slave: 1
|
|
# address: 13050 # 13051
|
|
# input_type: holding
|
|
# count: 1
|
|
# data_type: uint16
|
|
# swap: word
|
|
# precision: 0
|
|
# scan_interval: 60
|
|
|
|
- name: Inverter battery forced charge/discharge power
|
|
slave: 1
|
|
address: 13051 # 13052
|
|
input_type: holding
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 0
|
|
# datasheet says:
|
|
# 0 to 5000 W for SH*K-*
|
|
# 0 to 100 % for SH*.0RT
|
|
# for my SH10RT it is set in W...
|
|
unit_of_measurement: W
|
|
device_class: power
|
|
state_class: measurement
|
|
scan_interval: 10
|
|
|
|
- name: Inverter max SoC
|
|
unique_id: c602a1446bddc9d6fa7a
|
|
slave: 1
|
|
address: 13057 # 13058
|
|
input_type: holding
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: "%"
|
|
device_class: battery
|
|
state_class: measurement
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
- name: Inverter min SoC
|
|
unique_id: 61a08ee663d37248f372
|
|
slave: 1
|
|
address: 13058 # 13059
|
|
input_type: holding
|
|
count: 1
|
|
data_type: uint16
|
|
swap: word
|
|
precision: 1
|
|
unit_of_measurement: "%"
|
|
device_class: battery
|
|
state_class: measurement
|
|
scale: 0.1
|
|
scan_interval: 60
|
|
|
|
# binary_sensor:
|
|
# - platform: template
|
|
# sensors:
|
|
# pv_generating:
|
|
# friendly_name: "PV generating"
|
|
# value_template: "{{ states('sensor.running_state')|int|bitwise_and(0x1) > 0 }}"
|
|
# battery_charging:
|
|
# friendly_name: "Battery charging"
|
|
# value_template: "{{ states('sensor.running_state')|int|bitwise_and(0x2) > 0 }}"
|
|
# battery_discharging:
|
|
# friendly_name: "Battery discharging"
|
|
# value_template: "{{ states('sensor.running_state')|int|bitwise_and(0x4) > 0 }}"
|
|
# exporting_power:
|
|
# friendly_name: "Exporting power"
|
|
# value_template: "{{ states('sensor.running_state')|int|bitwise_and(0x10) > 0 }}"
|
|
# importing_power:
|
|
# friendly_name: "Importing power"
|
|
# value_template: "{{ states('sensor.running_state')|int|bitwise_and(0x20) > 0 }}"
|
|
|
|
# # 'virtual' template sensors for better readability
|
|
sensor:
|
|
- platform: template
|
|
sensors:
|
|
inverter_battery_power:
|
|
unique_id: 7ef0fbbb0d9825b99f35
|
|
friendly_name: Inverter battery power
|
|
value_template: >-
|
|
{% set current = states('sensor.inverter_battery_current') %}
|
|
{% set power = states('sensor.inverter_battery_power_raw') %}
|
|
{% if 'unavailable' in [current, power] %}
|
|
unavailable
|
|
{% elif 'unknown' in [current, power] %}
|
|
unknown
|
|
{% elif current|float < 0.0 and power|float > 0.0 %}
|
|
{{ -1 * power | float }}
|
|
{% else %}
|
|
{{ power | float }}
|
|
{% endif %}
|
|
unit_of_measurement: W
|
|
device_class: power
|
|
inverter_state:
|
|
# Inverter States from modbus reference manual
|
|
friendly_name: "Inverter state"
|
|
value_template: >-
|
|
{% if ((states('sensor.inverter_system_state_raw') | int(default=0)) == 0x0002) %}
|
|
Stop
|
|
{% elif ((states('sensor.inverter_system_state_raw') | int(default=0)) == 0x0008) %}
|
|
Standby
|
|
{% elif ((states('sensor.inverter_system_state_raw') | int(default=0)) == 0x0010) %}
|
|
Initial Standby
|
|
{% elif ((states('sensor.inverter_system_state_raw') | int(default=0)) == 0x0020) %}
|
|
Startup
|
|
{% elif ((states('sensor.inverter_system_state_raw') | int(default=0)) == 0x0040) %}
|
|
Running
|
|
{% elif ((states('sensor.inverter_system_state_raw') | int(default=0)) == 0x0100) %}
|
|
Fault
|
|
{% elif ((states('sensor.inverter_system_state_raw') | int(default=0)) == 0x0400) %}
|
|
Maintain mode
|
|
{% elif ((states('sensor.inverter_system_state_raw') | int(default=0)) == 0x0800) %}
|
|
Forced mode
|
|
{% elif ((states('sensor.inverter_system_state_raw') | int(default=0)) == 0x8200) %}
|
|
Dispatch running {# what even is this? #}
|
|
{% elif ((states('sensor.inverter_system_state_raw') | int(default=0)) == 0x1000) %}
|
|
Off-grid mode
|
|
{% elif ((states('sensor.inverter_system_state_raw') | int(default=0)) == 0x2501) %}
|
|
Restarting
|
|
{% elif ((states('sensor.inverter_system_state_raw') | int(default=0)) == 0x4000) %}
|
|
External EMS mode
|
|
{% else %}
|
|
unknown {#- should not see this #}
|
|
{% endif %}
|
|
|
|
# sungrow_grid_state:
|
|
# friendly_name: "Sungrow Grid State"
|
|
# value_template: >-
|
|
# {% if ((states('sensor.grid_state_raw') | int(default=0)) == 0x00AA) %}
|
|
# Off Grid
|
|
# {% elif ((states('sensor.grid_state_raw') | int(default=0)) == 0x0055) %}
|
|
# On Grid
|
|
# {% else %}
|
|
# Unknown - should not see me!
|
|
# {% endif %}
|
|
|
|
# sungrow_device_type:
|
|
# # device codes from modbus reference manual
|
|
# friendly_name: "Sungrow Device Type"
|
|
# value_template: >-
|
|
# {% if ((states('sensor.sungrow_device_type_code') | int(default=0)) == 0x0D09) %}
|
|
# SH5K-20
|
|
# {% elif ((states('sensor.sungrow_device_type_code') | int(default=0)) == 0x0D06) %}
|
|
# SH3K6
|
|
# {% elif ((states('sensor.sungrow_device_type_code') | int(default=0)) == 0x0D07) %}
|
|
# SH4K6
|
|
# {% elif ((states('sensor.sungrow_device_type_code') | int(default=0)) == 0x0D03) %}
|
|
# SH5K-V13
|
|
# {% elif ((states('sensor.sungrow_device_type_code') | int(default=0)) == 0x0D0C) %}
|
|
# SH5K-30
|
|
# {% elif ((states('sensor.sungrow_device_type_code') | int(default=0)) == 0x0D0A) %}
|
|
# SH3K6-30
|
|
# {% elif ((states('sensor.sungrow_device_type_code') | int(default=0)) == 0x0D0B) %}
|
|
# SH4K6-30
|
|
# {% elif ((states('sensor.sungrow_device_type_code') | int(default=0)) == 0x0D0F) %}
|
|
# SH5.0RS
|
|
# {% elif ((states('sensor.sungrow_device_type_code') | int(default=0)) == 0x0D0D) %}
|
|
# SH3.6RS
|
|
# {% elif ((states('sensor.sungrow_device_type_code') | int(default=0)) == 0x0D0E) %}
|
|
# SH4.6RS
|
|
# {% elif ((states('sensor.sungrow_device_type_code') | int(default=0)) == 0x0D10) %}
|
|
# SH6.0RS
|
|
# {% elif ((states('sensor.sungrow_device_type_code') | int(default=0)) == 0x0E03) %}
|
|
# SH10RT
|
|
# {% elif ((states('sensor.sungrow_device_type_code') | int(default=0)) == 0x0E02) %}
|
|
# SH8.0RT
|
|
# {% elif ((states('sensor.sungrow_device_type_code') | int(default=0)) == 0x0E01) %}
|
|
# SH6.0RT
|
|
# {% elif ((states('sensor.sungrow_device_type_code') | int(default=0)) == 0x0E00) %}
|
|
# SH5.0RT
|
|
# {% else %}
|
|
# Unknown device code!
|
|
# {% endif %}
|
|
|
|
# # make the sensor battery_charge_discharge_cmd more human readable
|
|
# sungrow_battery_charge_discharge_cmd:
|
|
# # Inverter States from modbus reference manual
|
|
# # 0xAA (170) Force charge
|
|
# # 0xBB (187) Force discharge
|
|
# # 0xCC (204) Stop (Default)
|
|
# # don't know how to compare the integer values in hexadecimal format in following decoder statement...
|
|
# friendly_name: "Battery Charge Discharge Cmd"
|
|
# value_template: >-
|
|
# {% if ((states('sensor.battery_charge_discharge_cmd_raw') | int(default=0)) == 0x00AA) %}
|
|
# Force charge
|
|
# {% elif ((states('sensor.battery_charge_discharge_cmd_raw') | int(default=0)) == 0x00BB) %}
|
|
# Force discharge
|
|
# {% elif ((states('sensor.battery_charge_discharge_cmd_raw') | int(default=0)) == 0x00CC) %}
|
|
# Stop (Default)
|
|
# {% else %}
|
|
# Unknown - should not see me!
|
|
# {% endif %}
|
|
|
|
# # make the sensor ems_selection_raw more human readable
|
|
# sungrow_ems_mode_selection:
|
|
# friendly_name: "EMS Mode Selection"
|
|
# value_template: >-
|
|
# {% if ((states('sensor.ems_mode_selection_raw') | int(default=0)) == 0) %}
|
|
# Self-consumption mode (default)
|
|
# {% elif ((states('sensor.ems_mode_selection_raw') | int(default=0)) == 2) %}
|
|
# Forced mode
|
|
# {% elif ((states('sensor.ems_mode_selection_raw') | int(default=0)) == 3) %}
|
|
# External EMS
|
|
# {% elif ((states('sensor.ems_mode_selection_raw') | int(default=0)) == 4) %}
|
|
# VPP
|
|
# {% else %}
|
|
# Unknown - should not see me!
|
|
# {% endif %}
|
|
|
|
# # getting input for Min and Max SoC
|
|
# input_number:
|
|
# set_sg_min_soc:
|
|
# name: min Soc
|
|
# #initial: 15
|
|
# min: 5
|
|
# max: 50
|
|
# step: 1
|
|
|
|
# set_sg_max_soc:
|
|
# name: max Soc
|
|
# #initial: 85
|
|
# min: 50
|
|
# max: 95
|
|
# step: 1
|
|
|
|
# set_sg_charge_discharge_power_percentage:
|
|
# name: max charge discharge power in W
|
|
# #initial: 40
|
|
# min: 0
|
|
# max: 5000
|
|
# step: 50
|
|
|
|
# input_select:
|
|
# set_sg_start_stop_mode:
|
|
# name: Inverter mode
|
|
# options:
|
|
# - "Start"
|
|
# - "Stop"
|
|
|
|
# # get input for battery mode (forced charge/discharge, stop (default) )
|
|
# set_sg_ems_mode:
|
|
# name: EMS mode
|
|
# options:
|
|
# - "Self-consumption mode (default)"
|
|
# - "Forced mode"
|
|
# - "External EMS"
|
|
# - "VPP"
|
|
# icon: mdi:battery-unknown
|
|
|
|
# set_sg_battery_charge_discharge_cmd:
|
|
# name: Battery charge discharge cmd
|
|
# options:
|
|
# - "Stop (default)"
|
|
# - "Force charge"
|
|
# - "Force discharge"
|
|
# icon: mdi:battery-unknown
|
|
|
|
# # Automation: Write modbus registers on input changes via GUI
|
|
|
|
# # note: If you change a value by the sliders, it will take up to 60 seconds until the state variables are updated
|
|
# # Unfortunately, I could not find a way to "force update" modbus registers, yet...
|
|
# automation:
|
|
|
|
# # Start 0xCF = 207
|
|
# # Stop 0xCE = 206
|
|
# # Todo I want to use hexadecimal format to write values!?
|
|
# - id: "24334413543545" # random number
|
|
# alias: start stop
|
|
# description: "Starts/ Stops the inverter"
|
|
# trigger:
|
|
# - platform: state
|
|
# entity_id:
|
|
# - input_select.set_sg_start_stop_mode
|
|
# condition: []
|
|
# action:
|
|
# - service: modbus.write_register
|
|
# data_template:
|
|
# address: 12999 # 13000
|
|
# slave: 1
|
|
# value: "{% if is_state('input_select.set_sg_start_stop_mode' , 'Start') %} 207
|
|
# {% else %} 206 {% endif %}"
|
|
# hub: SungrowSHx
|
|
# mode: single
|
|
|
|
# - id: "24321413543543" # random number
|
|
# alias: update max SoC
|
|
# description: "Updates Sungrow max Soc holding register"
|
|
# trigger:
|
|
# - platform: state
|
|
# entity_id:
|
|
# - input_number.set_sg_max_soc
|
|
# condition: []
|
|
# action:
|
|
# - service: modbus.write_register
|
|
# data_template:
|
|
# address: 13057 # 13058
|
|
# slave: 1
|
|
# value: "{{ states('input_number.set_sg_max_soc') | int *10}}"
|
|
# hub: SungrowSHx
|
|
# mode: single
|
|
|
|
# - id: "24321413543545" # random number
|
|
# alias: update min SoC
|
|
# description: "Updates Sungrow min Soc holding register"
|
|
# trigger:
|
|
# - platform: state
|
|
# entity_id:
|
|
# - input_number.set_sg_min_soc
|
|
# condition: []
|
|
# action:
|
|
# - service: modbus.write_register
|
|
# data_template:
|
|
# address: 13058 # 13059
|
|
# slave: 1
|
|
# value: "{{ states('input_number.set_sg_min_soc') | int *10}}"
|
|
# hub: SungrowSHx
|
|
# mode: single
|
|
|
|
# - id: "24321413553543" # random number
|
|
# alias: update battery charge discharge cmd
|
|
# description: "Updates Sungrow holding register for battery charge discharge command"
|
|
# trigger:
|
|
# - platform: state
|
|
# entity_id:
|
|
# - input_select.set_sg_battery_charge_discharge_cmd
|
|
# condition: []
|
|
# action:
|
|
# - service: modbus.write_register
|
|
# data_template:
|
|
# address: 13050 # 13051
|
|
# slave: 1
|
|
# # 0xAA: 170 Charge
|
|
# # 0xBB: 187 Discharge
|
|
# # 0xCC: 204 Stop (Default)
|
|
# # don't know how to compare the integer values in hexadecimal format in following decoder statement...
|
|
# value: "{% if is_state('input_select.set_sg_battery_charge_discharge_cmd' , 'Stop (default)') %} 204
|
|
# {% elif is_state('input_select.set_sg_battery_charge_discharge_cmd' , 'Force charge') %} 170
|
|
# {% elif is_state('input_select.set_sg_battery_charge_discharge_cmd' , 'Force discharge') %} 187
|
|
# {% else %} 204 {% endif %}"
|
|
# hub: SungrowSHx
|
|
# mode: single
|
|
|
|
# - id: "24323313553543" # random number
|
|
# alias: update EMS mode
|
|
# description: "Updates EMS mode"
|
|
# trigger:
|
|
# - platform: state
|
|
# entity_id:
|
|
# - input_select.set_sg_ems_mode
|
|
# condition: []
|
|
# action:
|
|
# - service: modbus.write_register
|
|
# data_template:
|
|
# address: 13049 # 13050
|
|
# slave: 1
|
|
# # 0: Self-consumption mode (Default)
|
|
# # 1: entry does not exist
|
|
# # 2: Forced Mode
|
|
# # 3: External EMS
|
|
# # 4: VPP
|
|
# # don't know how to compare the integer values in hexadecimal format in following decoder statement...
|
|
# value: "{% if is_state('input_select.set_sg_ems_mode' , 'Self-consumption mode (default)') %} 0
|
|
# {% elif is_state('input_select.set_sg_ems_mode' , 'Forced mode') %} 2
|
|
# {% elif is_state('input_select.set_sg_ems_mode' , 'External EMS') %} 3
|
|
# {% elif is_state('input_select.set_sg_ems_mode' , 'VPP') %} 4
|
|
# {% else %} 0 {% endif %}"
|
|
# hub: SungrowSHx
|
|
# mode: single
|
|
|
|
# - id: "24321413543521" # random number
|
|
# alias: "update max charge discharge power percent"
|
|
# description: "Sets max charge discharge power in % of BDC rated power"
|
|
# trigger:
|
|
# - platform: state
|
|
# entity_id:
|
|
# - input_number.set_sg_charge_discharge_power_percentage
|
|
# condition: []
|
|
# action:
|
|
# - service: modbus.write_register
|
|
# data_template:
|
|
# address: 13051 # 13052
|
|
# slave: 1
|
|
# value: "{{ states('input_number.set_sg_charge_discharge_power_percentage') | int}}"
|
|
# hub: SungrowSHx
|
|
# mode: single
|