Zendure SolarFlow 800/Pro Integration

Zendure recently released an API for their latest generation devices, i.e. SolarFlow 800, 800Pro, 2400AC. With this API, the devices can be accessed straight through the local network, no need for a cloud connection.

The available data points are described here:

With this (and the http-Binding), an http URL thing can be set up, which polls the device data on a regular schedule, e.g.

UID: http:url:zendure-data
label: Zendure SolarFlow800Pro Data
thingTypeUID: http:url
configuration:
  authMode: BASIC
  ignoreSSLErrors: false
  baseURL: http://<device-ip>/properties/report
  delay: 0
  stateMethod: GET
  refresh: 30
  commandMethod: GET
  timeout: 3000
  bufferSize: 2048
channels:
  - id: last-failure
    channelTypeUID: http:request-date-time
    label: Last Failure
    configuration: {}
  - id: last-success
    channelTypeUID: http:request-date-time
    label: Last Success
    configuration: {}
  - id: zendure_socLevel
    channelTypeUID: http:number
    label: SolarFlow SOC Level
    description: Battery Charge Level (%)
    configuration:
      stateTransformation:
        - JSONPATH:$.packData[0].socLevel
  - id: zendure_State
    channelTypeUID: http:number
    label: SolarFlow State
    description: Charging/Discharging State
    configuration:
      stateTransformation:
        - JSONPATH:$.packData[0].state
  - id: zendure_outputHomePower
    channelTypeUID: http:number
    label: SolarFlow Output Home Power
    description: Output power from SolarFlow to home electricity
    configuration:
      stateTransformation:
        - JSONPATH:$.properties.outputHomePower
  - id: zendure_solarInputPower
    channelTypeUID: http:number
    label: SolarFlow Solar Input Power
    description: Total solar input power to SolarFlow
    configuration:
      stateTransformation:
        - JSONPATH:$.properties.solarInputPower
  - id: zendure_packInputPower
    channelTypeUID: http:number
    label: SolarFlow Battery Pack Input Power
    description: Current Power from Battery pack (discharging)
    configuration:
      stateTransformation:
        - JSONPATH:$.properties.packInputPower
  - id: zendure_outputPackPower
    channelTypeUID: http:number
    label: SolarFlow Output Pack Power
    description: Output power to battery pack (charging)
    configuration:
      stateTransformation:
        - JSONPATH:$.properties.outputPackPower
  - id: zendure_solarPower1
    channelTypeUID: http:number
    label: SolarFlow Solar Panel 1 Power
    description: Solar Power from Panel 1
    configuration:
      stateTransformation:
        - JSONPATH:$.properties.solarPower1
  - id: zendure_solarPower2
    channelTypeUID: http:number
    label: SolarFlow Solar Panel 2 Power
    description: Solar Power from Panel 2
    configuration:
      stateTransformation:
        - JSONPATH:$.properties.solarPower2
  - id: zendure_solarPower3
    channelTypeUID: http:number
    label: SolarFlow Solar Panel 3 Power
    description: Solar Power from Panel 3
    configuration:
      stateTransformation:
        - JSONPATH:$.properties.solarPower3
  - id: zendure_solarPower4
    channelTypeUID: http:number
    label: SolarFlow Panel 4 Power
    description: Solar Power from Panel 4
    configuration:
      stateTransformation:
        - JSONPATH:$.properties.solarPower4
  - id: zendure_minSoc
    channelTypeUID: http:number
    label: SolarFlow Minimum SOC level
    description: Minimum charge level for battery
    configuration:
      stateTransformation:
        - JSONPATH:$.properties.minSoc ∩ JS(|input/10)
        - ""
  - id: zendure_socSet
    channelTypeUID: http:number
    label: SolarFlow Maximum SOC level
    description: Maximum charge level for battery
    configuration:
      stateTransformation:
        - JSONPATH:$.properties.socSet ∩ JS(|input/10)

Data is available per battery pack (one data set per battery pack as these devices can use multiple batteries) and overall device data (for the entire system). Unfortunately, the parameters of the energy management system are not accessible yet.

Please note that the number of solar panels depend on the device (and your individual setup). SOC values are given in percentages*10, that is why a quick transformation is needed.

if you call the api with a browser, much more datapoints show up (V1.0.7), I’ve asked Zendure for an updated list.

Next to reading the api json, writing to the api is also needed if OH wants to be the EMS. I’m working on this Inline Script (in Blockly) to change writeable parameters

(() => {
  const ip  = "192.168.X.Y";
  const sn  = "Your serial number";
  const url = `http://${ip}/properties/write`;

  const body = JSON.stringify({ 
    sn,
    properties: { acMode: 2 }  //example setting
  });

  try {
    const resp = actions.HTTP.sendHttpPostRequest(url, "application/json", body, 5000);
    console.log("Zendure write response:", resp);
    // Optional: parse JSON if device returns JSON
    try { console.log("Parsed:", JSON.stringify(JSON.parse(resp), null, 2)); } catch (_) {}
  } catch (e) {
    console.error("Zendure POST failed:", e);
  }
})();

Thank you for the hint and the work on setting parameters. Using the URL

http://[device-ip]//properties/report

in the browser, I get the following additional parameters

sn - the device/battery serial number

messageID - ?

product - the product name (in my case ā€œsolarFlow800Proā€œ)

packType - ?

Do you get any others? And do you have any ideas about the ā€œ?ā€ parameters?

MessageId seems to be the sequential number of a report, if you refresh the report page, the id increases. I don’t know what packType is.

This is what my report shows, no panels connected yet.

y{"timestamp":1758365923,
"messageId":2,
"sn":"xxxxxxxxxxxxx",
"version":2,
"product":"solarFlow800Pro",
"properties":{"heatState":0,
"packInputPower":0,
"outputPackPower":163,
"outputHomePower":0,
"remainOutTime":1440,
"packState":1
,"electricLevel":99,
"gridInputPower":163,
"solarInputPower":0,
"solarPower1":0,
"solarPower2":0,
"solarPower3":0,
"solarPower4":0,
"pass":0,
"reverseState":0,
"socStatus":0,
"hyperTmp":3121,
"gridOffPower":0,
"dcStatus":1,
"pvStatus":1,
"acStatus":2,
"dataReady":1,
"gridState":1,
"BatVolt":5226,
"socLimit":0,
"writeRsp":0,
"acMode":1,
"inputLimit":800,
"outputLimit":0,
"socSet":1000,
"minSoc":100,
"gridStandard":4,
"gridReverse":2,
"inverseMaxPower":800,
"lampSwitch":1,
"gridOffMode":2,
"IOTState":2,
"Fanmode":1,
"Fanspeed":0,
"bindstate":0,
"factoryModeState":0,
"OTAState":0,
"LCNState":0,
"oldMode":0,
"VoltWakeup":0,
"ts":1758364611,
"tsZone":14,
"smartMode":1,
"chargeMaxLimit":1000,
"packNum":1,
"rssi":-65,
"is_error":0},
"packData":[{"sn":"xxxxxxxxx",
"packType":300,
"socLevel":99,
"state":1,
"power":120,
"maxTemp":3111,
"totalVol":5220,
"batcur":23,
"maxVol":354,
"minVol":344,
"softVersion":4117}]}

Your write script works fine, thank you. Unfortunately, the changes made through the script are not shown in the Zendure app (e.g. for minSoc-Level). And the same range limitations as in the app seem to apply (e.g. socSet cannot be lower than 70%). I am still struggeling on how to integrate this into the corresponding http-items Channels, I have tried this Command transformation, but it does not fly:

JS(|JSON.stringify({sn:"xxxxx", properties:{minSoc:(isNaN(parseInt(input))?0:parseInt(input)*10)}})|)

Do you have any hint on how to fix this?

Let’s see if Zendure comes back with some information on the undocumented parameters, unfortunately their support quality seems to be… improvable.

I see the same happening, min/max soc levels are determined by the app, so it seems. For me, that’s not a problem, but something to look into.

If you want to manage the battery from OH, use rules and Java scripting with the script above

I did a new Binding, which translates (In my opinion) the unusable values to more usable ones. So I defined that the energyflow (power) from pv to battery or to mains is positive.
The energy flow from mains to battery is negative.
There is PV power battery power and inverter power.
i.e. only one battery power - is chargign and + is dischargign the battery.

sources are here: openhab-ibapl/de.ibapl.openhab.binding.zendure at master Ā· aploese/openhab-ibapl Ā· GitHub

a snapshot (as kar) is here: https://central.sonatype.com/repository/maven-snapshots/de/ibapl/openhab/oh-ibapl-kar/5.0.0.0-SNAPSHOT/oh-ibapl-kar-5.0.0.0-20251129.172924-1.kar

I have access to a solarflow 800 and a solarflow 800 Pro, they are working,
Currently I try to figure out the state bits and get an meaningfull overall state for the whole device and not for the parts (pv, battery and inverter).

Arne

1 Like

great developments!

My javascript based HEMS is working fine, I do have an issue connecting to the sf800Pro as soon as it starts to charge/discharge. The wifi connection seems to be unavailable for a few/several minutes. I keep getting timeouts on the properties/report calls. After minutes it seems to recover and than runs fine.

Do you see similar issues?

My case is at support of Zendure.

No, I have not observed such behaviour with my sf800pro yet. Do you have similar connectivity issues with the official app when your problem occurs? My experiences with Zendure support are rather frustrating, keeping fingers crossed for you… Did you get any feedback on your inquiries on the API?

I don’t know if there’s impact on the app itself, since it just blocks traffice a short period of time, the app will sent data to zendure anyway. Perhaps not the most actual data, but it does work most of the time.

Zendure support does need ā€˜attention’ :wink: But they are very helpfull, last week i even got a new version, which doesn’t solve the problem btw. I’m now trying to get a wireshark dump, perhaps that helps.

At the end, my own HEMS script is working perfectly, so that’s good.

I wrote a zendure ā€œitemsā€ and ā€œthingsā€ file for openHAB and sent it to the zendure SDK repository. It is now on the master branch. Maybe someone else can use it too.

2 Likes