rosswarren / epevermodbus

Python library for communicating with EPever solar charge controllers
MIT License
43 stars 18 forks source link

Unsupported battery type? #17

Closed AlexAltea closed 1 year ago

AlexAltea commented 1 year ago

First, thank you very much for creating and maintaining this tool; it's brilliant!

I get the following error on the latest release of epevermodbus:

Traceback (most recent call last):
  File "/home/alexandro/.local/bin/epevermodbus", line 8, in <module>
    sys.exit(main())
  File "/home/alexandro/.local/lib/python3.9/site-packages/epevermodbus/command_line.py", line 60, in main
    print(f"Battery type: {controller.get_battery_type()}")
  File "/home/alexandro/.local/lib/python3.9/site-packages/epevermodbus/driver.py", line 271, in get_battery_type
    return {0: "USER_DEFINED", 1: "SEALED", 2: "GEL", 3: "FLOODED"}[
KeyError: 4

My controller should be set to LiFePO4. The manual shows more types than just sealed/gel/flooded/user: https://www.epever.com/wp-content/uploads/2021/05/Tracer-AN50-100A-Manual-EN-V3.1.pdf

image

However, it's not clear to me how you figure out which numerical values correspond to which types. Is it trial and error?

rosswarren commented 1 year ago

Thanks for reporting! The docs that I have for the modbus protocol make no mention of a 4th type. Could you please let me know which charge controller you have? On my Charge controller I must set "USER" battery type for a LiFePO4 battery you maybe have a newer model.

AlexAltea commented 1 year ago

I have an Epever Tracer2210AN.

On my Charge controller I must set "USER" battery type for a LiFePO4 battery you maybe have a newer model.

Right, it surprised me that most tutorials I found online said that LiFePO users should use the "USER" type when my device had clear support LiFePO4 and LiFePO8.

AlexAltea commented 1 year ago

I've decompiled the official controller software from https://www.epever.com/support/softwares/

And there's three variants of the protocol, each with support for different battery types:

    public static readonly string[] BatteryType = new string[6]
    {
      nameof (LiBattery),
      "LeadAcid(MF)",
      nameof (GelBattery),
      "LeadAcid(Liquid)",
      "LiFePO4",
      "Li-NiCoMn"
    };
    public static readonly string[] BatteryType3 = new string[11]
    {
      nameof (User),
      "LeadAcid(MF)",
      nameof (GelBattery),
      "LeadAcid(Liquid)",
      "LeadAcid(MF)User",
      nameof (GelBatteryUser),
      "LeadAcid(Liquid)User",
      nameof (LiIronBatteryNum4),
      nameof (LiThreeBatteryNum3),
      nameof (LiIronBatteryNum8),
      nameof (LiThreeBatteryNum6)
    };
    public static readonly string[] BatteryType1 = new string[4]
    {
      nameof (User),
      "LeadAcid(MF)",
      nameof (GelBattery),
      "LeadAcid(Liquid)"
    };

From searching Google it seems: LeadAcid(MF) is Sealed and LeadAcid(Liquid) is Flooded.

Also, in BatteryType, the type User appears as LiBattery (value 0). This is evidenced by the following code:

public bool IsUserType => this.batteryType == 0;

So all together:

BatteryType

Field Name Index
User 0
Sealed 1
GelBattery 2
Flooded 3
LiFePO4 4
Li-NiCoMn 5

BatteryType3

Field Name Index
User 0
Sealed 1
GelBattery 2
Flooded 3
SealedUser 4
GelBatteryUser 5
FloodedUser 6
LiIronBatteryNum4 7
LiThreeBatteryNum3 8
LiIronBatteryNum8 9
LiThreeBatteryNum6 10

BatteryType1

Field Name Index
User 0
Sealed 1
GelBattery 2
Flooded 3
rosswarren commented 1 year ago

Wow, that's great investigation! So I guess we can easily cover the case for the two shorter variants. But the one with 11 entries might be an issue as the value for 4 and 5 would conflict. We will need a way to differentiate when we are dealing with BatteryType3. Any ideas? Or was there anything in the code that might indicate when BatteryType3 might be in use?

AlexAltea commented 1 year ago

Ok, the Android app seems to be even more useful since it's sources are JavaScript which is "just minified", rather than compiled. Here's the releavant formatted file: app-service.clean.zip

It seems that the following lines are common to all devices:

this.battery_type_list = [{
    id: 0,
    val: this.$t("message.batterySetting.battery_opt.customize"),
    type: 0
}, {
    id: 1,
    val: this.$t("message.batterySetting.battery_opt.AGM"),
    type: 1
}, {
    id: 2,
    val: this.$t("message.batterySetting.battery_opt.GEL"),
    type: 2
}, {
    id: 3,
    val: this.$t("message.batterySetting.battery_opt.FLD"),
    type: 3
}

which matches your list.

But there's for some models, this list is expanded:

image

Followed by: this.battery_type_list.length < 5 && (this.battery_type_list = this.battery_type_list.concat($));

AlexAltea commented 1 year ago

Sorry I don't have an "easy" answer to your question. It seems their protocol is just a mess, and many fields are device-dependent for IDs >= 4.