PV SolaX inverter cloud sensors via API

So I assume you have two sensors for current PV, two sensors for today’s PV and two for Total. Now we have to add them into 3 new sensors like:


    
  - platform: template
    sensors:
      pv_now:
        friendly_name: "PV Now"
        unit_of_measurement: W
        value_template: "{{ states('sensor.solax_now')|int + states('sensor.solax_now2')| int }}"
        icon_template: mdi:power-socket-de
        device_class: power
        
  - platform: template
    sensors:
      pv_today:
        friendly_name: "PV Today"
        unit_of_measurement: "kWh"
        value_template: "{{ (states('sensor.solax_today')|int + states('sensor.solax_today2')|int) }}"
        icon_template: mdi:solar-panel        

  - platform: template
    sensors:
      pv_total:
        friendly_name: "PV Total"
        unit_of_measurement: kWh
        value_template: "{{ states('sensor.solax_total')|int + states('sensor.solax_total2')|int }}"
        icon_template: mdi:chart-line

1 Like

Sorry that I did it wrong. I hope I do it now oké.
This is the total code in the config.yaml:

# Configure a default setup of Home Assistant (frontend, api, etc)
default_config:

# Text to speech
tts:
  - platform: google_translate

group: !include groups.yaml
automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml
#########################################################
#                                                       #
#         SOLAX CLOUD.   Master                         #
#                                                       #
#########################################################
sensor:
  - platform: rest
    resource: https://www.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=APITOKEN&sn=SWXXXXXXXXXX
    value_template: '{{ ( value_json.result.yieldtotal | round(0) ) }}'
    name: "Master Solax total"
    unit_of_measurement: "KWh"

  - platform: rest
    resource: https://www.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=APITOKEN&sn=SWXXXXXXXXXX
    value_template: '{{ ( value_json.result.acpower | round(0) ) }}'
    name: "Master Solax now"
    unit_of_measurement: "W"

  - platform: rest
    resource: https://www.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=APITOKEN&sn=SWXXXXXXXXXX
    value_template: '{{ ( value_json.result.powerdc2 | round(0) ) }}'
    name: "Master Leistung Panel"
    unit_of_measurement: "W"

  - platform: rest
    resource: https://www.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=APITOKEN&sn=SWXXXXXXXXXX
    value_template: '{{ value_json.result.yieldtoday }}'
    name: "Master Solax today"
    unit_of_measurement: "KWh"
    
  - platform: rest
    resource: https://www.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=APITOKEN&sn=SWXXXXXXXXXX
    value_template: "{{ value_json.result.uploadTime }}"
    name: "Master Solax upload time"
    
  - platform: rest
    resource: https://www.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=APITOKEN&sn=SWXXXXXXXXXX
    value_template: >
          {% if value_json.result.inverterStatus == '100' %}Wait
          {% elif value_json.result.inverterStatus == '101' %}Check
          {% elif value_json.result.inverterStatus == '102' %}Normal
          {% elif value_json.result.inverterStatus == '103' %}Fault
          {% elif value_json.result.inverterStatus == '104' %}Permanent Fault
          {% elif value_json.result.inverterStatus == '105' %}Update
          {% elif value_json.result.inverterStatus == '106' %}EPS Check
          {% elif value_json.result.inverterStatus == '107' %}EPS
          {% elif value_json.result.inverterStatus == '108' %}Self-test
          {% elif value_json.result.inverterStatus == '109' %}Idle
          {% elif value_json.result.inverterStatus == '110' %}Standby
          {% elif value_json.result.inverterStatus == '111' %}Pv Wake Up Bat
          {% elif value_json.result.inverterStatus == '112' %}Gen Check
          {% elif value_json.result.inverterStatus == '113' %}Gen Run
          {% else %}I dont know{% endif %}
    name: "Master Solax status"

#########################################################
#                                                       #
#            END OF CONFIGURATION FILE                  #
#                                                       #
#########################################################


#########################################################
#                                                       #
#         SOLAX CLOUD.   Slave		                #
#                                                       #
#########################################################

  - platform: rest
    resource: https://www.eu.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=APITOKEN&sn=SWXXXXXXXXXX
    value_template: '{{ ( value_json.result.yieldtotal | round(0) ) }}'
    name: "Slave Solax total"
    unit_of_measurement: "KWh"

  - platform: rest
    resource: https://www.eu.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=APITOKEN&sn=SWXXXXXXXXXX
    value_template: '{{ ( value_json.result.acpower | round(0) ) }}'
    name: "Slave Solax now"
    unit_of_measurement: "W"

  - platform: rest
    resource: https://www.eu.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=APITOKEN&sn=SWXXXXXXXXXX
    value_template: '{{ ( value_json.result.powerdc2 | round(0) ) }}'
    name: "Slave Leistung Panel"
    unit_of_measurement: "W"

  - platform: rest
    resource: https://www.eu.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=APITOKEN&sn=SWXXXXXXXXXX
    value_template: '{{ value_json.result.yieldtoday }}'
    name: "Slave Solax today"
    unit_of_measurement: "KWh"
    
  - platform: rest
    resource: https://www.eu.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=APITOKEN&sn=SWXXXXXXXXXX
    value_template: "{{ value_json.result.uploadTime }}"
    name: "Slave Solax upload time"
    
  - platform: rest
    resource: https://www.eu.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=APITOKEN&sn=SWXXXXXXXXXX
    value_template: >
          {% if value_json.result.inverterStatus == '100' %}Wait
          {% elif value_json.result.inverterStatus == '101' %}Check
          {% elif value_json.result.inverterStatus == '102' %}Normal
          {% elif value_json.result.inverterStatus == '103' %}Fault
          {% elif value_json.result.inverterStatus == '104' %}Permanent Fault
          {% elif value_json.result.inverterStatus == '105' %}Update
          {% elif value_json.result.inverterStatus == '106' %}EPS Check
          {% elif value_json.result.inverterStatus == '107' %}EPS
          {% elif value_json.result.inverterStatus == '108' %}Self-test
          {% elif value_json.result.inverterStatus == '109' %}Idle
          {% elif value_json.result.inverterStatus == '110' %}Standby
          {% elif value_json.result.inverterStatus == '111' %}Pv Wake Up Bat
          {% elif value_json.resreult.inverterStatus == '112' %}Gen Check
          {% elif value_json.result.inverterStatus == '113' %}Gen Run
          {% else %}I dont know{% endif %}
    name: "Slave Solax status"

#########################################################
#                                                       #
#            END OF CONFIGURATION FILE                  #
#                                                       #
#########################################################

############
# Gesamtverbrauch aktuell
###
  - platform: template
    total_energy_used:
      value_template: '{{ ((state.sensor.master_solax_now | float) + 
      (state.sensor.slave_solax_now | float)}}'
      friendly_name: 'Gesamtverbrauch aktuell'  
      unit_of_measurement: "KW"
1 Like

YES this works.
We are really grateful, thank you so much for your help.

1 Like

I added :
scan_interval: 60
to one of the api calls to see if that will scan at 1 minute intervals instead of the default 5 minutes
I will tell you if it works…

Thanks for this @Doublet !

The default scan interval for the rest sensor is 30 seconds. The update frequency is 5 minutes on Solax side, so the scan interval isn’t going to change things.

I have two Solax inverters (X1 and X3) and I saw in the API documentation there is a request limit of 10000/day. So I changed the sensor a bit, with the purpose of making one rest call and extracting the data I need for the sensors.

## X3 ##
- platform: rest
  resource: https://www.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=202102060300yyyyyyy&sn=SWXXXXXXX
  name: "Solax X3"
  json_attributes_path: "$.result"
  json_attributes:
    - yieldtoday
    - yieldtotal
    - acpower
    - uploadTime
    - inverterStatus
  value_template: '1'  # dummy value, not used; avoids the "State max length is 255 characters" error
- platform: template
  sensors:
    solax_x3_today:
      friendly_name: "Solax X3 today"
      value_template: "{{ state_attr('sensor.solax_x3', 'yieldtoday') }}"
      unit_of_measurement: "KWh"
    solax_x3_total:
      friendly_name: "Solax X3 total"
      value_template: "{{ state_attr('sensor.solax_x3', 'yieldtotal') }}"
      unit_of_measurement: "KWh"
    solax_x3_now:
      friendly_name: "Solax X3 now"
      value_template: "{{ state_attr('sensor.solax_x3', 'acpower') }}"
      unit_of_measurement: "W"
    solax_x3_upload_time:
      friendly_name: "Solax X3 upload time"
      value_template: "{{ state_attr('sensor.solax_x3', 'uploadTime') }}"
    solax_x3_status:
      friendly_name: "Solax X3 status"
      value_template: >
        {% if state_attr('sensor.solax_x3', 'inverterStatus') == '100' %}Wait
        {% elif state_attr('sensor.solax_x3', 'inverterStatus') == '101' %}Check
        {% elif state_attr('sensor.solax_x3', 'inverterStatus') == '102' %}Normal
        {% elif state_attr('sensor.solax_x3', 'inverterStatus') == '103' %}Fault
        {% elif state_attr('sensor.solax_x3', 'inverterStatus') == '104' %}Permanent Fault
        {% elif state_attr('sensor.solax_x3', 'inverterStatus') == '105' %}Update
        {% elif state_attr('sensor.solax_x3', 'inverterStatus') == '106' %}EPS Check
        {% elif state_attr('sensor.solax_x3', 'inverterStatus') == '107' %}EPS
        {% elif state_attr('sensor.solax_x3', 'inverterStatus') == '108' %}Self-test
        {% elif state_attr('sensor.solax_x3', 'inverterStatus') == '109' %}Idle
        {% elif state_attr('sensor.solax_x3', 'inverterStatus') == '110' %}Standby
        {% elif state_attr('sensor.solax_x3', 'inverterStatus') == '111' %}Pv Wake Up Bat
        {% elif state_attr('sensor.solax_x3', 'inverterStatus') == '112' %}Gen Check
        {% elif state_attr('sensor.solax_x3', 'inverterStatus') == '113' %}Gen Run
        {% else %}I dont know{% endif %}

## X1 ##
- platform: rest
  resource: https://www.eu.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=20210517200601yyyyyyyyyyyy&sn=SWXXXXXXXXX
  name: "Solax X1"
  json_attributes_path: "$.result"
  json_attributes:
    - yieldtoday
    - yieldtotal
    - acpower
    - uploadTime
    - inverterStatus
  value_template: '1'  # dummy value, not used; avoids the "State max length is 255 characters" error
- platform: template
  sensors:
    solax_x1_today:
      friendly_name: "Solax X1 today"
      value_template: "{{ state_attr('sensor.solax_x1', 'yieldtoday') }}"
      unit_of_measurement: "KWh"
    solax_x1_total:
      friendly_name: "Solax X1 total"
      value_template: "{{ state_attr('sensor.solax_x1', 'yieldtotal') }}"
      unit_of_measurement: "KWh"
    solax_x1_now:
      friendly_name: "Solax X1 now"
      value_template: "{{ state_attr('sensor.solax_x1', 'acpower') }}"
      unit_of_measurement: "W"
    solax_x1_upload_time:
      friendly_name: "Solax X1 upload time"
      value_template: "{{ state_attr('sensor.solax_x1', 'uploadTime') }}"
    solax_x1_status:
      friendly_name: "Solax X1 status"
      value_template: >
        {% if state_attr('sensor.solax_x1', 'inverterStatus') == '100' %}Wait
        {% elif state_attr('sensor.solax_x1', 'inverterStatus') == '101' %}Check
        {% elif state_attr('sensor.solax_x1', 'inverterStatus') == '102' %}Normal
        {% elif state_attr('sensor.solax_x1', 'inverterStatus') == '103' %}Fault
        {% elif state_attr('sensor.solax_x1', 'inverterStatus') == '104' %}Permanent Fault
        {% elif state_attr('sensor.solax_x1', 'inverterStatus') == '105' %}Update
        {% elif state_attr('sensor.solax_x1', 'inverterStatus') == '106' %}EPS Check
        {% elif state_attr('sensor.solax_x1', 'inverterStatus') == '107' %}EPS
        {% elif state_attr('sensor.solax_x1', 'inverterStatus') == '108' %}Self-test
        {% elif state_attr('sensor.solax_x1', 'inverterStatus') == '109' %}Idle
        {% elif state_attr('sensor.solax_x1', 'inverterStatus') == '110' %}Standby
        {% elif state_attr('sensor.solax_x1', 'inverterStatus') == '111' %}Pv Wake Up Bat
        {% elif state_attr('sensor.solax_x1', 'inverterStatus') == '112' %}Gen Check
        {% elif state_attr('sensor.solax_x1', 'inverterStatus') == '113' %}Gen Run
        {% else %}I dont know{% endif %}

And sensors to sum both inverters:

- platform: template
  sensors:
    solax_today:
      friendly_name: Solax today
      unit_of_measurement: kWh
      value_template: "{{ (states('sensor.solax_x1_today') | float) + (states('sensor.solax_x3_today') | float) }}"
    solax_now:
      friendly_name: Solax now
      unit_of_measurement: W
      value_template: "{{ (states('sensor.solax_x1_now') | float) + (states('sensor.solax_x3_now') | float) }}"
    solax_total:
      friendly_name: Solax total
      unit_of_measurement: KWh
      value_template: "{{ (states('sensor.solax_x1_total') | float) + (states('sensor.solax_x3_total') | float) }}"
    
2 Likes

@Bobbika Thanks for this extensive example.
I have the same setup of inverters so I could use it with very small alterations.

With the new energy management this became even more important to me.

Sadly it seems that there is no support for template sensors according to this post by @frenck.

I will try to contact Solax again to see if i can change their mind about the local API.
With my setup (X1 and X3 both with pocket lan adapter) the workaround connecting to the SSID locally does not work, obviously.

1 Like

I have send an extensive request to Solax Benelux to request to open up the local API again for Solax inverters. After my question they build the web api, but that is not really what we need.
My contact is on holiday until august 15th. If there is a response I’ll post results here.

3 Likes

Got it working!! You can add the below code to your config for a sensor that you can use in the energy dashboard:

template:
  - sensor:
    - name: test_energy
      state: "{{ states('sensor.solax_total') }}" 
      unit_of_measurement: 'kWh'
      state_class: measurement
      device_class: energy
      attributes:         
          last_reset: '1970-01-01T00:00:00+00:00'

image

6 Likes

Works with my solax X3

Thanks! This works great with my Solax X3

Great resource!

If there is anyone interested in building an integration, I’m leaving a link to the repo:

1 Like

Can I point out that this returns the total Solax power, which is an ever increasing value of all power captured by the PV panels.
I’m looking into a different solution using the Utility meter entity, but that only aggregates on the 15min scale :frowning:

I ended up with this:

    solax_yield_delta:
      friendly_name: "Solax yield delta"
      value_template: "{{ state_attr('sensor.solax_x1', 'acpower') /12000 }}"
      unit_of_measurement: 'kWh'
      state_class: measurement
      device_class: energy

I take the power value which is updated every 5min and convert that to kWh for the 5min time period (acpower * 1/12 * 1/1000). That seems right to me.

@mpietersen:
It is not clear to me what data you need exactly. Solax total power returns the power generated in total and this is by design. For the energy dashboard this is what you need.

The API also returns other parameters like Yield Today: (kWh yield reset on daily basis) which you could put into an entity as well if you’d desire?

If you take the power which is only measured every 5 minutes and take that as an average to calculate consumption you are probably way off depending on the weather conditions and country of installation.

As mentioned earlier I am waiting for solax to respond to my query in having the local API reopened for consumer grade systems as this would be preferred over a cloud based integration.
With a local API you could have an update frequency of seconds compared to the laggy and less frequently updated data from the cloud.

1 Like

Worked perfectly mate! Couldn’t be easier.

Are you saying the input for the energy dashboard is the PV’s total energy? (not saying I don’t believe you, just surprised). There is no documentation, but I assume the Energy Dashboard is based on the Utility Meter, which I never understood. It could very well be possible the dashboard uses the delta from a value (just as I’m trying to do).
So if you’re certain the total PV Wh value needs to go to the energy dashboard, Ill use that.
Thank you for commenting

Yes, this is exactly the input needed for the energy dashboard. Same for the energy from grid. The integration uses the long term statistics which are generated for sensors with the right attributes. Hence which is why the last reset is needed as well.

I am 100% sure that the Power dashboard needs total values in kWh.

Thanks a lot! Got my X1 working with your help :smile:

Yes I’m interested to do more with this repository / integration

That would be great!