Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e01b476d3 | ||
|
|
36c630d280 | ||
|
|
ff00635b17 | ||
|
|
51f6477462 | ||
|
|
e24444305f | ||
|
|
77743885fe | ||
|
|
3b228b0ced | ||
|
|
034b83723c |
124
.gitignore
vendored
124
.gitignore
vendored
@ -1,2 +1,122 @@
|
||||
app.dist/*
|
||||
app.bin
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
devenv
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
.idea
|
||||
.vscode
|
||||
.DS_Store
|
||||
venus/*
|
||||
*.deb
|
||||
*.deb.tar
|
||||
17
.vscode/launch.json
vendored
Normal file
17
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"name": "Python Debugger: Current File with Arguments",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "app.py",
|
||||
"console": "integratedTerminal",
|
||||
"args": "--interval 30 --repeat 2 --quiet COM14",
|
||||
}
|
||||
]
|
||||
}
|
||||
94
README.md
94
README.md
@ -1,6 +1,94 @@
|
||||
# How to use
|
||||
# Xnergy Charger Control Demo
|
||||
|
||||
### English Instructions
|
||||
|
||||
The Xnergy Charger Control Demo is a tool designed to control Xnergy chargers via RS485 serial communication. This program allows users to set the charging time and repetition count for charging cycles, making it ideal for testing and demonstration purposes.
|
||||
|
||||
**Command Syntax**
|
||||
|
||||
```shell
|
||||
xnergy-example.exe [-h] [--duration-on DURATION_ON] [--duration-off DURATION_OFF] [-r REPEAT] [-q] [-v] port
|
||||
```
|
||||
|
||||
**Positional Arguments**
|
||||
|
||||
- **port** (Required): The serial port device (e.g., COM3, /dev/ttyUSB0) connected to the Xnergy RCU.
|
||||
|
||||
**Optional Arguments**
|
||||
|
||||
- `-h, --help`: Show this help message and exit.
|
||||
- `--duration-on DURATION_ON`: Time (in seconds) to keep charging on. Default is 100 seconds.
|
||||
- `--duration-off DURATION_OFF`: Time (in seconds) to keep charging off before next charging cycle. Default is 10 seconds.
|
||||
- `-r REPEAT, --repeat REPEAT`: Number of times to repeat the charging cycle. Default is 1.
|
||||
- `-q, --quiet`: Quiet mode. Suppress all debug messages.
|
||||
- `-v, --version`: Show program version number and exit.
|
||||
|
||||
**Usage Examples**
|
||||
|
||||
1. Basic usage: `xnergy-example.exe COM3`
|
||||
Controls the charger via COM3 using default duration settings and 1 repetition.
|
||||
|
||||
2. Custom durations and repeats: `xnergy-example.exe --duration-on 30 --duration-off 5 -r 5 COM5`
|
||||
Controls the charger via COM5 with 30 seconds on, 5 seconds off, and 5 repetitions.
|
||||
|
||||
3. Quiet mode: `xnergy-example.exe -q COM5`
|
||||
Runs on COM5 without showing debug messages.
|
||||
|
||||
### Xnergy 充电器控制演示程序说明
|
||||
|
||||
### 中文说明
|
||||
|
||||
Xnergy 充电器控制演示程序是一个用于控制 Xnergy 充电器的工具,通过 RS485 串口与充电器通信。该程序允许用户设置充电周期的持续时间和重复次数,适用于测试和演示场景。
|
||||
|
||||
**命令格式**
|
||||
|
||||
```
|
||||
xnergy-example.exe [-h] [--duration-on DURATION_ON] [--duration-off DURATION_OFF] [-r REPEAT] [-q] [-v] port
|
||||
```
|
||||
|
||||
**参数说明**
|
||||
|
||||
- **port**(必需):连接到 Xnergy RCU 的串口设备名称(如 COM3、/dev/ttyUSB0)。
|
||||
|
||||
**可选参数**
|
||||
|
||||
- `-h, --help`:显示此帮助信息并退出。
|
||||
- `--duration-on DURATION_ON`:充电器开启的持续时间(秒),默认 100 秒。
|
||||
- `--duration-off DURATION_OFF`:充电器关闭的持续时间(秒),默认 10 秒。
|
||||
- `-r REPEAT, --repeat REPEAT`:充电周期的重复次数,默认 1 次。
|
||||
- `-q, --quiet`:安静模式,抑制所有调试信息。
|
||||
- `-v, --version`:显示程序版本号并退出。
|
||||
|
||||
**使用示例**
|
||||
|
||||
1. 基本用法:`xnergy-example.exe COM3`
|
||||
通过 COM3 端口控制充电器,使用默认持续时间和 1 次重复。
|
||||
|
||||
2. 自定义持续时间和重复次数:`xnergy-example.exe --duration-on 60 --duration-off 15 -r 5 COM5`
|
||||
通过 COM5 端口控制充电器,设置开启 60 秒,关闭 15 秒,重复 5 次。
|
||||
|
||||
3. 安静模式:`xnergy-example.exe -q COM5`
|
||||
在 COM5 端口上运行,不显示调试信息。
|
||||
|
||||
### How to use code
|
||||
|
||||
Please use `python3`
|
||||
|
||||
* `pip3 install -r requirements.txt`
|
||||
* `python3 app.py PORT`
|
||||
- `pip3 install -r requirements.txt`
|
||||
- `python3 app.py PORT`
|
||||
|
||||
### packaging
|
||||
|
||||
pyinstaller will be faster than nuitka, but sometimes the executable file generated by pyinstaller may be treated as a virus by some antivirus software.
|
||||
|
||||
```shell
|
||||
poetry install --no-root --all-groups
|
||||
```
|
||||
|
||||
```shell
|
||||
poetry run nuitka --standalone --windows-icon-from-ico=".\xnergy_favicon.ico" .\app.py
|
||||
```
|
||||
|
||||
```shell
|
||||
poetry run pyinstaller --onefile --icon=".\xnergy_favicon.ico" .\app.py
|
||||
```
|
||||
|
||||
BIN
README.pdf
Normal file
BIN
README.pdf
Normal file
Binary file not shown.
79
app.py
79
app.py
@ -7,10 +7,10 @@ and show the charger voltage, battery voltage and charging current
|
||||
stop charging in 30 seconds
|
||||
'''
|
||||
from minimalmodbus import Instrument, MODE_RTU
|
||||
import serial
|
||||
import sys
|
||||
import time
|
||||
|
||||
VERSION = '0.1.0'
|
||||
VERSION = '3.0.0'
|
||||
UNIT = 16
|
||||
|
||||
MODBUS_FC_READ_SINGLE_COIL = int("0x01", 16)
|
||||
@ -24,55 +24,62 @@ charger_voltage_adddress = 30
|
||||
batery_voltage_address = 32
|
||||
current_address = 31
|
||||
|
||||
|
||||
def monitor_charger(instrument, interval=1, duration=30):
|
||||
"""
|
||||
Monitor the charger voltage, battery voltage and current for a given duration.
|
||||
"""
|
||||
t = 0
|
||||
while t < duration:
|
||||
try:
|
||||
charger_voltage = instrument.read_registers(registeraddress=charger_voltage_adddress, number_of_registers=1, functioncode=MODBUS_FC_READ_INPUT_REGISTERS)
|
||||
battery_voltage = instrument.read_registers(registeraddress=batery_voltage_address, number_of_registers=1, functioncode=MODBUS_FC_READ_INPUT_REGISTERS)
|
||||
current = instrument.read_registers(registeraddress=current_address, number_of_registers=1, functioncode=MODBUS_FC_READ_INPUT_REGISTERS)
|
||||
|
||||
print(f'Time: {t}s - Charger Voltage: {charger_voltage[0]}({charger_voltage[0] / 128:.2f} V ) '
|
||||
f'Battery Voltage: {battery_voltage[0]}({battery_voltage[0] / 128:.2f} V ) '
|
||||
f'Current: {current[0]}({current[0] / 128:.2f} A )')
|
||||
sys.stdout.flush()
|
||||
except Exception as e:
|
||||
print(f'Error reading registers: {e}')
|
||||
pass
|
||||
time.sleep(interval)
|
||||
t += interval
|
||||
print()
|
||||
|
||||
|
||||
def run():
|
||||
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description='xnergy charger control demo')
|
||||
|
||||
parser.add_argument('port', type=str,
|
||||
help='The serial port(RS485) that connect to xnergy RCU')
|
||||
|
||||
# parser.add_argument('-P', '--parallel', type=int, nargs='*', choices=(17, 18, 19),
|
||||
# help='set to parallel mode, parameter is the unit id, can be used multiple times')
|
||||
|
||||
parser.add_argument('-v', '--verbose', action='count', default=0,
|
||||
help='verbose mode, show more information')
|
||||
parser.add_argument('port', type=str, help='The serial port(RS485) that connect to xnergy RCU')
|
||||
parser.add_argument('--duration-on', type=int, default=100, help='The duration time in seconds to keep the charger on, default is 100 seconds')
|
||||
parser.add_argument('--duration-off', type=int, default=10, help='The duration time in seconds to keep the charger off, default is 10 seconds')
|
||||
parser.add_argument('-r', '--repeat', type=int, default=1, help='The number of times to repeat the charging cycle, default is 1')
|
||||
|
||||
parser.add_argument('-q', '--quiet', action='store_true', help='quiet mode, suppress all output')
|
||||
parser.add_argument('-v', '--version', action='version', version=f'%(prog)s {VERSION}')
|
||||
args = parser.parse_args()
|
||||
|
||||
instrument = Instrument(port=args.port, mode=MODE_RTU, slaveaddress=UNIT, debug=True)
|
||||
instrument = Instrument(port=args.port, mode=MODE_RTU, slaveaddress=UNIT, debug=not args.quiet)
|
||||
instrument.serial.baudrate = 9600
|
||||
# start charging
|
||||
instrument.write_bit(registeraddress=enable_charger_address, value=1)
|
||||
print('Start Charging, will stop charging in 30 seconds')
|
||||
|
||||
print(f'Start Charging, will start/stop charging {args.repeat} times with on duration {args.duration_on}s and off duration {args.duration_off}s')
|
||||
|
||||
counter = 0
|
||||
while True:
|
||||
charger_voltage = instrument.read_registers(registeraddress=charger_voltage_adddress, number_of_registers=1,
|
||||
functioncode=MODBUS_FC_READ_INPUT_REGISTERS)
|
||||
battery_voltage = instrument.read_registers(registeraddress=batery_voltage_address, number_of_registers=1,
|
||||
functioncode=MODBUS_FC_READ_INPUT_REGISTERS)
|
||||
current = instrument.read_registers(registeraddress=current_address, number_of_registers=1,
|
||||
functioncode=MODBUS_FC_READ_INPUT_REGISTERS)
|
||||
|
||||
print(
|
||||
str(counter) + ' '
|
||||
|
||||
'Charger voltage: ' + str(charger_voltage) + ' '
|
||||
'Battery voltage: ' + str(battery_voltage) + ' '
|
||||
'Current: ' + str(current)
|
||||
, end='\r', flush=True)
|
||||
|
||||
counter += 1
|
||||
if counter > 30:
|
||||
break
|
||||
time.sleep(1)
|
||||
while counter <= args.repeat:
|
||||
# start charging
|
||||
instrument.write_bit(registeraddress=enable_charger_address, value=1)
|
||||
monitor_charger(instrument, duration=args.duration_on)
|
||||
print()
|
||||
|
||||
# stop charging
|
||||
instrument.write_bit(registeraddress=enable_charger_address, value=0)
|
||||
print('Stop Charging')
|
||||
monitor_charger(instrument, duration=args.duration_off)
|
||||
print()
|
||||
counter += 1
|
||||
print(f'Charging cycle {counter} completed.')
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
2514
poetry.lock
generated
2514
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@ -1,18 +1,50 @@
|
||||
[tool.poetry]
|
||||
name = "xnergy-example"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
description = "An example for Xnergy charger"
|
||||
authors = ["longqi <longqi90@gmail.com>"]
|
||||
readme = "README.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.8,<4.0"
|
||||
python = ">=3.9,<3.13"
|
||||
minimalmodbus = "^2.1.1"
|
||||
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
nuitka = "^2.7.2"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry.requires-plugins]
|
||||
poetry-plugin-export = "*"
|
||||
poetry-plugin-shell = "*"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
nuitka = "*"
|
||||
poetry = "*"
|
||||
ipython = "*"
|
||||
flake8 = "*"
|
||||
yapf = "*"
|
||||
pyinstaller = "*"
|
||||
|
||||
|
||||
[[tool.poetry.source]]
|
||||
name = "default"
|
||||
url = "https://pypi.python.org/simple/"
|
||||
priority = "primary"
|
||||
|
||||
[[tool.poetry.source]]
|
||||
name = "aliyun"
|
||||
url = "https://mirrors.aliyun.com/pypi/simple/"
|
||||
priority = "supplemental"
|
||||
|
||||
[[tool.poetry.source]]
|
||||
name = "tsinghua"
|
||||
url = "https://pypi.tuna.tsinghua.edu.cn/simple/"
|
||||
priority = "supplemental"
|
||||
|
||||
[tool.yapf]
|
||||
use_tabs = true
|
||||
column_limit = 120
|
||||
continuation_align_style = "valign-right"
|
||||
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
|
||||
@ -1,2 +1,6 @@
|
||||
minimalmodbus==2.1.1 ; python_version >= "3.8" and python_version < "4.0"
|
||||
pyserial==3.5 ; python_version >= "3.8" and python_version < "4.0"
|
||||
minimalmodbus==2.1.1 ; python_version >= "3.9" and python_version < "3.13" \
|
||||
--hash=sha256:75c677e2f3ea901b762f8b2ab7cf8ad84de915bbea275d66e30b724e23887b1a \
|
||||
--hash=sha256:c3f5a56e107d537e4bb420f7e735841ab2939c8ca6fb528f5fe4124571315b64
|
||||
pyserial==3.5 ; python_version >= "3.9" and python_version < "3.13" \
|
||||
--hash=sha256:3c77e014170dfffbd816e6ffc205e9842efb10be9f58ec16d3e8675b4925cddb \
|
||||
--hash=sha256:c4451db6ba391ca6ca299fb3ec7bae67a5c55dde170964c7a14ceefec02f2cf0
|
||||
|
||||
BIN
xnergy_favicon.ico
Normal file
BIN
xnergy_favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
Loading…
x
Reference in New Issue
Block a user