PV SolaX inverter cloud sensors via API

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!

For testing it would be nice if I could do that remotely on someone’s inverter, as far as I’ve read there is both a cloud and local API? I see that there is already an local API integration in core.

Klaas, The local integration is only working on models which are exposing a local api. On most models thats no longer the case. With a workaround for a Wifi module you can bypass it, but if you have a wired module you dont have this option.

Can we add graph like that:

and battery module

All in one

1 Like

Is there a way to reduce the REST calls? Last weeks I often get the following result if I check the rest link:

{"exception":"Daily access over limit!","success":false}

I had the same problems since a couple of day’s. Adding the line
scan_interval: 60
directly after each
- platform: rest
did the trick for me.

1 Like

I have three inverters and the code works fine up to summing all three values. However, the last energy distribution code is not working. My whole code is in sensors.yaml file.

## X1a ##
- platform: rest
  resource: https://www.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=4444444yyyyyyyyyyyy&sn=SWXXXXXXXX
  name: "Solax X1a"
  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_x1a_today:
      friendly_name: "Solax X1a today"
      value_template: "{{ state_attr('sensor.solax_x1a', 'yieldtoday') }}"
      unit_of_measurement: "KWh"
    solax_x1a_total:
      friendly_name: "Solax X1a total"
      value_template: "{{ state_attr('sensor.solax_x1a', 'yieldtotal') }}"
      unit_of_measurement: "KWh"
    solax_x1a_now:
      friendly_name: "Solax X1a now"
      value_template: "{{ state_attr('sensor.solax_x1a', 'acpower') }}"
      unit_of_measurement: "W"
    solax_x1a_upload_time:
      friendly_name: "Solax X1a upload time"
      value_template: "{{ state_attr('sensor.solax_x1a', 'uploadTime') }}"
    solax_x1a_status:
      friendly_name: "Solax X1 status"
      value_template: >
        {% if state_attr('sensor.solax_x1a', 'inverterStatus') == '100' %}Wait
        {% elif state_attr('sensor.solax_x1a', 'inverterStatus') == '101' %}Check
        {% elif state_attr('sensor.solax_x1a', 'inverterStatus') == '102' %}Normal
        {% elif state_attr('sensor.solax_x1a', 'inverterStatus') == '103' %}Fault
        {% elif state_attr('sensor.solax_x1a', 'inverterStatus') == '104' %}Permanent Fault
        {% elif state_attr('sensor.solax_x1a', 'inverterStatus') == '105' %}Update
        {% elif state_attr('sensor.solax_x1a', 'inverterStatus') == '106' %}EPS Check
        {% elif state_attr('sensor.solax_x1a', 'inverterStatus') == '107' %}EPS
        {% elif state_attr('sensor.solax_x1a', 'inverterStatus') == '108' %}Self-test
        {% elif state_attr('sensor.solax_x1a', 'inverterStatus') == '109' %}Idle
        {% elif state_attr('sensor.solax_x1a', 'inverterStatus') == '110' %}Standby
        {% elif state_attr('sensor.solax_x1a', 'inverterStatus') == '111' %}Pv Wake Up Bat
        {% elif state_attr('sensor.solax_x1a', 'inverterStatus') == '112' %}Gen Check
        {% elif state_attr('sensor.solax_x1a', 'inverterStatus') == '113' %}Gen Run
        {% else %}I dont know{% endif %}

## X1b ##
- platform: rest
  resource: https://www.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=4444444yyyyyyyyyyyy&sn=SWXXXXXXXX
  name: "Solax X1b"
  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_x1b_today:
      friendly_name: "Solax X1b today"
      value_template: "{{ state_attr('sensor.solax_x1b', 'yieldtoday') }}"
      unit_of_measurement: "KWh"
    solax_x1b_total:
      friendly_name: "Solax X1b total"
      value_template: "{{ state_attr('sensor.solax_x1b', 'yieldtotal') }}"
      unit_of_measurement: "KWh"
    solax_x1b_now:
      friendly_name: "Solax X1b now"
      value_template: "{{ state_attr('sensor.solax_x1b', 'acpower') }}"
      unit_of_measurement: "W"
    solax_x1b_upload_time:
      friendly_name: "Solax X1b upload time"
      value_template: "{{ state_attr('sensor.solax_x1b', 'uploadTime') }}"
    solax_x1b_status:
      friendly_name: "Solax X1b status"
      value_template: >
        {% if state_attr('sensor.solax_x1b', 'inverterStatus') == '100' %}Wait
        {% elif state_attr('sensor.solax_x1b', 'inverterStatus') == '101' %}Check
        {% elif state_attr('sensor.solax_x1b', 'inverterStatus') == '102' %}Normal
        {% elif state_attr('sensor.solax_x1b', 'inverterStatus') == '103' %}Fault
        {% elif state_attr('sensor.solax_x1b', 'inverterStatus') == '104' %}Permanent Fault
        {% elif state_attr('sensor.solax_x1b', 'inverterStatus') == '105' %}Update
        {% elif state_attr('sensor.solax_x1b', 'inverterStatus') == '106' %}EPS Check
        {% elif state_attr('sensor.solax_x1b', 'inverterStatus') == '107' %}EPS
        {% elif state_attr('sensor.solax_x1b', 'inverterStatus') == '108' %}Self-test
        {% elif state_attr('sensor.solax_x1b', 'inverterStatus') == '109' %}Idle
        {% elif state_attr('sensor.solax_x1b', 'inverterStatus') == '110' %}Standby
        {% elif state_attr('sensor.solax_x1b', 'inverterStatus') == '111' %}Pv Wake Up Bat
        {% elif state_attr('sensor.solax_x1b', 'inverterStatus') == '112' %}Gen Check
        {% elif state_attr('sensor.solax_x1b', 'inverterStatus') == '113' %}Gen Run
        {% else %}I dont know{% endif %}

## X1h ##
- platform: rest
  resource: https://www.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=4444444yyyyyyyyyyyy&sn=SWXXXXXXXX
  name: "Solax X1h"
  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_x1h_today:
      friendly_name: "Solax X1h today"
      value_template: "{{ state_attr('sensor.solax_x1h', 'yieldtoday') }}"
      unit_of_measurement: "KWh"
    solax_x1h_total:
      friendly_name: "Solax X1h total"
      value_template: "{{ state_attr('sensor.solax_x1h', 'yieldtotal') }}"
      unit_of_measurement: "KWh"
    solax_x1h_now:
      friendly_name: "Solax X1h now"
      value_template: "{{ state_attr('sensor.solax_x1h', 'acpower') }}"
      unit_of_measurement: "W"
    solax_x1h_upload_time:
      friendly_name: "Solax X1h upload time"
      value_template: "{{ state_attr('sensor.solax_x1h', 'uploadTime') }}"
    solax_x1h_status:
      friendly_name: "Solax X1h status"
      value_template: >
        {% if state_attr('sensor.solax_x1h', 'inverterStatus') == '100' %}Wait
        {% elif state_attr('sensor.solax_x1h', 'inverterStatus') == '101' %}Check
        {% elif state_attr('sensor.solax_x1h', 'inverterStatus') == '102' %}Normal
        {% elif state_attr('sensor.solax_x1h', 'inverterStatus') == '103' %}Fault
        {% elif state_attr('sensor.solax_x1h', 'inverterStatus') == '104' %}Permanent Fault
        {% elif state_attr('sensor.solax_x1h', 'inverterStatus') == '105' %}Update
        {% elif state_attr('sensor.solax_x1h', 'inverterStatus') == '106' %}EPS Check
        {% elif state_attr('sensor.solax_x1h', 'inverterStatus') == '107' %}EPS
        {% elif state_attr('sensor.solax_x1h', 'inverterStatus') == '108' %}Self-test
        {% elif state_attr('sensor.solax_x1h', 'inverterStatus') == '109' %}Idle
        {% elif state_attr('sensor.solax_x1h', 'inverterStatus') == '110' %}Standby
        {% elif state_attr('sensor.solax_x1h', 'inverterStatus') == '111' %}Pv Wake Up Bat
        {% elif state_attr('sensor.solax_x1h', 'inverterStatus') == '112' %}Gen Check
        {% elif state_attr('sensor.solax_x1h', 'inverterStatus') == '113' %}Gen Run
        {% else %}I dont know{% endif %}

- platform: template
  sensors:
    solax_today:
      friendly_name: Solax today
      unit_of_measurement: kWh
      value_template: "{{ (states('sensor.solax_x1a_today') | float) + (states('sensor.solax_x1b_today') | float) + (states('sensor.solax_x1h_today') | float)}}"
    solax_now:
      friendly_name: Solax now
      unit_of_measurement: W
      value_template: "{{ (states('sensor.solax_x1a_now') | float) + (states('sensor.solax_x1b_now') | float) + (states('sensor.solax_x1h_now') | float) }}"
    solax_total:
      friendly_name: Solax total
      unit_of_measurement: KWh
      value_template: "{{ (states('sensor.solax_x1a_total') | float) + (states('sensor.solax_x1b_total') | float)  + (states('sensor.solax_x1h_total') | float) }}"
    
- platform: template
  sensors:
    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:0'

I get the following error:

Invalid config for [sensor.template]: expected dictionary for dictionary value @ data['sensors']['device_class']. Got 'energy'
expected dictionary for dictionary value @ data['sensors']['name']. Got 'test_energy'
expected dictionary for dictionary value @ data['sensors']['state']. Got "{{ states('sensor.solax_total') }}"
expected dictionary for dictionary value @ data['sensors']['state_class']. Got 'measurement'
expected dictionary for dictionary value @ data['sensors']['unit_of_measurement']. Got 'kWh'
extra keys not allowed @ data['sensors']['attributes']['last_reset']. Got '1970-01-01T00:00:00+00:0'
required key not provided @ data['sensors']['attributes']['value_template']. Got None. (See ?, line ?). 
1 Like

Same problem here. Tried your solution but it does not work. Anyone with a possible solution?