Solax X1 Hybrid G4 (local & cloud API)

@kamilb thank you so much for your guide. I’ve just got a Solax system and the dongle’s open SSID just really freaked me out.

I came across this reverse engineering repo to get the local data translation. Have you had a look at it? https://github.com/nazar-pc/solax-local-api-docs/blob/fe4d46346fb3936963e8c31ada53b870f0d73b61/Data2.txt

Witam. U mnie też działają sensory. Mam tylko jedno pytanie, czy można to pokazać w jakiś ładnych wykresach.

Been trying to get this to work but keep getting 401 unauthorized error message, I’ve changed the REG_NO and can access the inverter using a web browsers on the same network, only thing is, it doesn’t ask for a password to access the site and I think this might be complicating the process? any thoughts as I’m slowly going out my mind!

I’ve tried admin, ADMIN, Admin, the inverter 4 digit pin, blank (removing the pwd prompt) and all sorts… this really is the last part of a puzzle as we use Agile and I would really like some intelligence as to when the batteries are charging etc

(full error code content: “\r\n\r\nError\r\n<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1">\r\n\r\n

401 Unauthorized.

\r\n”
status: 401)

Just a Note for Connections with Wifi Sticks V2 (tested with Version 2.033.20 and 2.034.22).

It seems not necessary using a reverse Proxy setup with nginx to map the IP 5.8.8.8 or use downgraded Firmware to access the API on a local IP, its enough to add a “X-Forwarded-For: 5.8.8.8” header to the request.

The device shows up at my local Network as “MXCHIP”. Using:

curl --header “X-Forwarded-For: 5.8.8.8” -X POST “http://192.168.178.22/?optType=ReadRealTimeData&pwd=&”

returns the JSON data.

Important, it seems to be necessary to have the “&” at the end of the URL, otherwise my stick just crashes.

If this works, adding the following lines in your YAML configuration of the REST API allows direct access on the local IP:

rest:

  • authentication: digest
    scan_interval: 20
    resource: http://192.168.178.22
    payload: “optType=ReadRealTimeData&pwd=&”
    method: POST
    headers:
    Content-Type: “application/x-www-form-urlencoded”
    X-Forwarded-For: “5.8.8.8”
    sensor:
1 Like

Hi Kamil,

Thanks for your very clear instructions, I’ve been reading countless posts on this topic for my Inverter + Cloud API only use case.

I’ve implemented your (cloud) instructions and have all my sensors available as entities, however not getting any data from Solax…yet. Will contintue to investigate.

One particular issue I am getting is 5 x errors related to Unit of Measurement, any suggestions?

Logger: homeassistant.components.sensor
Source: components/sensor/init.py:732
integration: Sensor (documentation, issues)
First occurred: 6:13:24 AM (1 occurrences)
Last logged: 6:13:24 AM

Entity sensor.solax_cloud_grid_power (<class ‘homeassistant.components.template.sensor.SensorTemplate’>) is using native unit of measurement ‘W’ which is not a valid unit for the device class (‘energy’) it is using; expected one of [‘kWh’, ‘MJ’, ‘GJ’, ‘Wh’, ‘MWh’]; Please update your configuration if your entity is manually configured, otherwise create a bug report at Issues · home-assistant/core · GitHub

Hi @riccid. This looks like a config error - worth testing out getting of the data using something like curl or postman first. Also, worth experimenting with the entity config (e.g. changing units, or commenting certain ones out).

(Please disregard - I was missing:
“sensor powercalc_label: !include powercalc.yaml”
from my config.yaml)

sigh

Hi Kamil,

You were correct, my issue was a simple (aka moronic) one, I was using the incorrect serial number in my API url.

I have another issue after adding all the cloud based components in your post. Currently I can add Energy from Grid and Energy to Grid in the Energy dashboard, however when I attempt to add Solar production there are no ‘current’ value sensors I can use.

Any thoughts as to why? Is this an issue within my Powercalc.yaml or have I perhaps missed a step?

Bizzarely I have also been able to build a dashboard that provides a whole bunch of API based feeds from the Inverter.

Nice work. Just confirming that I have local access working directly without a proxy.

X1 - G2 with Pocket WiFi 3.0. The data is different though being its a a X1-G2 so I’m working on a map for that.

You don’t need to add an “&” if your using the pocket v3.

- platform: rest
  name: "solax_rest_local"
  scan_interval: 10
  resource: !secret solax_local_ip
  payload: !secret solax_local_realtime_payload
  method: POST
  headers:
    Content-Type: "application/x-www-form-urlencoded"
    X-Forwarded-For: "5.8.8.8"
  authentication: digest
  json_attributes:
        - sn
        - ver
        - type
        - Data
        - Information
  value_template: OK -  {{ now().strftime("%H:%M:%S") }}

Good morning
I wanted to share with you an informative integration that I find practical, it is a battery charge and recharge estimation based on Node-RED. This is of course to be adapted according to your capacity, for my part I have 6000w.

[{"id":"a4c4fbb082a29c5e","type":"function","z":"823ffcb27199a3e4","name":"function 2","func":"let soc = msg.payload\nlet payload_batt = msg.payload_batt\n\nlet kwh_resten_batteri = 6000-((6000 * soc) / 100)\nlet heur_centieme = ((kwh_resten_batteri / payload_batt).toFixed(2)).toString().split(\".\")\nlet heur = parseInt(heur_centieme[0])\n//let heur = heur_centieme[0]\n\nlet centieme = parseInt(heur_centieme[1])\nlet minute = Math.round((60 * centieme) / 100)\n\n//let heur_Minute = (heur + \"h\" + minute).toString()\nlet heur_Minute = heur + \".\" + minute\n\nreturn {heur: heur, minute: minute,heur_Minute: heur_Minute}","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":380,"y":360,"wires":[["19d909b16ed213fe"]]},{"id":"641f1388717bd659","type":"api-current-state","z":"823ffcb27199a3e4","name":"batterie charge","server":"ee46c249.bf5b7","version":3,"outputs":2,"halt_if":"0","halt_if_type":"num","halt_if_compare":"is_not","entity_id":"sensor.solax_local_battery_use_in","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload_batt","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":220,"y":360,"wires":[["a4c4fbb082a29c5e"],[]]},{"id":"9ef483368eba2406","type":"poll-state","z":"823ffcb27199a3e4","name":"soc","server":"ee46c249.bf5b7","version":3,"exposeAsEntityConfig":"","updateInterval":"1","updateIntervalType":"num","updateIntervalUnits":"minutes","outputInitially":false,"outputOnChanged":false,"entityId":"sensor.solax_local_battery_soc","stateType":"str","ifState":"","ifStateType":"str","ifStateOperator":"is_not","outputs":1,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":70,"y":380,"wires":[["641f1388717bd659","4ce0b3598691af76"]]},{"id":"19d909b16ed213fe","type":"ha-sensor","z":"823ffcb27199a3e4","name":"batt heur charge","entityConfig":"4a7f66909dbb5d8f","version":0,"state":"heur_Minute","stateType":"msg","attributes":[],"inputOverride":"allow","outputProperties":[],"x":540,"y":360,"wires":[["c911df0b83ab7abd"]]},{"id":"da14648fa965217f","type":"function","z":"823ffcb27199a3e4","name":"function 3","func":"let soc = msg.payload - 10\nlet payload_batt = msg.payload_batt\n\nlet kwh_resten_batteri = ((6000 * soc) / 100)\nlet heur_centieme = ((kwh_resten_batteri / payload_batt).toFixed(2)).toString().split(\".\")\nlet heur = parseInt(heur_centieme[0])\n//let heur = heur_centieme[0]\n\nlet centieme = parseInt(heur_centieme[1])\nlet minute = Math.round((60 * centieme) / 100)\n\nlet heur_Minute = (heur + \".\" + minute).toString() \n//let heur_Minute = heur + \".\" + minute\n\nreturn {heur: heur, minute: minute,heur_Minute: heur_Minute,}","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":400,"y":420,"wires":[["6e442fb0705d776a"]]},{"id":"4ce0b3598691af76","type":"api-current-state","z":"823ffcb27199a3e4","name":"batterie decharge","server":"ee46c249.bf5b7","version":3,"outputs":2,"halt_if":"0","halt_if_type":"num","halt_if_compare":"is_not","entity_id":"sensor.solax_local_battery_use_out","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload_batt","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":230,"y":420,"wires":[["da14648fa965217f"],[]]},{"id":"b7b85832ab9e96b8","type":"debug","z":"823ffcb27199a3e4","name":"heur decharge","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"heur_Minute","targetType":"msg","statusVal":"","statusType":"auto","x":760,"y":420,"wires":[]},{"id":"6e442fb0705d776a","type":"ha-sensor","z":"823ffcb27199a3e4","name":"batt heur decharge","entityConfig":"5d26a678d03e588e","version":0,"state":"heur_Minute","stateType":"msg","attributes":[],"inputOverride":"allow","outputProperties":[],"x":570,"y":420,"wires":[["b7b85832ab9e96b8"]]},{"id":"c911df0b83ab7abd","type":"debug","z":"823ffcb27199a3e4","name":"heur charge","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"heur_Minute","targetType":"msg","statusVal":"","statusType":"auto","x":730,"y":360,"wires":[]},{"id":"ee46c249.bf5b7","type":"server","name":"Home Assistant","addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"","connectionDelay":false,"cacheJson":false,"heartbeat":false,"heartbeatInterval":"","statusSeparator":"","enableGlobalContextStore":false},{"id":"4a7f66909dbb5d8f","type":"ha-entity-config","server":"ee46c249.bf5b7","deviceConfig":"e27b7c4e474e94ed","name":"batt heur charge","version":"6","entityType":"sensor","haConfig":[{"property":"name","value":"batt heur charge"},{"property":"icon","value":""},{"property":"entity_picture","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""}],"resend":false,"debugEnabled":false},{"id":"5d26a678d03e588e","type":"ha-entity-config","server":"ee46c249.bf5b7","deviceConfig":"66d7642f45afe0a7","name":"batt heur decharge","version":"6","entityType":"sensor","haConfig":[{"property":"name","value":"batt heur decharge"},{"property":"icon","value":""},{"property":"entity_picture","value":""},{"property":"entity_category","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""}],"resend":false,"debugEnabled":false},{"id":"e27b7c4e474e94ed","type":"ha-device-config","name":"batt heur charge","hwVersion":"","manufacturer":"Node-RED","model":"","swVersion":""},{"id":"66d7642f45afe0a7","type":"ha-device-config","name":"batt heur decharge","hwVersion":"","manufacturer":"Node-RED","model":"","swVersion":""}]