PV SolaX inverter cloud sensors via API

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 ?). 

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

This also worked for for me, although I used an interval of 120

I think it depends how many times HA makes contact with the website, there is a maximum of 10.000 connections per Day.
In my configuration.yaml are 5 calls each time, wich make 5x60x24 = 7.200 connections per Day.
So if you have 2 inverters 60 seconds is not enough.

I was getting more concerned about the upload of my data to a third party in the cloud. I have moved on to a complete offline solution whereby I can extract the data from the inverter direct. For this I needed an extra raspberry Pi. Here is how I did it: SolaX inverter Wifi Reverse Proxy setup

can you help me with the below?

sensor that you can use in the energy dashboard:

this is the code

‘’’’’’## X3 ##

  • platform: rest
    resource: https://www.solaxcloud.com:9443/proxy/api/getRealtimeInfo.do?tokenId=XXXXXXX&sn=XXXXXXX
    name: “Solax X3”
    json_attributes_path: “$.result”
    json_attributes:
    • yieldtoday
    • yieldtotal
    • acpower
    • uploadTime
    • inverterStatus
    • sn
      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”
    device_class: energy
    solax_x3_total:
    friendly_name: “Solax X3 total”
    value_template: “{{ state_attr(‘sensor.solax_x3’, ‘yieldtotal’) }}”
    unit_of_measurement: “KWh”
    device_class: energy
    solax_x3_now:
    friendly_name: “Solax X3 now”
    value_template: “{{ state_attr(‘sensor.solax_x3’, ‘acpower’) }}”
    unit_of_measurement: “W”
    device_class: energy
    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 %}
    solax_x3_sn:
    friendly_name: “Solax X3 sn”
    value_template: “{{ state_attr(‘sensor.solax_x3’, ‘sn’) }}”
    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’
      ‘’’’’’’’

This is the message that we get in the configuration test:

The system cannot restart because the configuration is not valid: Invalid config for [sensor.template]: expected dictionary for dictionary value @ data[‘sensors’][‘template’]. Got [OrderedDict([(‘sensor’, None)]), OrderedDict([(‘name’, ‘test_energy’), (‘state’, “{{ states(‘sensor.solax_total’) }}”), (‘unit_of_measurement’, ‘kWh’), (‘state_class’, ‘measurement’), (‘device_class’, ‘energy’), (‘attributes’, OrderedDict([(‘last_reset’, ‘1970-01-01T00:00:00+00:00’)]))])]. (See ?, line ?).

.
Do you have a idea what we do wrong?

Can you please repost the code in a proper format? (between …)

type or paste code here

I’ve got the API code and tried the URL (at night) but the only thing i’m getting is This sn did not access! is this due to the fact that it´s currently not on or am I doing something wrong?

{
success: false,
exception: "Query success!",
result: "this sn did not access!"
}

In the night my inverter goes in a kind of sleep mode and no data is available or transmitted. So nothing is wrong, just an efficient design.

Thanks for the quick response, I’ll just add it to my configuration than, and see what happens during the day!

Hi I’m new to Home Assistant so it might be that I am doing something wrong. I got the script working and the sensors are showing up on my dashboard. But when I try to add them to my engery page it does not display the sensors in the list.

No problemo, have a look at this solution: PV SolaX inverter cloud sensors via API - #45 by mpietersen