on/off use different time setting

- Changed Python version constraint from ">=3.9,<3.14" to ">=3.9,<3.13" in both files.
- Updated dependency versions in pyproject.toml to use wildcard "*" for development dependencies.
- Added hash values for minimalmodbus and pyserial in requirements.txt for enhanced security.
This commit is contained in:
Zhang LongQi 2025-09-09 17:32:01 +08:00
parent 51f6477462
commit ff00635b17
6 changed files with 615 additions and 640 deletions

152
README.md
View File

@ -1,94 +1,94 @@
# 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 --onefile --windows-icon-from-ico="C:\PATH\TO\xnergy_favicon.ico" .\app.py
poetry run nuitka --standalone --windows-icon-from-ico=".\xnergy_favicon.ico" .\app.py
```
```shell
poetry run pyinstaller --onefile --icon="C:\PATH\TO\xnergy_favicon.ico" .\app.py
poetry run pyinstaller --onefile --icon=".\xnergy_favicon.ico" .\app.py
```
pyinstaller will be faster than nuitka, but sometimes the executable file generated by pyinstaller may be treated as a virus by some antivirus software.
### 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 interval time and repetition count for charging cycles, making it ideal for testing and demonstration purposes.
**Command Syntax**
```
xnergy-example.exe [-h] [-i INTERVAL] [-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.
- `-i INTERVAL, --interval INTERVAL`: Time interval (in seconds) between charger on/off cycles. Default is 1800 seconds (30 minutes).
- `-r REPEAT, --repeat REPEAT`: Number of times to repeat the charging cycle. Default is 1.
- `-q, --quiet`: Quiet mode. Suppress all output 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 interval and 1 repetition.
2. Custom interval and repeats: `xnergy-example.exe -i 3600 -r 5 COM5`
Controls the charger via COM5 with a 1-hour interval and 5 repetitions.
3. Quiet mode: `xnergy-example.exe -q COM5`
Runs on COM5 without displaying any output.
### Xnergy充电器控制演示程序说明
### 中文说明
Xnergy充电器控制演示程序是一个用于控制Xnergy充电器的工具通过RS485串口与充电器通信。该程序允许用户设置充电周期的间隔时间和重复次数适用于测试和演示场景。
**命令格式**
```
xnergy-example.exe [-h] [-i INTERVAL] [-r REPEAT] [-q] [-v] port
```
**参数说明**
- **port**必需连接到Xnergy RCU的串口设备名称如COM3、/dev/ttyUSB0
**可选参数**
- `-h, --help`:显示此帮助信息并退出。
- `-i INTERVAL, --interval INTERVAL`充电器开关切换的间隔时间默认1800秒30分钟
- `-r REPEAT, --repeat REPEAT`充电周期的重复次数默认1次。
- `-q, --quiet`:安静模式,抑制所有输出信息。
- `-v, --version`:显示程序版本号并退出。
**使用示例**
1. 基本用法:`xnergy-example.exe COM3`
通过COM3端口控制充电器使用默认间隔时间和1次重复。
2. 自定义间隔和重复次数:`xnergy-example.exe -i 3600 -r 5 COM5`
通过COM5端口控制充电器设置间隔为1小时重复5次。
3. 安静模式:`xnergy-example.exe -q COM5`
在COM5端口上运行不显示任何输出信息。

Binary file not shown.

37
app.py
View File

@ -32,18 +32,11 @@ def monitor_charger(instrument, interval=1, duration=30):
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)
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 ) '
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()
@ -62,19 +55,9 @@ def run():
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('-i',
'--interval',
type=int,
default=1800,
help='The interval time in seconds to on/off the charger, default is 1800 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('-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('--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}')
@ -83,17 +66,17 @@ def run():
instrument = Instrument(port=args.port, mode=MODE_RTU, slaveaddress=UNIT, debug=not args.quiet)
instrument.serial.baudrate = 9600
print(f'Start Charging, will start/stop charging {args.repeat} times in {args.interval} 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 counter <= args.repeat:
# start charging
instrument.write_bit(registeraddress=enable_charger_address, value=1)
monitor_charger(instrument, duration=args.interval)
monitor_charger(instrument, duration=args.duration_on)
print()
# stop charging
instrument.write_bit(registeraddress=enable_charger_address, value=0)
monitor_charger(instrument, duration=args.interval)
monitor_charger(instrument, duration=args.duration_off)
print()
counter += 1
print(f'Charging cycle {counter} completed.')

1034
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -6,7 +6,7 @@ authors = ["longqi <longqi90@gmail.com>"]
readme = "README.md"
[tool.poetry.dependencies]
python = ">=3.9,<3.14"
python = ">=3.9,<3.13"
minimalmodbus = "^2.1.1"
[build-system]
@ -14,16 +14,16 @@ requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
[tool.poetry.requires-plugins]
poetry-plugin-export = ">=1.8"
poetry-plugin-shell = ">=1.0.1"
poetry-plugin-export = "*"
poetry-plugin-shell = "*"
[tool.poetry.group.dev.dependencies]
nuitka = "^2.7.2"
poetry = "^2.1.3"
ipython = "^8.11.0"
flake8 = "^7.2.0"
yapf = "^0.43.0"
pyinstaller = "^6.13.0"
nuitka = "*"
poetry = "*"
ipython = "*"
flake8 = "*"
yapf = "*"
pyinstaller = "*"
[[tool.poetry.source]]

View File

@ -1,4 +1,6 @@
--index-url https://pypi.python.org/simple
minimalmodbus==2.1.1 ; python_version >= "3.9" and python_version < "3.14"
pyserial==3.5 ; python_version >= "3.9" and python_version < "3.14"
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