Eu tenho um Solax Hybrid X1 integrado pela cloud e local, sem ser preciso modbus, com a pen wifi deles.
Fiz da seguinte maneira:
Ficheiros/integrações necessários:
- config.yaml (normal)
- sensors.yaml (para manter o config mais limpo)
- templates.yaml (para manter o config mais limpo)
- secrets.yaml
- powercalc.yaml
- integração powercalc
- ip da pen wifi (aparece no router como expressif)
1- Em primeiro lugar, instalar a integração Powercalc através do HACS
powercalc
2- Escrever as seguintes linhas no config.yaml:
sensor: !include sensors.yaml
template: !include templates.yaml
sensor powercalc_label: !include powercalc.yaml
### Commands for controlling the Solax Local inverter
rest_command:
solax_local_charge_battery_from_grid:
url: !secret solax_local_ip
method: post
payload: !secret solax_local_set_battery_level_payload
3- Ecrever em secrets.yaml:
solax_cloud_api: https://www.solaxcloud.com/proxyApp/proxy/api/getRealtimeInfo.do?tokenId=TOKEN OBTIDO NA PÁGINA DA SOLAX&sn=REFERÊNCIA DA PEN WIFI
solax_local_ip: http://IP DO EXPRESSIF/ # IP of solax module
solax_local_ip2: IP DO EXPRESSIF/?optType=ReadRealTimeData
solax_local_realtime_payload: "optType=ReadRealTimeData&pwd=REFERÊNCIA DA PEN WIFI"
solax_local_settings_payload: "optType=ReadSetData&pwd=REFERÊNCIA DA PEN WIFI"
solax_local_set_battery_min_soc_payload: 'optType=setReg&pwd=REFERÊNCIA DA PEN WIFI&data={"num":1,"Data":[{"reg":29,"val":"{{ level }}"}]}'
solax_local_set_battery_grid_charge_level_payload: 'optType=setReg&pwd=REFERÊNCIA DA PEN WIFI&data={"num":1,"Data":[{"reg":31,"val":"{{ level }}"}]}'
solax_local_set_battery_forced_charge_start: 'optType=setReg&pwd=REFERÊNCIA DA PEN WIFI&data={"num":1,"Data":[{"reg":37,"val":"{{ value }}"}]}'
solax_local_set_period2_enable_payload: 'optType=setReg&pwd=REFERÊNCIA DA PEN WIFI&data={"num":1,"Data":[{"reg":41,"val":"{{ enabled }}"}]}'
solax_local_set_battery_level_payload: 'optType=setReg&pwd=REFERÊNCIA DA PEN WIFI&data={"num":1,"Data":[{"reg":31,"val":"{{ level }}"}]}'
Convém atribuir ip fixo á pen wifi
4- Escrever em sensors.yaml
###################################
# Solax X1 Hybrid Rest Sensors #
###################################
# Solax Cloud REST
- platform: rest
scan_interval: 595
resource: !secret solax_cloud_api
json_attributes_path: "$.result"
json_attributes:
- yieldtoday
- yieldtotal
- acpower
- uploadTime
- inverterStatus
- feedinpower
- feedinenergy
- consumeenergy
- soc
- batPower
- powerdc1
- powerdc2
- batStatus
value_template: 'Active' # dummy value, not used; avoids the "State max length is 255 characters" error
name: "solax_rest_cloud"
### Solax Local REST sensor ###
- platform: rest
scan_interval: 5
resource: !secret solax_local_ip
payload: !secret solax_local_realtime_payload
method: POST
name: "solax_rest_local"
json_attributes:
- sn
- ver
- type
- Data
- Information
value_template: 'OK' # dummy value, not used; avoids the "State max length is 255 characters" error
### Solax Local REST settings ###
- platform: rest
scan_interval: 3600
resource: !secret solax_local_ip
payload: !secret solax_local_settings_payload
method: POST
name: "solax_rest_local_settings"
# Unfortunately settings are not returned as a JSON document but an array of numbers, so having to pick just the relevant to avoid the max 255 chars limit
# 0 - Self Use Min SOC %
# 1 - Self Use Charge from grid (0 for disabled, 1 for enabled)
# 2 - Self Use Charge from grid to %
value_template: "{{ '[' ~ value.split(',')[28] ~ ',' ~ value.split(',')[29] ~ ',' ~ value.split(',')[30] ~ ']' }}"
- platform: rest
name: solaxx1data
resource: !secret solax_local_ip2 # Local IP of Solax Pocket Wifi
method: POST
headers:
X-Forwarded-For: 5.8.8.8
scan_interval: 5
timeout: 4
value_template: 'OK'
json_attributes:
- type
- SN
- ver
- Data
- Information
5- Escrever em templates.yaml (A referência da pen wifi fica entre aspas!)
- sensor:
- name: Solax ENERGYTODAY
unit_of_measurement: "kWh"
state: >
{% if is_state('sensor.solaxx1data', 'unavailable') %}
{{ states('sensor.solaxx1_energytoday') }}
{% else %}
{{ state_attr("sensor.solaxx1data", "Data")[8] }}
{% endif %}
icon: mdi:home-lightning-bolt-outline
device_class: "energy"
state_class: total_increasing
- name: "Solax Cloud Yield Today"
state: "{{ state_attr('sensor.solax_rest_cloud', 'yieldtoday') }}"
unit_of_measurement: "kWh"
unique_id: solax_2
icon: mdi:flash
device_class: energy
state_class: total_increasing
- name: "Solax Cloud Yield Total"
state: "{{ state_attr('sensor.solax_rest_cloud', 'yieldtotal') }}"
unit_of_measurement: "kWh"
unique_id: solax_3
icon: mdi:flash
device_class: energy
state_class: total_increasing
- name: "Solax Cloud Inverter"
unit_of_measurement: "W"
state: "{{ state_attr('sensor.solax_rest_cloud', 'acpower') }}"
unique_id: solax_cloud_inverter
icon: mdi:flash
device_class: energy
state_class: measurement
- name: "Solax Cloud Upload Time"
state: >
{% set time = state_attr('sensor.solax_rest_cloud', 'uploadTime') %}
{{ as_timestamp(time) | timestamp_custom('%I:%M %p') }}
unique_id: solax_5
icon: mdi:clock
- name: "Solax Cloud Battery Status"
state: "{{ state_attr('sensor.solax_rest_cloud', 'batStatus') }}"
unique_id: solax_6
icon: mdi:battery
- name: "Solax Cloud Solar Panel"
state: "{{ state_attr('sensor.solax_rest_cloud', 'powerdc1') + state_attr('sensor.solax_rest_cloud', 'powerdc2') }}"
unit_of_measurement: "W"
device_class: energy
state_class: measurement
unique_id: solax_cloud_solar_panel
icon: mdi:solar-power-variant
- name: "Solax Cloud Battery Use"
state: >
{{ state_attr('sensor.solax_rest_cloud', 'batPower') }}
unit_of_measurement: "W"
device_class: energy
state_class: measurement
unique_id: solax_cloud_battery_use
icon: mdi:battery
- name: "Solax Cloud Battery Adjusted"
state: >
{% set ac = states('sensor.solax_cloud_inverter')|int %}
{% set pv = states('sensor.solax_cloud_solar_panel')|int %}
{{ (0 - ac + pv) }}
unit_of_measurement: "W"
device_class: energy
state_class: measurement
unique_id: solax_cloud_battery_adjusted
icon: mdi:battery
- name: "Solax Cloud Battery Use In"
state: >
{% set batAdj = states('sensor.solax_cloud_battery_adjusted')|int(default=0) %}
{% set attr = state_attr('sensor.solax_rest_cloud', 'batPower') %}
{{ batAdj if is_number(batAdj) and (batAdj|int > 0) else 0 }}
unit_of_measurement: "W"
unique_id: solax_cloud_battery_use_in
icon: mdi:battery
- name: "Solax Cloud Battery Use Out"
state: >
{% set batAdj = states('sensor.solax_cloud_battery_adjusted')|int(default=0) %}
{% set attr = state_attr('sensor.solax_rest_cloud', 'batPower') %}
{{ (0 - batAdj) if is_number(batAdj) and (batAdj|int < 0) else 0 }}
unit_of_measurement: "W"
unique_id: solax_cloud_battery_use_out
icon: mdi:battery
- name: "Solax Cloud Battery"
state: "{{ state_attr('sensor.solax_rest_cloud', 'soc') }}"
unit_of_measurement: "%"
device_class: battery
state_class: measurement
unique_id: solax_12
icon: mdi:battery
- name: "Solax Cloud Grid Power"
state: >
{% set attr = state_attr('sensor.solax_rest_cloud', 'feedinpower') %}
{{ (0 - attr) if is_number(attr) else 0 }}
unit_of_measurement: "W"
device_class: energy
state_class: measurement
unique_id: solax_13
icon: mdi:transmission-tower
- name: "Solax Cloud Grid Power in"
state: >
{% set attr = state_attr('sensor.solax_rest_cloud', 'feedinpower') %}
{{ (0 - attr) if is_number(attr) and (attr|float < 0) else 0 }}
unit_of_measurement: "W"
unique_id: solax_14
icon: mdi:transmission-tower
- name: "Solax Cloud Grid Power out"
state: >
{% set attr = state_attr('sensor.solax_rest_cloud', 'feedinpower') %}
{{ attr if is_number(attr) and (attr|float > 0) else 0 }}
unit_of_measurement: "W"
unique_id: solax_15
icon: mdi:transmission-tower
- name: "Solax Cloud Energy To Grid"
state: "{{ state_attr('sensor.solax_rest_cloud', 'feedinenergy') }}"
unit_of_measurement: "kWh"
unique_id: solax_16
icon: mdi:transmission-tower
device_class: energy
state_class: total_increasing
- name: "Solax Cloud Energy From Grid"
state: "{{ state_attr('sensor.solax_rest_cloud', 'consumeenergy') }}"
unit_of_measurement: "kWh"
unique_id: solax_19
icon: mdi:transmission-tower
device_class: energy
state_class: total_increasing
- name: "Solax Cloud Status"
unique_id: solax_20
icon: mdi:solar-power-variant
state: >
{% set attr = state_attr('sensor.solax_rest_cloud', 'inverterStatus') %}
{% if attr == '100' %}Wait
{% elif attr == '101' %}Check
{% elif attr == '102' %}Normal
{% elif attr == '103' %}Fault
{% elif attr == '104' %}Permanent Fault
{% elif attr == '105' %}Update
{% elif attr == '106' %}EPS Check
{% elif attr == '107' %}EPS
{% elif attr == '108' %}Self-test
{% elif attr == '109' %}Idle
{% elif attr == '110' %}Standby
{% elif attr == '111' %}Pv Wake Up Bat
{% elif attr == '112' %}Gen Check
{% elif attr == '113' %}Gen Run
{% else %}unknown{% endif %}
- name: SolaX Cloud Total Home Use
unique_id: home use
state: >
{% set battery = states('sensor.solax_battery_use') %}
{% set grid = states('sensor.solax_grid_power') %}
{% set solar = states('sensor.solar_panel_power') %}
{% set total = 0 - battery|float if is_number(battery) else 0 %}
{% set total = total + (solar|float if is_number(solar) else 0) %}
{% set total = total + (grid|float if is_number(grid) else 0) %}
{{ total }}
state_class: measurement
icon: 'mdi:flash'
unit_of_measurement: W
device_class: power
# --- LOCAL --------------------------
### Local sensor readings ###
- name: solax_local
state: >
{% if state_attr('sensor.solax_rest_local', 'sn') == "REFERÊNCIA DA PEN WIFI" %}{{ now().strftime("%H:%M:%S") }}
{% else %}{{ (states('sensor.solax_local')) }}{% endif %}
attributes:
sn: >-
{% if state_attr('sensor.solax_rest_local', 'sn') == "REFERÊNCIA DA PEN WIFI" %}{{ (state_attr('sensor.solax_rest_local', 'sn')) }}
{% else %}{{ (state_attr('sensor.solax_local', 'sn')) }}{% endif %}
ver: >-
{% if state_attr('sensor.solax_rest_local', 'sn') == "REFERÊNCIA DA PEN WIFI" %}{{ (state_attr('sensor.solax_rest_local', 'ver')) }}
{% else %}{{ (state_attr('sensor.solax_local', 'ver')) }}{% endif %}
type: >-
{% if state_attr('sensor.solax_rest_local', 'sn') == "REFERÊNCIA DA PEN WIFI" %}{{ (state_attr('sensor.solax_rest_local', 'type')) }}
{% else %}{{ (state_attr('sensor.solax_local', 'type')) }}{% endif %}
Data: >-
{% if state_attr('sensor.solax_rest_local', 'sn') == "REFERÊNCIA DA PEN WIFI" %}{{ (state_attr('sensor.solax_rest_local', 'Data')) }}
{% else %}{{ (state_attr('sensor.solax_local', 'Data')) }}{% endif %}
Information: >-
{% if state_attr('sensor.solax_rest_local', 'sn') == "REFERÊNCIA DA PEN WIFI" %}{{ (state_attr('sensor.solax_rest_local', 'Information')) }}
{% else %}{{ (state_attr('sensor.solax_local', 'Information')) }}{% endif %}
### Make the settings look like sensor data by embedding the info in the Data attribute
- name: solax_local_settings
state: >
{{ now().strftime("%H:%M:%S") }}
attributes:
Data: >-
{{ (states('sensor.solax_rest_local_settings')) }}
#### Combined Solar PV output ####
- name: "Solax Local PV Output"
unique_id: solax_local_pv_output
state: "{{ (state_attr('sensor.solax_local', 'Data')[8] + state_attr('sensor.solax_local', 'Data')[9]) | int(default=0) }}"
unit_of_measurement: "W"
state_class: measurement
device_class: "power"
### Inverter output (negative for charging battery) ####
- name: "Solax Local AC Power"
unique_id: solax_local_ac_power
state: >
{% if state_attr('sensor.solax_local', 'Data')[2] > 32767 %}{{ (state_attr('sensor.solax_local', 'Data')[2] - 65536) | int(default=0) }}
{% else %}{{ state_attr('sensor.solax_local', 'Data')[2] | int(default=0) }}{% endif %}
unit_of_measurement: "W"
state_class: measurement
device_class: "power"
### Battery current, voltage and temperature ###
- name: "Solax Local Battery Voltage"
unique_id: solax_local_battery_voltage
state: "{{ state_attr('sensor.solax_local', 'Data')[14] | float / 100}}"
unit_of_measurement: "V"
device_class: "voltage"
- name: "Solax Local Battery Current"
unique_id: solax_local_battery_current
state: >
{% if state_attr('sensor.solax_local', 'Data')[15] > 32767 %}{{ (state_attr('sensor.solax_local', 'Data')[15] - 65536) / 100 }}
{% else %}{{ state_attr('sensor.solax_local', 'Data')[15] / 100 }}{% endif %}
unit_of_measurement: "A"
device_class: "current"
- name: "Solax Local Battery Temperature"
unique_id: solax_local_battery_temp
state: "{{ state_attr('sensor.solax_local', 'Data')[17] | int(default=0) }}"
unit_of_measurement: "°C"
device_class: "temperature"
### Battery charging/discharging power (positive for charging the battery) ###
- name: "Solax Local Battery Power"
unique_id: solax_local_battery_power
state: >
{% if state_attr('sensor.solax_local', 'Data')[16] > 32767 %}{{ state_attr('sensor.solax_local', 'Data')[16] - 65536 }}
{% else %}{{ state_attr('sensor.solax_local', 'Data')[16] }}{% endif %}
unit_of_measurement: "W"
#state_class: measurement
device_class: "power"
- name: "Solax Local Battery Power Adjusted"
unique_id: solax_local_battery_power_adjusted
state: >
{% set battery = states('sensor.solax_local_battery_power')|int %}
{% set ac = states('sensor.solax_local_ac_power')|int %}
{% set pv = states('sensor.solax_local_pv_output')|int %}
{{ (0 - ac + pv) }}
unit_of_measurement: "W"
#state_class: measurement
device_class: "power"
### Battery charge level (%)
- name: "Solax Local Battery SoC"
unique_id: solax_local_battery_soc
state: "{{ state_attr('sensor.solax_local', 'Data')[18] | int(default=0) }}"
unit_of_measurement: "%"
### Battery discharge min (%)
- name: "Solax Local Battery Min SoC"
unique_id: solax_local_battery_min_soc
state: "{{ state_attr('sensor.solax_local_settings', 'Data')[0] | int(default=0) }}"
unit_of_measurement: "%"
### Battery charge from grid
- name: "Solax Local Battery Charge From Grid"
unique_id: solax_local_battery_grid_enabled
state: "{{ state_attr('sensor.solax_local_settings', 'Data')[1] | int(default=0) }}"
### Battery charge level to (%) from grid
- name: "Solax Local Battery Charge From Grid To"
unique_id: solax_local_battery_charge_from_grid_to
state: "{{ state_attr('sensor.solax_local_settings', 'Data')[2] | int(default=0) }}"
unit_of_measurement: "%"
### Estimated remaining energy ###
- name: "Solax Local Battery Remain Energy"
unique_id: solax_local_battery_kwh
state: "{{ states('sensor.solax_local_battery_soc') | int(default=0) * 6.2 / 100 }}"
unit_of_measurement: "kWh"
device_class: "energy"
### Grid power (positive for feed-in, negative for consumption) ###
- name: "Solax Local Grid Power"
unique_id: solax_local_grid_power
state: >
{% if state_attr('sensor.solax_local', 'Data')[32] > 32767 %}{{ (state_attr('sensor.solax_local', 'Data')[32] - 65536) }}
{% else %}{{ state_attr('sensor.solax_local', 'Data')[32] }}{% endif %}
unit_of_measurement: "W"
state_class: measurement
device_class: "power"
### Expected household load (negative not expected as it only consumes energy) ###
- name: "Solax Local Load Power"
unique_id: solax_local_load_power
state: "{{ states('sensor.solax_local_ac_power')| float(default=0) - states('sensor.solax_local_grid_power') | int(default=0) }}"
unit_of_measurement: "W"
device_class: "power"
- name: "Solax Solar Panel"
unit_of_measurement: "W"
state: >
{% if state_attr('sensor.solax_local', 'Data') != None %}
{{ state_attr('sensor.solax_local', 'Data')[8]|int }}
{% else %} unknown {% endif %}
device_class: energy
state_class: measurement
unique_id: solax_8
icon: mdi:solar-power-variant
- name: "Solax AC Voltage"
state: >
{% if state_attr('sensor.solax_local', 'Data') != None %}
{{ state_attr('sensor.solax_local', 'Data')[0] |int/10}}
{% else %} unknown {% endif %}
unit_of_measurement: "V"
device_class: "voltage"
unique_id: solax_100
- name: "Solax AC Frequency"
state: >
{% if state_attr('sensor.solax_local', 'Data') != None %}
{{ state_attr('sensor.solax_local', 'Data')[3] |int/100}}
{% else %} unknown {% endif %}
unit_of_measurement: "Hz"
device_class: "frequency"
unique_id: solax_101
#### Solar AC Total Yield - Error Check 0 Value ###
- name: "Solax Dashboard AC Total Yield"
unique_id: solax_dashboard_ac_total_yield
state: >
{% if state_attr('sensor.solax_local', 'Data')[11] == 0 %}{{ states('sensor.solax_dashboard_ac_daily_yield') }}
{% else %}{{ (state_attr('sensor.solax_local', 'Data')[11]) | float(default=0) / 10 }}{% endif %}
unit_of_measurement: "kWh"
state_class: "total_increasing"
device_class: "energy"
#### Solar AC Dashboard Daily Yield ###
- name: "Solax Dashboard AC Daily Yield"
unique_id: solax_dashboard_ac_daily_yield
state: "{{ (state_attr('sensor.solax_local', 'Data')[13]) | float(default=0) / 10 }}"
unit_of_measurement: "kWh"
state_class: "total_increasing"
device_class: "energy"
6- Escrever em powercalc.yaml:
- platform: powercalc
entity_id: sensor.solax_local_pv_output
name: Solar Panels V2
fixed:
power: "{{ states('sensor.solax_local_pv_output')| int(default=0) }}"
- platform: powercalc
entity_id: sensor.solax_cloud_solar_panel
name: Solax Cloud Solar Panels V1
fixed:
power: "{{ states('sensor.solax_cloud_solar_panel')| int(default=0) }}"
- platform: powercalc
entity_id: sensor.solax_cloud_battery_use_in
name: Solar Cloud Battery In V1
fixed:
power: "{{states('sensor.solax_cloud_battery_use_in')}}"
- platform: powercalc
entity_id: sensor.solax_cloud_battery_use_out
name: Solar Cloud Battery Out V1
fixed:
power: "{{states('sensor.solax_cloud_battery_use_out')}}"
A partir daqui, fazer restart como normal e começar a obter valores. Fica-se com os valores da cloud e locais. Para o energy dashboard, apenas funciona com a cloud, porque o local dá os valores instantâneos (potência), não dá energia (kWh).
Isto dá uma carrada de entities, que podem procurar como solax (dá todas), local (dá todas as leituras locais) e cloud.
Tenho este pequeno cartão no lovelace:

Espero ter ajudado o pessoal com esta espécie de primeiro tutorial, que espero que não esteja repetido aqui! O tutorial foi feito com base em alguns que apanhei no reddit e na community.