Hanwha Q CELLS

I had my QCells system installed about four weeks ago and I’ve been massively frustrated with the lack of an API.

Sooooo, I’ve been a bit busy over the last couple of few weeks working on a solution to this. I’ve done some reverse engineering of the Installer portal on port 7000 and now have a Python script that allows me to schedule the Inverter based on Solcast forecasts. I also have a second script which polls readings every 5 seconds to build up a usage history (so I have a local copy if the QCells servers ever became unavailable). Please note, I am not in any way a Python expert!

TLDR; The code is available here: GitHub - britisson/qcscheduler

Here’s a summary of my findings so far:

To log in to the Installer page on port 7000 you need to know the password. For me, this wasn’t the last four digits of the serial number, so I just clicked on Forgot Password to reset the password. It will ask you for the serial number of the inverter and your choice of new password

As for the port 9111 page - I can’t get in. Like others here, I’ve tried every username and password combo going without success. And QCells themselves have been hopeless, I’ve sent two emails and heard nothing back.

So, back to the Installer portal. Once logged in, I turned on the network inspector in Firefox and whilst performing actions I noticed a load of calls to endpoints which return JSON files. These endpoints return pretty much everything you’d want to know about the inverter. Crucially, there are also endpoints that allow you to change the inverter settings. The ones used in my scripts are:

/system/status/pcssystem
GET request. Returns detailed information about the batteries and panels, current readings for battery, inverter and grid, SOC, SOH.

/config/allnvm
GET request. I think this is mainly the current settings of the inverter. I use it in the script to get the backup battery % setting

/install/device
POST request. JSON containing the required charging regime is posted to this endpoint. You can see the details of this in the Python script or using Inspector on the Installer portal

/install/battery-sync
POST request. An empty request is posted after a call to device. No idea what it does, but in Inspector this was always called after the device endpoint

Unfortunately, these endpoints will not work unless you’re logged in, they rely on session cookie authentication. If you call them without logging in you’ll get a 401. That’s easy enough to cope with in Python and the script handles logging in. However, I’m not an expert on Home Assistant so I don’t know if it can be made to work in HA, hopefully one of you guys can read my code and see if it can be made to work.

There are other endpoints available, I don’t use these in my script but they are potentially useful:

/config/tou
GET request. Fetches all the Time Of Use settings (i.e. Time-based Mode as it’s called in the app)

/system/status/pv-meter-connect
GET request. Returns a status of the PV meter. I don’t have a PV meter in my system so this is always 0 for me

/system/status/pcsconntectstatus
GET request. PCS = Power conversion system. Returns a status of 0 or 1.

/system/status/cloudconnectstatus
GET request. Returns status of 0 or 1 to indicate if it’s connected to QCells cloud

/json/error_code_list.json
GET request. Returns a set of error code definitions which are returned by other endpoints.

/system/information/ems-version
GET request. Returns hardware and software versions

/system/information/serial-number
GET request. Does what it says on the tin

/system/information/product-model-name?EMS_serial_number=xxxxxxxxxxxxxxxx
GET request. Returns the model name and a validity check of the serial number provided

/system/information/ess-version
GET request. Returns version numbers for the batteries

/install/datetime
GET request. Returns what the inverter thinks is the current date and time

/install/network-info
GET request. Returns the IP and MAC addresses of the connected network interface (my inverter is connected by ethernet)

/system/information/installState
GET request. Returns an install_done value of 1

/system/latest-version
GET request. I think this checks for any newer versions of the inverter software, there is an updatable value which is false for me (assuming that means it’s up to date)

/install/internet-connection
POST request. You need to post {network_type: 0} which will return your local IP and a status of 1 if connected.

/resource/grid-code/default/826
GET request. I think this returns some grid settings based on the country code provided (guessing 826 is UK)

/install/ntp-status
GET request. I’m assuming this is indicating that the inverter is connected to a time server.

Unfortuantely, I can’t find an endpoint which shows usage which is why I ended up writing the readings script.

There are no doubt many more endpoints but these are all the ones I could deduce from Firefox.

I’ve set the scripts to run on a dedicated Raspberry Pi Zero 2 W with an ethernet hat. The scheduler.sh script (which in turn runs scheduler.py) is called by a CRON job every night at 23:30. The readings script is set up in /etc/rc.local to run on startup. They rely on a set of tables in a MariaDB database called QCells to record the readings, again, there is a script to do this on the Github

Apologies for such a long post. I hope you find this is useful. Happy to answer any questions and definitely welcome any feedback.