Solar Panels
The main code used for the solar system comes from two devices
SolaX Inveters
The invertors are queried using REST and return a JSON package POSTMAN has been pre-configured to do the same queries
######################################################### # # # SOLAX CLOUD Rear Unit # # # ######################################################### #sensors: - platform: rest scan_interval: 150 resource: https://www.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=20210515090442704400044&sn=SWNBESA3MD name: "rear solax" json_attributes_path: "$.result" json_attributes: - yieldtoday - yieldtotal - acpower - uploadTime - inverterStatus - powerdc1 value_template: "1" # dummy value, not used; avoids the "State max length is 255 characters" error - platform: template sensors: rear_solax_today: friendly_name: "Rear Solax today" value_template: "{{ state_attr('sensor.rear_solax', 'yieldtoday') }}" unit_of_measurement: "KWh" rear_solax_total: friendly_name: "Rear Solax total" value_template: "{{ state_attr('sensor.rear_solax', 'yieldtotal') }}" unit_of_measurement: "KWh" rear_solax_now: friendly_name: "Rear Solax now" value_template: "{{ state_attr('sensor.rear_solax', 'acpower') }}" unit_of_measurement: "W" rear_solax_dc_now: friendly_name: "Rear Solax DC now" value_template: "{{ state_attr('sensor.rear_solax', 'powerdc1') }}" unit_of_measurement: "W" rear_solax_upload_time: friendly_name: "Rear Solax upload time" value_template: "{{ state_attr('sensor.rear_solax', 'uploadTime') }}" rear_solax_status: friendly_name: "Rear Solax status" value_template: > {% if state_attr('sensor.rear_solax', 'inverterStatus') == '100' %}Wait {% elif state_attr('sensor.rear_solax', 'inverterStatus') == '101' %}Check {% elif state_attr('sensor.rear_solax', 'inverterStatus') == '102' %}Normal {% elif state_attr('sensor.rear_solax', 'inverterStatus') == '103' %}Fault {% elif state_attr('sensor.rear_solax', 'inverterStatus') == '104' %}Permanent Fault {% elif state_attr('sensor.rear_solax', 'inverterStatus') == '105' %}Update {% elif state_attr('sensor.rear_solax', 'inverterStatus') == '106' %}EPS Check {% elif state_attr('sensor.rear_solax', 'inverterStatus') == '107' %}EPS {% elif state_attr('sensor.rear_solax', 'inverterStatus') == '108' %}Self-test {% elif state_attr('sensor.rear_solax', 'inverterStatus') == '109' %}Idle {% elif state_attr('sensor.rear_solax', 'inverterStatus') == '110' %}Standby {% elif state_attr('sensor.rear_solax', 'inverterStatus') == '111' %}Pv Wake Up Bat {% elif state_attr('sensor.rear_solax', 'inverterStatus') == '112' %}Gen Check {% elif state_attr('sensor.rear_solax', 'inverterStatus') == '113' %}Gen Run {% else %}I dont know{% endif %} ######################################################### # # # SOLAX CLOUD Street Unit # # # ######################################################### - platform: rest scan_interval: 150 resource: https://www.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=20210515090442704400044&sn=SWNUHG6EEP name: "street solax" json_attributes_path: "$.result" json_attributes: - yieldtoday - yieldtotal - acpower - uploadTime - inverterStatus - powerdc1 value_template: "1" # dummy value, not used; avoids the "State max length is 255 characters" error - platform: template sensors: street_solax_today: friendly_name: "Street Solax today" value_template: "{{ state_attr('sensor.street_solax', 'yieldtoday') }}" unit_of_measurement: "KWh" street_solax_total: friendly_name: "Street Solax total" value_template: "{{ state_attr('sensor.street_solax', 'yieldtotal') }}" unit_of_measurement: "KWh" street_solax_now: friendly_name: "Street Solax now" value_template: "{{ state_attr('sensor.street_solax', 'acpower') }}" unit_of_measurement: "W" street_solax_dc_now: friendly_name: "Street Solax DC now" value_template: "{{ state_attr('sensor.street_solax', 'powerdc1') }}" unit_of_measurement: "W" street_solax_upload_time: friendly_name: "Street Solax upload time" value_template: "{{ state_attr('sensor.street_solax', 'uploadTime') }}" street_solax_status: friendly_name: "Street Solax status" value_template: > {% if state_attr('sensor.street_solax', 'inverterStatus') == '100' %}Wait {% elif state_attr('sensor.street_solax', 'inverterStatus') == '101' %}Check {% elif state_attr('sensor.street_solax', 'inverterStatus') == '102' %}Normal {% elif state_attr('sensor.street_solax', 'inverterStatus') == '103' %}Fault {% elif state_attr('sensor.street_solax', 'inverterStatus') == '104' %}Permanent Fault {% elif state_attr('sensor.street_solax', 'inverterStatus') == '105' %}Update {% elif state_attr('sensor.street_solax', 'inverterStatus') == '106' %}EPS Check {% elif state_attr('sensor.street_solax', 'inverterStatus') == '107' %}EPS {% elif state_attr('sensor.street_solax', 'inverterStatus') == '108' %}Self-test {% elif state_attr('sensor.street_solax', 'inverterStatus') == '109' %}Idle {% elif state_attr('sensor.street_solax', 'inverterStatus') == '110' %}Standby {% elif state_attr('sensor.street_solax', 'inverterStatus') == '111' %}Pv Wake Up Bat {% elif state_attr('sensor.street_solax', 'inverterStatus') == '112' %}Gen Check {% elif state_attr('sensor.street_solax', 'inverterStatus') == '113' %}Gen Run {% else %}I dont know{% endif %} ######################################################### # # # SOLAX CLOUD Combined # # # ######################################################### - platform: template sensors: pv_now: friendly_name: "PV Now" unit_of_measurement: W value_template: "{{ (states('sensor.rear_solax_now')|int + states('sensor.street_solax_now')| int) }}" icon_template: mdi:power-socket-de device_class: power pv_today: friendly_name: "PV Today" unit_of_measurement: "kWh" value_template: "{{ (states('sensor.rear_solax_today')|int + states('sensor.street_solax_today')|int) }}" icon_template: mdi:solar-panel pv_total: friendly_name: "PV Total" unit_of_measurement: kWh value_template: "{{ (states('sensor.rear_solax_total')|int + states('sensor.street_solax_total')|int) }}" icon_template: mdi:chart-line phev_charging_a: value_template: "{{ (states('sensor.meter_power_c')|int - states('sensor.meter_power_b')| int + states('sensor.meter_power_a')| int) }}" phev_charging: friendly_name: "Power to PHEV" unit_of_measurement: 'W' device_class: power value_template: > {% if states('sensor.phev_charging_a')|int < 20 %} 0 {% else %} {{ (states('sensor.phev_charging_a')|int|abs )}} {% endif %}
Iammeter
This three phase device has its own native integration into Home Assistant
- Phase A = Power from/to the grid +ive is from the grid and -ive is power sent to the grid
- Phase B = The house meter board, so all power consumption except the SolaX's them selves and the EV Charger
- Phase C = Solar generation. Should be the same as sensor.pv_now from the calculation above
############################### # # # Power Monitor # # # ############################### - platform: iammeter host: 192.168.1.116 name: meter - platform: template sensors: phev_charging: unit_of_measurement: "w" value_template: > {% if (states('sensor.meter_power_c')|int + states('sensor.meter_power_a')| int - states('sensor.meter_power_b')| int) >500 %} {{ states('sensor.meter_power_c')|int + states('sensor.meter_power_a')| int - states('sensor.meter_power_b')| int }} {% else %} 0 {% endif %} phev_amps: unit_of_measurement: "A" value_template: > {{ (((states('sensor.phev_charging')|float ) / (states('sensor.meter_voltage_a')|float)) | round(2)) }} grid_consumption: friendly_name: "Power from Grid" unit_of_measurement: "W" device_class: power value_template: > {% if states('sensor.meter_power_a')|int > 0 %} {{ states('sensor.meter_power_a')|int }} {% else %} 0 {% endif %} grid_feed_in: friendly_name: "Power to Grid" unit_of_measurement: "W" device_class: power value_template: > {% if states('sensor.meter_power_a')|int < 0 %} {{ (states('sensor.meter_power_a')|int|abs )}} {% else %} 0 {% endif %} generation_to_house: friendly_name: "Solar to house" unit_of_measurement: "W" device_class: power value_template: > {% if states('sensor.grid_consumption')|int > 0 %} {{ (states('sensor.meter_power_b')|int + states('sensor.phev_charging')| int - states('sensor.grid_consumption')| int) }} {% else %} {{ (states('sensor.meter_power_c')|int - states('sensor.grid_feed_in')| int) }} {% endif %}
User Interface
The main displays include:
Power Flow Diagram
type: custom:tesla-style-solar-power-card show_w_not_kw: 1 name: Power Flow house_entity: sensor.meter_power_b grid_entity: sensor.grid_consumption generation_entity: sensor.meter_power_c generation_to_grid_entity: sensor.grid_feed_in generation_to_house_entity: sensor.generation_to_house appliance1_consumption_entity: sensor.phev_charging grid_to_house_entity: sensor.grid_consumption
Generated Power Total
Individual values for each SolaX
type: custom:apexcharts-card header: show: true title: Generated Power show_states: true colorize_states: true apex_config: chart: height: 450 zoom: type: x enabled: true autoScaleYaxis: false toolbar: show: true autoSelected: zoom xaxis.type: datetime series: - entity: sensor.rear_solax_today type: column group_by: func: max duration: 24h - entity: sensor.street_solax_today type: column group_by: func: max duration: 24h graph_span: 28d span: end: day
Total Values
type: custom:apexcharts-card header: show: true title: Total Generated Power show_states: true colorize_states: true apex_config: chart: height: 350 zoom: type: x enabled: true autoScaleYaxis: false toolbar: show: true autoSelected: zoom xaxis.type: datetime series: - entity: sensor.pv_today type: column group_by: func: max duration: 24h graph_span: 28d span: end: day
Charts
Useful Apex custom chart with pan, zoom
type: custom:apexcharts-card header: show: true title: Solar Power show_states: true colorize_states: true apex_config: chart: height: 350 zoom: type: x enabled: true autoScaleYaxis: false toolbar: show: true autoSelected: zoom xaxis.type: datetime stroke: width: 1 curve: smooth series: - entity: sensor.meter_power_a color: red group_by: func: avg duration: 5min - entity: sensor.meter_power_b group_by: func: avg duration: 5min - entity: sensor.meter_power_c color: yellow group_by: func: avg duration: 5min