# Home Assistant Sungrow wallbox integration # https://github.com/Louisbertelsmann/Sungrow-Wallbox-Modbus-HomeAssistant # by Louis Bertelsmann # last update: 2024-07-24 modbus: - name: SungrowACx type: tcp host: !secret wallbox_modbus_host_ip port: !secret wallbox_modbus_port sensors: - name: Wallbox device type code unique_id: wb1_dev_number_raw slave: !secret wallbox_modbus_slave address: 21223 # reg 21224 input_type: input data_type: uint16 scan_interval: 600 - name: Power phases unique_id: wb1_power_phases slave: !secret wallbox_modbus_slave address: 21224 # reg 21225 input_type: input data_type: uint16 scan_interval: 600 - name: Rated voltage unique_id: wb1_rated_voltage slave: !secret wallbox_modbus_slave address: 21261 # reg 21262 input_type: input data_type: uint16 unit_of_measurement: V device_class: Voltage scan_interval: 600 - name: Phase switching status Raw unique_id: wb1_phase_switching_status_raw slave: !secret wallbox_modbus_slave address: 21269 # reg 21270 input_type: input data_type: uint16 scan_interval: 60 - name: Minimum charging power unique_id: wb1_minimum_charging_power slave: !secret wallbox_modbus_slave address: 21271 # reg 21272 input_type: input data_type: uint16 precision: 1 unit_of_measurement: W device_class: Power scale: 1 scan_interval: 60 - name: Maximum charging power unique_id: wb1_maximum_charging_power slave: !secret wallbox_modbus_slave address: 21272 # reg 21273 input_type: input data_type: uint16 precision: 1 unit_of_measurement: W device_class: Power scale: 1 scan_interval: 60 - name: Total energy unique_id: wb1_total_energy slave: !secret wallbox_modbus_slave address: 21299 # reg 21300 input_type: input data_type: uint32 precision: 1 unit_of_measurement: Wh state_class: total_increasing device_class: Energy scale: 1 swap: word scan_interval: 600 - name: Phase A charging voltage unique_id: wb1_phase_a_charging_voltage slave: !secret wallbox_modbus_slave address: 21301 # reg 21302 input_type: input data_type: uint16 unit_of_measurement: V device_class: Voltage scale: 0.1 scan_interval: 600 - name: Phase A charging current unique_id: wb1_phase_a_charging_current slave: !secret wallbox_modbus_slave address: 21302 # reg 21303 input_type: input data_type: uint16 unit_of_measurement: A device_class: Current state_class: measurement scale: 0.1 scan_interval: 600 - name: Phase B charging voltage unique_id: wb1_phase_b_charging_voltage slave: !secret wallbox_modbus_slave address: 21303 # reg: 21304 input_type: input data_type: uint16 unit_of_measurement: V device_class: Voltage state_class: measurement scale: 0.1 scan_interval: 600 - name: Phase B charging current unique_id: wb1_phase_b_charging_current slave: !secret wallbox_modbus_slave address: 21304 # reg: 21305 input_type: input data_type: uint16 unit_of_measurement: A device_class: Current state_class: measurement scale: 0.1 scan_interval: 600 - name: Phase C charging voltage unique_id: wb1_phase_c_charging_voltage slave: !secret wallbox_modbus_slave address: 21305 # reg: 21306 input_type: input data_type: uint16 unit_of_measurement: V device_class: Voltage state_class: measurement scale: 0.1 scan_interval: 600 - name: Phase C charging current unique_id: wb1_phase_c_charging_current slave: !secret wallbox_modbus_slave address: 21306 # reg 21307 input_type: input data_type: uint16 unit_of_measurement: A device_class: Current state_class: measurement scale: 0.1 scan_interval: 600 - name: Charging power unique_id: wb1_charging_power slave: !secret wallbox_modbus_slave address: 21307 # reg 21308 input_type: input data_type: uint32 unit_of_measurement: W device_class: power state_class: measurement swap: word scan_interval: 600 - name: Charging energy unique_id: wb1_charging_energy slave: !secret wallbox_modbus_slave address: 21309 # reg 21310 input_type: input data_type: uint32 unit_of_measurement: Wh device_class: Energy scale: 1 swap: word scan_interval: 600 - name: Charging status Raw unique_id: wb1_charging_status slave: !secret wallbox_modbus_slave address: 21316 # reg 21317 input_type: input data_type: uint16 scan_interval: 10 - name: Charging start time Raw unique_id: wb1_charging_start_time_raw slave: !secret wallbox_modbus_slave address: 21317 # reg 21318 input_type: input data_type: uint32 swap: word scan_interval: 600 - name: Charging end time Raw unique_id: wb1_charging_end_time_raw slave: !secret wallbox_modbus_slave address: 21319 # reg 21320 input_type: input data_type: uint32 swap: word scan_interval: 600 - name: Start mode Raw unique_id: wb1_start_mode_raw slave: !secret wallbox_modbus_slave address: 21313 input_type: input data_type: uint16 scan_interval: 600 ##################### # holding registers ##################### - name: Output current setting unique_id: wb1_output_current_setting slave: !secret wallbox_modbus_slave address: 21202 # reg 21203 input_type: holding data_type: uint16 scale: 0.1 unit_of_measurement: A scan_interval: 600 - name: Single phase/Three phase switching unique_id: wb1_phase_switching slave: !secret wallbox_modbus_slave address: 21203 # reg 21204 input_type: holding data_type: uint16 scan_interval: 60 - name: Charger enable raw unique_id: wb1_charger_enable_raw slave: !secret wallbox_modbus_slave address: 21210 # reg 21211 input_type: holding data_type: uint16 scan_interval: 60 - name: Remote control unique_id: wb1_remote_control slave: !secret wallbox_modbus_slave address: 21211 # reg 21212 input_type: holding data_type: uint16 scan_interval: 60 - name: Mileage per kWh unique_id: wb1_mile_per_kwh slave: !secret wallbox_modbus_slave address: 21231 # reg 21232 input_type: holding data_type: uint16 unit_of_measurement: km/kWh precision: 1 scale: 0.1 scan_interval: 60 - name: Working mode unique_id: wb1_working_mode slave: !secret wallbox_modbus_slave address: 21262 # reg 21263 input_type: holding data_type: uint16 scan_interval: 600 template: - sensor: - name: Charging start time unique_id: wb1_charging_start_time state: > {{ as_datetime(states.sensor.charging_start_time_raw.state).strftime("%d.%m.%Y %H:%M") }} - name: Charging end time unique_id: wb1_charging_end_time state: > {{ as_datetime(states.sensor.charging_end_time_raw.state).strftime("%d.%m.%Y %H:%M") }} - name: Charging duration unique_id: wb1_charging_duration state: > {{ as_datetime(states.sensor.charging_end_time_raw.state) - as_datetime(states.sensor.charging_start_time_raw.state) }} - name: Charged range unique_id: wb1_charged_range state: > {{ (((states.sensor.charging_energy.state | int) * (states.sensor.mileage_per_kwh.state | int) / 1000) | round(1))}} km - name: Wallbox device type unique_id: wb1_device_type availability: "{{states('sensor.wallbox_device_type_code')|is_number}}" state: >- {% if ((states('sensor.wallbox_device_type_code') | int(default=0)) == 0x20ED) %} AC007-00 {% elif ((states('sensor.wallbox_device_type_code') | int(default=0)) == 0x20DA) %} AC011E-01 {% else %} Unknown device code! {% endif %} - name: Wallbox working mode unique_id: wb1_working_mode availability: "{{states('sensor.working_mode')|is_number}}" state: >- {% if ((states('sensor.working_mode') | int(default=0)) == 0) %} Network {% elif ((states('sensor.working_mode') | int(default=0)) == 2) %} Plug and Play {% elif ((states('sensor.working_mode') | int(default=0)) == 6) %} EMS {% else %} Unknown working mode! {% endif %} - name: Phase switching status unique_id: wb1_phase_switching_status availability: "{{states('sensor.phase_switching_status_raw')|is_number}}" state: >- {% if ((states('sensor.phase_switching_status_raw') | int(default=0)) == 0) %} Three phase {% elif ((states('sensor.phase_switching_status_raw') | int(default=0)) == 1) %} Single phase {% else %} Unknown phase switching status! {% endif %} - name: Charging status unique_id: wb1_charging_status availability: "{{states('sensor.charging_status_raw')|is_number}}" state: >- {% if ((states('sensor.charging_status_raw') | int(default=0)) == 1) %} Idle {% elif ((states('sensor.charging_status_raw') | int(default=0)) == 2) %} Standby {% elif ((states('sensor.charging_status_raw') | int(default=0)) == 3) %} Charging {% elif ((states('sensor.charging_status_raw') | int(default=0)) == 4) %} Charging is suspended (pile side) {% elif ((states('sensor.charging_status_raw') | int(default=0)) == 5) %} Charging is suspended (vehicle side) {% elif ((states('sensor.charging_status_raw') | int(default=0)) == 6) %} Charging is completed {% elif ((states('sensor.charging_status_raw') | int(default=0)) == 7) %} Reserved {% elif ((states('sensor.charging_status_raw') | int(default=0)) == 8) %} Disabled {% elif ((states('sensor.charging_status_raw') | int(default=0)) == 9) %} Fault {% else %} Unknown charging status! {% endif %} - name: Start mode unique_id: wb1_start_mode availability: "{{states('sensor.start_mode_raw')|is_number}}" state: >- {% if ((states('sensor.start_mode_raw') | int(default=0)) == 0) %} Stopped {% elif ((states('sensor.start_mode_raw') | int(default=0)) == 1) %} Start with EMS {% elif ((states('sensor.start_mode_raw') | int(default=0)) == 2) %} Start by swiping {% else %} Unknown start mode! {% endif %} - name: Charger enable unique_id: wb1_charger_enable availability: "{{states('sensor.charger_enable_raw')|is_number}}" state: >- {% if ((states('sensor.charger_enable_raw') | int(default=0)) == 0) %} Disabled {% elif ((states('sensor.charger_enable_raw') | int(default=0)) == 1) %} Enabled {% else %} Unknown charger enable mode! {% endif %} input_number: set_wb1_output_current: name: Set output current min: 6 max: 63 initial: 16 step: 0.1 set_wb1_mileage_per_kwh: name: Set mileage per kwh min: 1 max: 500 mode: box step: 0.1 input_select: set_wb_phase_switch: name: Phase switch options: - "Three phase" - "Single phase" set_wb_charger_enable: name: Charger enable options: - "Disabled" - "Enabled" set_wb_working_mode: name: Working mode options: - "Network" - "Plug and Play" - "EMS" input_button: wb_start_charging: name: Start charging icon: mdi:play wb_stop_charging: name: Stop charging icon: mdi:stop automation: - id: "automation_wallbox_output_current" alias: "wallbox output current" description: "Sets the maximum output current of the wallbox" trigger: - platform: state entity_id: - input_number.set_wb1_output_current condition: - condition: template value_template: >- {{ states('input_number.set_wb1_output_current') | float != states('sensor.output_current_setting') | float }} action: - service: modbus.write_register data_template: hub: SungrowACx slave: !secret wallbox_modbus_slave address: 21202 # reg 21203 value: "{{ (states('input_number.set_wb1_output_current') | int) * 10 }}" - delay: hours: 0 minutes: 0 seconds: 10 milliseconds: 0 - service: homeassistant.update_entity data: {} target: entity_id: sensor.output_current_setting mode: single - id: "automation_wallbox_output_current_update" alias: "wallbox output current update" description: "Sets the maximum output current of the wallbox update" trigger: - platform: homeassistant event: start - platform: state entity_id: - sensor.output_current_setting condition: - condition: template value_template: "{{ not is_state('sensor.output_current_setting', 'unavailable') }}" action: - service: input_number.set_value target: entity_id: input_number.set_wb1_output_current data: value: "{{ states('sensor.output_current_setting') }}" mode: single - id: "automation_mileage_per_kwh" alias: "wallbox mileage per kwh" description: "Sets mileage per kWh" trigger: - platform: state entity_id: - input_number.set_wb1_mileage_per_kwh condition: - condition: template value_template: >- {{ states('input_number.set_wb1_mileage_per_kwh') | float != states('sensor.mileage_per_kwh') | float }} action: - service: modbus.write_register data_template: hub: SungrowACx slave: !secret wallbox_modbus_slave address: 21231 # reg 21232 value: "{{ ((states('input_number.set_wb1_mileage_per_kwh') | float ) * 10) | int }}" - delay: hours: 0 minutes: 0 seconds: 10 milliseconds: 0 - service: homeassistant.update_entity data: {} target: entity_id: sensor.mileage_per_kwh mode: single - id: "automation_mileage_per_kwh_update" alias: "wallbox mileage per kwh update" description: "Sets mileage per kWh update" trigger: - platform: homeassistant event: start - platform: state entity_id: - sensor.mileage_per_kwh condition: - condition: template value_template: "{{ not is_state('sensor.mileage_per_kwh', 'unavailable') }}" action: - service: input_number.set_value target: entity_id: input_number.set_wb1_mileage_per_kwh data: value: "{{ states('sensor.mileage_per_kwh') }}" mode: single - id: "automation_wallbox_change_phase_switch_cmd" alias: "wallbox change phase switch cmd" description: "Switch wallbox operation mode between Single- and Three-phase mode" trigger: - platform: state entity_id: - input_select.set_wb_phase_switch condition: - condition: template value_template: >- {{ states('input_select.set_wb_phase_switch') != states('sensor.phase_switching_status') }} variables: three_phase: 0 single_phase: 1 action: - service: modbus.write_register data_template: hub: SungrowACx slave: !secret wallbox_modbus_slave address: 21203 # reg 21204 value: > {% if is_state('input_select.set_wb_phase_switch', "Three phase") %} {{three_phase}} {% elif is_state('input_select.set_wb_phase_switch', "Single phase") %} {{single_phase}} {% endif %} - delay: hours: 0 minutes: 0 seconds: 10 milliseconds: 0 - service: homeassistant.update_entity data: {} target: entity_id: sensor.single_phase_three_phase_switching mode: single - id: "automation_wallbox_change_phase_switch_cmd_update" alias: "wallbox change phase switch cmd update" description: "Switch wallbox operation mode between Single- and Three-phase mode update" trigger: - platform: homeassistant event: start - platform: state entity_id: - sensor.single_phase_three_phase_switching condition: - condition: template value_template: "{{ not is_state('sensor.single_phase_three_phase_switching', 'unavailable') }}" action: - service: input_select.select_option target: entity_id: input_select.set_wb_phase_switch data: option: "{{ states('sensor.phase_switching_status') }}" mode: single - id: "automation_wallbox_charger_enable_cmd" alias: "wallbox charger enable cmd" description: "Switch wallbox operation mode between enabled and disabled" trigger: - platform: state entity_id: - input_select.set_wb_charger_enable condition: - condition: template value_template: >- {{ states('input_select.set_wb_charger_enable') != states('sensor.charger_enable') }} variables: disable: 0 enable: 1 action: - service: modbus.write_register data_template: hub: SungrowACx slave: !secret wallbox_modbus_slave address: 21210 # reg 21211 value: > {% if is_state('input_select.set_wb_charger_enable', "Disable") %} {{disable}} {% elif is_state('input_select.set_wb_charger_enable', "Enable") %} {{enable}} {% endif %} - delay: hours: 0 minutes: 0 seconds: 10 milliseconds: 0 - service: homeassistant.update_entity data: {} target: entity_id: sensor.charger_enable mode: single - id: "automation_wallbox_charger_enable_cmd_update" alias: "wallbox charger enable cmd update" description: "Switch wallbox operation mode between enabled and disabled update" trigger: - platform: homeassistant event: start - platform: state entity_id: - sensor.charger_enable_raw condition: - condition: template value_template: "{{ not is_state('sensor.charger_enable', 'unavailable') }}" action: - service: input_select.select_option target: entity_id: input_select.set_wb_charger_enable data: option: "{{ states('sensor.charger_enable') }}" mode: single - id: "automation_wallbox_start_charging" alias: "wallbox charger start remote control cmd" description: "Remote control wallbox" trigger: - platform: state entity_id: - input_button.wb_start_charging condition: [] variables: start_charging: 0 stop_charging: 1 action: - service: modbus.write_register data_template: hub: SungrowACx slave: !secret wallbox_modbus_slave address: 21211 # reg 21212 value: > {{start_charging}} mode: single - id: "automation_wallbox_stop_charging" alias: "wallbox charger stop remote control cmd" description: "Remote control wallbox" trigger: - platform: state entity_id: - input_button.wb_stop_charging condition: [] variables: start_charging: 0 stop_charging: 1 action: - service: modbus.write_register data_template: hub: SungrowACx slave: !secret wallbox_modbus_slave address: 21211 # reg 21212 value: > {{stop_charging}} mode: single - id: "automation_wallbox_set_wb_working_mode" alias: "wallbox set working mode" description: "Set wallbox working mode" trigger: - platform: state entity_id: - input_select.set_wb_working_mode condition: - condition: template value_template: >- {{ states('input_select.set_wb_working_mode') != states('sensor.wallbox_working_mode') }} variables: network: 0 plug_and_play: 2 ems: 6 action: - service: modbus.write_register data_template: hub: SungrowACx slave: !secret wallbox_modbus_slave address: 21262 # reg 21263 value: > {% if is_state('input_select.set_wb_working_mode', "Network") %} {{network}} {% elif is_state('input_select.set_wb_working_mode', "Plug and Play") %} {{plug_and_play}} {% elif is_state('input_select.set_wb_working_mode', "EMS") %} {{ems}} {% endif %} - delay: hours: 0 minutes: 0 seconds: 10 milliseconds: 0 - service: homeassistant.update_entity data: {} target: entity_id: sensor.working_mode mode: single - id: "automation_wallbox_set_wb_working_mode_update" alias: "wallbox set working mode update" description: "Set wallbox working mode update" trigger: - platform: homeassistant event: start - platform: state entity_id: - sensor.working_mode condition: - condition: template value_template: "{{ not is_state('sensor.working_mode', 'unavailable') }}" action: - service: input_select.select_option target: entity_id: input_select.set_wb_working_mode data: option: "{{ states('sensor.wallbox_working_mode') }}" mode: single - id: "automation_fast_update_while_charging" alias: automation_fast_update_while_charging description: Update relevant entities for charging every 10sec and not just every hour trigger: - platform: state entity_id: - sensor.charging_status_raw to: "3" condition: [] action: - service: homeassistant.update_entity data: {} target: entity_id: sensor.charging_start_time_raw - repeat: sequence: - service: homeassistant.update_entity data: {} target: entity_id: - sensor.charging_power - sensor.phase_a_charging_current - sensor.phase_a_charging_voltage - sensor.phase_b_charging_current - sensor.phase_b_charging_voltage - sensor.phase_c_charging_current - sensor.phase_c_charging_voltage - sensor.output_current_setting - sensor.charging_energy - sensor.charging_end_time_raw - sensor.total_energy - delay: hours: 0 minutes: 0 seconds: 10 milliseconds: 0 while: - condition: state entity_id: sensor.charging_status_raw state: "3" mode: single