Giter VIP home page Giter VIP logo

epevermodbus's Introduction

epevermodbus

This package is intended to help you communicate with an EPever charge controller. It has been tested with an EPever Tracer AN but should work with other EPever devices.

image

Features

  • Read real time data
  • Read battery parameters
  • Write battery parameters this feature is a work in progress
  • Automatic retries

Connecting to the charge controller

I have only tested this package on Linux / Raspberry Pi but I see no reason why it should not work on other devices.

For the cable you have two options

  • Official EPever cable

image

When using the offical cable on Linux your device will show up something like /dev/ttyXRUSB0. You will need to use a custom driver to use this cable on Linux rather than the bundled cdc-acm driver. It can be difficult to get this driver working properly on Linux and Raspberry Pi.

On Windows you can use the driver provided by EPever and the cable should work fine so long as you check the rs485 checkbox in device manager.

  • Your own custom cable

You can quite easily make your own cable if you purchase a few parts, and with this approach you won't need a custom driver on Linux so it should be easier to get working. The device should show up as something like /dev/ttyUSB0.

For more information read: https://ross-warren.co.uk/2021/08/14/building-a-cable-to-connect-my-epever-charge-controller/

Installing the package

To install the package run

pip install epevermodbus

This package requires Python 3, depending on your setup you might have to instead run:

pip3 install epevermodbus

Command line utility

To run the command line utility and see the debug output run the following on the command line:

epevermodbus --portname /dev/ttyUSB0 --slaveaddress 1
usage: epevermodbus [-h] [--portname PORTNAME] [--slaveaddress SLAVEADDRESS]

optional arguments:
  -h, --help            show this help message and exit
  --portname PORTNAME   Port name for example /dev/ttyUSB0
  --slaveaddress SLAVEADDRESS
                        Slave address 1-247
  --baudrate BAUDRATE   Baudrate to communicate with controller (default is 115200)

Example output

Real Time Data
Solar voltage: 0.02V
Solar current: 0.0A
Solar power: 0.0W
Solar power L: 0.0W
Solar power H: 0.0W
Load voltage: 0.0V
Load current: 0.0A
Load power: 0.0W
Load power L: 0.0W
Load power H: 0.0W
Battery current L: 0.0A
Battery current H: 0.0A
Battery voltage: 13.25V
Battery state of charge: 86%
Battery temperature: 16.91°C
Remote battery temperature: 0.0°C
Controller temperature: 16.55°C
Battery status: {'wrong_identifaction_for_rated_voltage': False, 'battery_inner_resistence_abnormal': False, 'temperature_warning_status': 'NORMAL', 'battery_status': 'NORMAL'}
Charging equipment status: {'input_voltage_status': 'NORMAL', 'charging_mosfet_is_short_circuit': False, 'charging_or_anti_reverse_mosfet_is_open_circuit': False, 'anti_reverse_mosfet_is_short_circuit': False, 'input_over_current': False, 'load_over_current': False, 'load_short_circuit': False, 'load_mosfet_short_circuit': False, 'disequilibrium_in_three_circuits': False, 'pv_input_short_circuit': False, 'charging_status': 'NO_CHARGING', 'fault': False, 'running': True}
Discharging equipment status: {'input_voltage_status': 'NORMAL', 'output_power_load': 'LIGHT', 'short_circuit': False, 'unable_to_discharge': False, 'unable_to_stop_discharging': False, 'output_voltage_abnormal': False, 'input_over_voltage': False, 'short_circuit_in_high_voltage_side': False, 'boost_over_voltage': False, 'output_over_voltage': False, 'fault': False, 'running': False}
Day time: False
Night time: True
Maximum battery voltage today: 14.5V
Minimum battery voltage today: 13.25V
Device over temperature: False


Battery Parameters:
Rated charging current: 20.0A
Rated load current: 20.0A
Battery real rated voltage: 12.0V
Battery type: USER_DEFINED
Battery capacity: 40AH
Temperature compensation coefficient: 0
Over voltage disconnect voltage: 14.7V
Charging limit voltage: 14.4V
Over voltage reconnect voltage: 14.6V
Equalize charging voltage: 14.4V
Boost charging voltage: 14.4V
Float charging voltage: 13.6V
Boost reconnect charging voltage: 13.3V
Low voltage reconnect voltage: 12.0V
Under voltage recover voltage: 12.0V
Under voltage warning voltage: 11.5V
Low voltage disconnect voltage: 11.0V
Discharging limit voltage: 11.0V
Battery rated voltage: 12V
Default load on/off in manual mode: OFF
Equalize duration: 0 min
Boost duration: 180 min
Battery discharge: 30%
Battery charge: 100%
Charging mode: VOLTAGE_COMPENSATION

Python usage

To use the library within your Python code

from epevermodbus.driver import EpeverChargeController


controller = EpeverChargeController("/dev/ttyUSB0", 1)

controller.get_solar_voltage()

See https://github.com/rosswarren/epevermodbus/blob/main/epevermodbus/driver.py for all available methods

epevermodbus's People

Contributors

alexverrico avatar hrford avatar rafael2k avatar rosswarren avatar smithchart avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

epevermodbus's Issues

Fix command-line tool solar power call, possibly use native power readings, add battery power.

  1. The "solar power" line shows the solar current but should be:
    print(f"Solar power: {controller.get_solar_power()}W")
  2. Is there any reason why the library makes two calls, one for voltage and one for current, when the power value is available as one call to the device? (Edit: Actually, it's two calls, or maybe even one call 0x10 for H & L, but I guess would be more accurate as the values for V and I would be calculated at the same time!?)
  3. I'd like to add a power call for the battery (0x3106 and 0x3107), as there's already functions for solar (0x3102/3) and load (0x310E/F) power.
  4. And a question about battery current. In another library, they use 0x3105 for current, but you use 0x331B/C. I'll try to get my head around this and see if we can make a two-register call using func 0x10.

This issue is for points 1 to 3

Are the retries necessary?

I added automatic retries because I get intermittent failures when communicating with my charge controller via my Raspberry PI Zero. I am not sure if these failures are expected or if it is a specific issue with my setup.

Write battery parameters

Hey, really enjoyed finding your project in amongst a few others, (from a bit too scriptey, to a bit too objectey.)
I really enjoy the abstraction you've done and the command line utility really shows off how your implementation is straight forward.

In the readme, it's stated "Write battery parameters this feature is a work in progress".

I have a Tracer 2206AN and have already written my values for a 12V 100Ah battery. It seems I chose values close to those in your example.

I've raised this issue to cover adding that functionality. Would you mind if I added that functionality and created a PR for you?

Unsupported battery type?

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?

write other parameters

Hi

I like to not only read the temperature_compensation_coefficient I want to write it as well.
Is it possible?

Regards
Christer

Automated testing / test harness

It would be nice to have some automated tests, so that the library can be quickly regression tested against a fake modbus interface when changes are made. This would reduce the time to develop new features as the library gets more complex.

Add switches to command line tool (filters, load control, etc.)

As the API might be starting to show all the information the API has to offer, I suggest we default to showing everything but could limit to certain sections by using switches.

I'm familiar with argparse and would like to implement this.
examples might include
--realtimedata, --batteryparameters or --load off

This would allow users without python knowledge to start using the API directly on the CLI.
It would also allow the command line tool to become the "demo" for your API.

Testing local changes

There should be a way to test local changes without having to publish to PyPI or making temporary changes to the code.
Currently, the import defaults to the installed version of the library.

syntax error on raspberry pi 4

Everything installed: pip install epevermodbus

python --version

Python 3.7.3
Running gives:
epevermodbus -h
Traceback (most recent call last):
File "/usr/local/bin/epevermodbus", line 6, in
from epevermodbus.command_line import main
File "/usr/local/lib/python2.7/dist-packages/epevermodbus/command_line.py", line 18
print(f"Solar voltage: {controller.get_solar_voltage()}V")
^
SyntaxError: invalid syntax
On raspberry Phyton 2 and 3 are installed. How do I install epevermodbus on python3?

Read / Set controller clock

I've implemented functions to read/set the clock of the charge controller to get valid results for the daily/weekly statistics.

  def get_clock(self):
  
    def split_short(val):
      hext = '{0:04x}'.format(val)
      ha = hext[:-2]
      hb = hext[-2:]
      return (int(ha,16), int(hb,16))
  
    r = self.retriable_read_registers(0x9013,3,3)
    min, sec = split_short(r[0])
    day, hour = split_short(r[1])
    year, mon = split_short(r[2])
    year += 2000

    curDate = datetime(year,mon,day,hour,min,sec)
    return curDate
 def set_clock(self, time):
  
    def gen_hex(a, b):
      ha = '{0:02x}'.format(a)
      hb = '{0:02x}'.format(b)
      return ha + hb
  
    r3 = int(gen_hex(time.year-2000,time.month), 16)
    r2 = int(gen_hex(time.day,time.hour), 16)
    r1 = int(gen_hex(time.minute,time.second), 16)
    self.write_registers(0x9013,[r1, r2, r3])

Can you please include these 2 functions.

I did not create a pull request since I'm not sure if this meets your requirements for clean code.

Error message after running "epevermodbus --portname /dev/ttyUSB0 --slaveaddress 1"

Hi, I'm having issues when running this command ("epevermodbus --portname /dev/ttyUSB0 --slaveaddress 1"):

"raise InvalidResponseError(text)
minimalmodbus.InvalidResponseError: Checksum error in rtu mode: b'\x01?' instead of b'I?' . The response is: b'\x01\x041\x00\x00\x01?' (plain response: b'\x01\x041\x00\x00\x01?')"

My Epever Tracer 1210AN is connected to my Raspberry Pi 4 model B through a USB to RS485 converter (CHT340)
Here is the output for "stty -F /dev/ttyUSB0":

"speed 115200 baud; line = 0;
min = 0; time = 0;
-brkint -icrnl -imaxbel
-opost -onlcr
-isig -icanon -iexten -echo -echoe -echok -echoctl -echoke"

I checked also the cabling in-between them with multimeter before actually connecting them together and everything seems to be in order.

Incorrect Battery Type

BUG report:

Battery Parameters:
Rated charging current: 40A
Rated load current: 40A
Battery real rated voltage: 24V
Traceback (most recent call last):
File "/home/kali/.local/bin/epevermodbus", line 8, in
sys.exit(main())
File "/home/kali/.local/lib/python3.10/site-packages/epevermodbus/command_line.py", line 60, in main
print(f"Battery type: {controller.get_battery_type()}")
File "/home/kali/.local/lib/python3.10/site-packages/epevermodbus/driver.py", line 271, in get_battery_type
return {0: "USER_DEFINED", 1: "SEALED", 2: "GEL", 3: "FLOODED"}[
KeyError: 0.02

In file driver.py, line 272 should be:
self.retriable_read_register(0x9000, 0, 3)
instead of
self.retriable_read_register(0x9000, 2, 3)

regards
Pavel

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.