bluetti-modbus-lib 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bluetti_modbus_lib-0.0.1/LICENSE +21 -0
- bluetti_modbus_lib-0.0.1/PKG-INFO +115 -0
- bluetti_modbus_lib-0.0.1/README.md +88 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib/__init__.py +0 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib/base_devices/__init__.py +2 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib/base_devices/balco.py +63 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib/base_devices/bluetti_device.py +13 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib/devices/__init__.py +2 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib/devices/balco260.py +6 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib/devices/transfer_hub.py +6 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib/fields/DeviceField.py +23 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib/fields/UIntField.py +35 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib/fields/__init__.py +2 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib/modbus/__init__.py +1 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib/modbus/client.py +62 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib/scripts/__init__.py +0 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib/scripts/bluetti_modread.py +30 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib.egg-info/PKG-INFO +115 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib.egg-info/SOURCES.txt +23 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib.egg-info/dependency_links.txt +1 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib.egg-info/entry_points.txt +2 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib.egg-info/requires.txt +4 -0
- bluetti_modbus_lib-0.0.1/bluetti_modbus_lib.egg-info/top_level.txt +1 -0
- bluetti_modbus_lib-0.0.1/setup.cfg +4 -0
- bluetti_modbus_lib-0.0.1/setup.py +43 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Patrick762
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bluetti-modbus-lib
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Bluetti Modbus
|
|
5
|
+
Home-page: https://github.com/Patrick762/bluetti-modbus-lib
|
|
6
|
+
Author: Patrick762
|
|
7
|
+
Author-email: <pip-bluetti-modbus-lib@hosting-rt.de>
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: async_timeout
|
|
14
|
+
Requires-Dist: asyncio
|
|
15
|
+
Requires-Dist: pymodbus
|
|
16
|
+
Requires-Dist: logging
|
|
17
|
+
Dynamic: author
|
|
18
|
+
Dynamic: author-email
|
|
19
|
+
Dynamic: classifier
|
|
20
|
+
Dynamic: description
|
|
21
|
+
Dynamic: description-content-type
|
|
22
|
+
Dynamic: home-page
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
Dynamic: requires-dist
|
|
25
|
+
Dynamic: summary
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# bluetti-modbus-lib
|
|
29
|
+
Inofficial Library for basic communication to bluetti powerstations via Modbus.
|
|
30
|
+
|
|
31
|
+
Based on official documentation https://github.com/bluetti-official/bluetti-modbus-tcp-slave
|
|
32
|
+
|
|
33
|
+
You have to enable Modbus TCP in the webinterface of your device first.
|
|
34
|
+
|
|
35
|
+
## Disclaimer
|
|
36
|
+
This library is provided without any warranty or support by Bluetti. I do not take responsibility for any problems it may cause in all cases. Use it at your own risk.
|
|
37
|
+
|
|
38
|
+
## Supported devices and data
|
|
39
|
+
|
|
40
|
+
TBD
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install bluetti-modbus-lib
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Commands for testing
|
|
49
|
+
|
|
50
|
+
Commands included in this library should only be used for testing.
|
|
51
|
+
|
|
52
|
+
### Read device data for supported devices
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
usage: bluetti-modread [-h] [-c HOST] [-p PORT] [-t TYPE]
|
|
56
|
+
|
|
57
|
+
Read bluetti devices via modbus
|
|
58
|
+
|
|
59
|
+
options:
|
|
60
|
+
-h, --help show this help message and exit
|
|
61
|
+
-c HOST, --host HOST IP-address of the device
|
|
62
|
+
-p PORT, --port PORT Port of the device
|
|
63
|
+
-t TYPE, --type TYPE Device type
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Example:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
bluetti-modread -c 10.2.1.60 -p 502 -t balco260
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Example output:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
num_inverters: 1 pcs
|
|
76
|
+
ac_load_power_total: 0 W
|
|
77
|
+
pv_power_total: 0 W
|
|
78
|
+
grid_power_total: 0 W
|
|
79
|
+
inverter_out_power_total: 0 W
|
|
80
|
+
pv_to_ac_power: 0 W
|
|
81
|
+
ac_load_energy_total: 0.1 kWh
|
|
82
|
+
pv_to_ac_load_energy_total: 0.1 kWh
|
|
83
|
+
pc_charging_energy_total: 0.0 kWh
|
|
84
|
+
grid_charging_energy_total: 0.0 kWh
|
|
85
|
+
grid_export_energy_total: 0.0 kWh
|
|
86
|
+
input_power_pv1: 0 W
|
|
87
|
+
input_voltage_pv1: 0.0 V
|
|
88
|
+
input_current_pv1: 0.0 A
|
|
89
|
+
input_power_pv2: 0 W
|
|
90
|
+
input_voltage_pv2: 0.0 V
|
|
91
|
+
input_current_pv2: 0.0 A
|
|
92
|
+
input_power_pv3: 0 W
|
|
93
|
+
input_voltage_pv3: 0.0 V
|
|
94
|
+
input_current_pv3: 0.0 A
|
|
95
|
+
input_power_pv4: 0 W
|
|
96
|
+
input_voltage_pv4: 0.0 V
|
|
97
|
+
input_current_pv4: 0.0 A
|
|
98
|
+
num_packs: 0 pcs
|
|
99
|
+
total_bat_voltage: 25.900000000000002 V
|
|
100
|
+
total_bat_current: 0.7000000000000001 A
|
|
101
|
+
total_bat_soc: 0 %
|
|
102
|
+
total_bat_soh: 0 %
|
|
103
|
+
total_bat_charge_time: 0 Min
|
|
104
|
+
total_bat_discharge_time: 0 Min
|
|
105
|
+
pack_voltage: 25.900000000000002 V
|
|
106
|
+
pack_current: 2999.3 A
|
|
107
|
+
pack_soc: 36 %
|
|
108
|
+
pack_soh: 100 %
|
|
109
|
+
pack_cycles: 0 times
|
|
110
|
+
pack_temp_avg: 0 °C
|
|
111
|
+
pack_cell_count: 8 pcs
|
|
112
|
+
pack_ntc_count: 4 pcs
|
|
113
|
+
pack_energy_charged: 2580 Wh
|
|
114
|
+
pack_energy_discharged: 2500 Wh
|
|
115
|
+
```
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# bluetti-modbus-lib
|
|
2
|
+
Inofficial Library for basic communication to bluetti powerstations via Modbus.
|
|
3
|
+
|
|
4
|
+
Based on official documentation https://github.com/bluetti-official/bluetti-modbus-tcp-slave
|
|
5
|
+
|
|
6
|
+
You have to enable Modbus TCP in the webinterface of your device first.
|
|
7
|
+
|
|
8
|
+
## Disclaimer
|
|
9
|
+
This library is provided without any warranty or support by Bluetti. I do not take responsibility for any problems it may cause in all cases. Use it at your own risk.
|
|
10
|
+
|
|
11
|
+
## Supported devices and data
|
|
12
|
+
|
|
13
|
+
TBD
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install bluetti-modbus-lib
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Commands for testing
|
|
22
|
+
|
|
23
|
+
Commands included in this library should only be used for testing.
|
|
24
|
+
|
|
25
|
+
### Read device data for supported devices
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
usage: bluetti-modread [-h] [-c HOST] [-p PORT] [-t TYPE]
|
|
29
|
+
|
|
30
|
+
Read bluetti devices via modbus
|
|
31
|
+
|
|
32
|
+
options:
|
|
33
|
+
-h, --help show this help message and exit
|
|
34
|
+
-c HOST, --host HOST IP-address of the device
|
|
35
|
+
-p PORT, --port PORT Port of the device
|
|
36
|
+
-t TYPE, --type TYPE Device type
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Example:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
bluetti-modread -c 10.2.1.60 -p 502 -t balco260
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Example output:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
num_inverters: 1 pcs
|
|
49
|
+
ac_load_power_total: 0 W
|
|
50
|
+
pv_power_total: 0 W
|
|
51
|
+
grid_power_total: 0 W
|
|
52
|
+
inverter_out_power_total: 0 W
|
|
53
|
+
pv_to_ac_power: 0 W
|
|
54
|
+
ac_load_energy_total: 0.1 kWh
|
|
55
|
+
pv_to_ac_load_energy_total: 0.1 kWh
|
|
56
|
+
pc_charging_energy_total: 0.0 kWh
|
|
57
|
+
grid_charging_energy_total: 0.0 kWh
|
|
58
|
+
grid_export_energy_total: 0.0 kWh
|
|
59
|
+
input_power_pv1: 0 W
|
|
60
|
+
input_voltage_pv1: 0.0 V
|
|
61
|
+
input_current_pv1: 0.0 A
|
|
62
|
+
input_power_pv2: 0 W
|
|
63
|
+
input_voltage_pv2: 0.0 V
|
|
64
|
+
input_current_pv2: 0.0 A
|
|
65
|
+
input_power_pv3: 0 W
|
|
66
|
+
input_voltage_pv3: 0.0 V
|
|
67
|
+
input_current_pv3: 0.0 A
|
|
68
|
+
input_power_pv4: 0 W
|
|
69
|
+
input_voltage_pv4: 0.0 V
|
|
70
|
+
input_current_pv4: 0.0 A
|
|
71
|
+
num_packs: 0 pcs
|
|
72
|
+
total_bat_voltage: 25.900000000000002 V
|
|
73
|
+
total_bat_current: 0.7000000000000001 A
|
|
74
|
+
total_bat_soc: 0 %
|
|
75
|
+
total_bat_soh: 0 %
|
|
76
|
+
total_bat_charge_time: 0 Min
|
|
77
|
+
total_bat_discharge_time: 0 Min
|
|
78
|
+
pack_voltage: 25.900000000000002 V
|
|
79
|
+
pack_current: 2999.3 A
|
|
80
|
+
pack_soc: 36 %
|
|
81
|
+
pack_soh: 100 %
|
|
82
|
+
pack_cycles: 0 times
|
|
83
|
+
pack_temp_avg: 0 °C
|
|
84
|
+
pack_cell_count: 8 pcs
|
|
85
|
+
pack_ntc_count: 4 pcs
|
|
86
|
+
pack_energy_charged: 2580 Wh
|
|
87
|
+
pack_energy_discharged: 2500 Wh
|
|
88
|
+
```
|
|
File without changes
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
from . import BluettiDevice
|
|
2
|
+
from ..fields import UIntField
|
|
3
|
+
|
|
4
|
+
# TODO Strings, Versions, Enums, SN
|
|
5
|
+
|
|
6
|
+
class BaseDeviceBalco(BluettiDevice):
|
|
7
|
+
def __init__(self):
|
|
8
|
+
super().__init__(
|
|
9
|
+
[
|
|
10
|
+
# Inverter summmary
|
|
11
|
+
UIntField("num_inverters", 50001, "pcs", min=1, max=10),
|
|
12
|
+
UIntField("ac_load_power_total", 50002, "W"),
|
|
13
|
+
UIntField("pv_power_total", 50004, "W"),
|
|
14
|
+
UIntField("grid_power_total", 50006, "W"),
|
|
15
|
+
UIntField("inverter_out_power_total", 50008, "W"),
|
|
16
|
+
UIntField("pv_to_ac_power", 50010, "W"),
|
|
17
|
+
|
|
18
|
+
UIntField("ac_load_energy_total", 50012, "kWh", multiplier=0.1),
|
|
19
|
+
UIntField("pc_charging_energy_total", 50014, "kWh", multiplier=0.1),
|
|
20
|
+
UIntField("grid_charging_energy_total", 50016, "kWh", multiplier=0.1),
|
|
21
|
+
UIntField("grid_export_energy_total", 50018, "kWh", multiplier=0.1),
|
|
22
|
+
UIntField("pv_to_ac_load_energy_total", 50012, "kWh", multiplier=0.1),
|
|
23
|
+
|
|
24
|
+
# MPPT details
|
|
25
|
+
UIntField("input_power_pv1", 50269, "W"),
|
|
26
|
+
UIntField("input_voltage_pv1", 50270, "V", multiplier=0.1),
|
|
27
|
+
UIntField("input_current_pv1", 50271, "A", multiplier=0.1),
|
|
28
|
+
|
|
29
|
+
UIntField("input_power_pv2", 50273, "W"),
|
|
30
|
+
UIntField("input_voltage_pv2", 50274, "V", multiplier=0.1),
|
|
31
|
+
UIntField("input_current_pv2", 50275, "A", multiplier=0.1),
|
|
32
|
+
|
|
33
|
+
UIntField("input_power_pv3", 50277, "W"),
|
|
34
|
+
UIntField("input_voltage_pv3", 50278, "V", multiplier=0.1),
|
|
35
|
+
UIntField("input_current_pv3", 50279, "A", multiplier=0.1),
|
|
36
|
+
|
|
37
|
+
UIntField("input_power_pv4", 50281, "W"),
|
|
38
|
+
UIntField("input_voltage_pv4", 50282, "V", multiplier=0.1),
|
|
39
|
+
UIntField("input_current_pv4", 50283, "A", multiplier=0.1),
|
|
40
|
+
|
|
41
|
+
# Pack Summary
|
|
42
|
+
UIntField("num_packs", 51001, "pcs", min=1, max=16),
|
|
43
|
+
UIntField("total_bat_voltage", 51002, "V", multiplier=0.1),
|
|
44
|
+
UIntField("total_bat_current", 51003, "A", multiplier=0.1),
|
|
45
|
+
UIntField("total_bat_soc", 51004, "%", min=0, max=100),
|
|
46
|
+
UIntField("total_bat_soh", 51005, "%", min=0, max=100),
|
|
47
|
+
|
|
48
|
+
UIntField("total_bat_charge_time", 51007, "Min"),
|
|
49
|
+
UIntField("total_bat_discharge_time", 51008, "Min"),
|
|
50
|
+
|
|
51
|
+
# Single pack details
|
|
52
|
+
UIntField("pack_voltage", 51219, "V", multiplier=0.1),
|
|
53
|
+
UIntField("pack_current", 51220, "A", multiplier=0.1),
|
|
54
|
+
UIntField("pack_soc", 51221, "%", min=0, max=100),
|
|
55
|
+
UIntField("pack_soh", 51222, "%", min=0, max=100),
|
|
56
|
+
UIntField("pack_cycles", 51223, "times"),
|
|
57
|
+
UIntField("pack_temp_avg", 51224, "°C"),
|
|
58
|
+
UIntField("pack_cell_count", 51234, "pcs"),
|
|
59
|
+
UIntField("pack_ntc_count", 51235, "pcs"),
|
|
60
|
+
UIntField("pack_energy_charged", 51236, "Wh"),
|
|
61
|
+
UIntField("pack_energy_discharged", 51238, "Wh"),
|
|
62
|
+
],
|
|
63
|
+
)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from pymodbus.client import ModbusTcpClient
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class DeviceField:
|
|
7
|
+
def __init__(self, name: str, address: int, unit: str, size: int):
|
|
8
|
+
self.name = name
|
|
9
|
+
self.address = address
|
|
10
|
+
self.unit = unit
|
|
11
|
+
self.size = size
|
|
12
|
+
|
|
13
|
+
def parse(self, client: ModbusTcpClient, data: list[int]) -> Any:
|
|
14
|
+
raise NotImplementedError
|
|
15
|
+
|
|
16
|
+
def is_writeable(self) -> bool:
|
|
17
|
+
return False
|
|
18
|
+
|
|
19
|
+
def allowed_write_type(self, value: Any) -> bool:
|
|
20
|
+
return False
|
|
21
|
+
|
|
22
|
+
def in_range(self, value: Any) -> bool:
|
|
23
|
+
return True
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from pymodbus.client import ModbusTcpClient
|
|
4
|
+
|
|
5
|
+
from . import DeviceField
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class UIntField(DeviceField):
|
|
9
|
+
def __init__(
|
|
10
|
+
self,
|
|
11
|
+
name: str,
|
|
12
|
+
address: int,
|
|
13
|
+
unit: str,
|
|
14
|
+
multiplier: float = 1,
|
|
15
|
+
min: int | None = None,
|
|
16
|
+
max: int | None = None,
|
|
17
|
+
):
|
|
18
|
+
super().__init__(name, address, unit, 1)
|
|
19
|
+
self.multiplier = multiplier
|
|
20
|
+
self.min = min
|
|
21
|
+
self.max = max
|
|
22
|
+
|
|
23
|
+
def parse(self, client: ModbusTcpClient, data: bytes) -> Any:
|
|
24
|
+
return client.convert_from_registers(
|
|
25
|
+
data,
|
|
26
|
+
client.DATATYPE.UINT16,
|
|
27
|
+
word_order="little",
|
|
28
|
+
) * self.multiplier
|
|
29
|
+
|
|
30
|
+
def in_range(self, value: int) -> bool:
|
|
31
|
+
if self.min is not None and self.min > value:
|
|
32
|
+
return False
|
|
33
|
+
if self.max is not None and self.max < value:
|
|
34
|
+
return False
|
|
35
|
+
return value >= 0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .client import BluettiModbusClient
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Any, List
|
|
3
|
+
|
|
4
|
+
import async_timeout
|
|
5
|
+
from pymodbus.client import ModbusTcpClient
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
|
|
8
|
+
from ..base_devices.bluetti_device import BluettiDevice
|
|
9
|
+
|
|
10
|
+
LOGGER = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class ClientReturnValue:
|
|
14
|
+
name: str
|
|
15
|
+
unit: str
|
|
16
|
+
value: Any
|
|
17
|
+
|
|
18
|
+
def __str__(self):
|
|
19
|
+
return f"{self.name}: {self.value} {self.unit}"
|
|
20
|
+
|
|
21
|
+
class BluettiModbusClient:
|
|
22
|
+
def __init__(self, host: str, port: int, device: BluettiDevice):
|
|
23
|
+
self.client = ModbusTcpClient(host, port=port)
|
|
24
|
+
self.device = device
|
|
25
|
+
|
|
26
|
+
async def read(self) -> List[ClientReturnValue]:
|
|
27
|
+
buffer = []
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
async with async_timeout.timeout(5):
|
|
31
|
+
LOGGER.debug("Connecting to device ...")
|
|
32
|
+
|
|
33
|
+
# Connect to device
|
|
34
|
+
retries_left = 5
|
|
35
|
+
while retries_left > 0:
|
|
36
|
+
LOGGER.debug(f"{retries_left} retries remaining")
|
|
37
|
+
if not self.client.connected:
|
|
38
|
+
self.client.connect()
|
|
39
|
+
retries_left = retries_left - 1
|
|
40
|
+
else:
|
|
41
|
+
break
|
|
42
|
+
|
|
43
|
+
LOGGER.debug("Connected to device")
|
|
44
|
+
|
|
45
|
+
# Read registers
|
|
46
|
+
for register in self.device.fields:
|
|
47
|
+
LOGGER.debug(f"Reading register at address {register.address}")
|
|
48
|
+
|
|
49
|
+
result = self.client.read_holding_registers(
|
|
50
|
+
address=register.address,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if len(result.registers) == 1:
|
|
54
|
+
parsed = register.parse(self.client, result.registers)
|
|
55
|
+
buffer.append(ClientReturnValue(register.name, register.unit, parsed))
|
|
56
|
+
|
|
57
|
+
except TimeoutError:
|
|
58
|
+
LOGGER.error("Timeout")
|
|
59
|
+
finally:
|
|
60
|
+
self.client.close()
|
|
61
|
+
|
|
62
|
+
return buffer
|
|
File without changes
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import asyncio
|
|
3
|
+
|
|
4
|
+
from ..devices import Balco260
|
|
5
|
+
from ..modbus import BluettiModbusClient
|
|
6
|
+
|
|
7
|
+
async def async_read(host: str, port: int, type: str):
|
|
8
|
+
if type != "balco260":
|
|
9
|
+
print("Only 'balco260' supported as type")
|
|
10
|
+
return
|
|
11
|
+
|
|
12
|
+
client = BluettiModbusClient(host, port, Balco260())
|
|
13
|
+
|
|
14
|
+
result = await client.read()
|
|
15
|
+
|
|
16
|
+
for r in result:
|
|
17
|
+
print(r)
|
|
18
|
+
|
|
19
|
+
def start():
|
|
20
|
+
parser = argparse.ArgumentParser(description="Read bluetti devices via modbus")
|
|
21
|
+
parser.add_argument("-c", "--host", type=str, help="IP-address of the device")
|
|
22
|
+
parser.add_argument("-p", "--port", type=int, help="Port of the device")
|
|
23
|
+
parser.add_argument("-t", "--type", type=str, help="Device type")
|
|
24
|
+
args = parser.parse_args()
|
|
25
|
+
|
|
26
|
+
if args.host is None or args.port is None or args.type is None:
|
|
27
|
+
parser.print_help()
|
|
28
|
+
return
|
|
29
|
+
|
|
30
|
+
asyncio.run(async_read(args.host, args.port, args.type))
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bluetti-modbus-lib
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Bluetti Modbus
|
|
5
|
+
Home-page: https://github.com/Patrick762/bluetti-modbus-lib
|
|
6
|
+
Author: Patrick762
|
|
7
|
+
Author-email: <pip-bluetti-modbus-lib@hosting-rt.de>
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: async_timeout
|
|
14
|
+
Requires-Dist: asyncio
|
|
15
|
+
Requires-Dist: pymodbus
|
|
16
|
+
Requires-Dist: logging
|
|
17
|
+
Dynamic: author
|
|
18
|
+
Dynamic: author-email
|
|
19
|
+
Dynamic: classifier
|
|
20
|
+
Dynamic: description
|
|
21
|
+
Dynamic: description-content-type
|
|
22
|
+
Dynamic: home-page
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
Dynamic: requires-dist
|
|
25
|
+
Dynamic: summary
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# bluetti-modbus-lib
|
|
29
|
+
Inofficial Library for basic communication to bluetti powerstations via Modbus.
|
|
30
|
+
|
|
31
|
+
Based on official documentation https://github.com/bluetti-official/bluetti-modbus-tcp-slave
|
|
32
|
+
|
|
33
|
+
You have to enable Modbus TCP in the webinterface of your device first.
|
|
34
|
+
|
|
35
|
+
## Disclaimer
|
|
36
|
+
This library is provided without any warranty or support by Bluetti. I do not take responsibility for any problems it may cause in all cases. Use it at your own risk.
|
|
37
|
+
|
|
38
|
+
## Supported devices and data
|
|
39
|
+
|
|
40
|
+
TBD
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install bluetti-modbus-lib
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Commands for testing
|
|
49
|
+
|
|
50
|
+
Commands included in this library should only be used for testing.
|
|
51
|
+
|
|
52
|
+
### Read device data for supported devices
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
usage: bluetti-modread [-h] [-c HOST] [-p PORT] [-t TYPE]
|
|
56
|
+
|
|
57
|
+
Read bluetti devices via modbus
|
|
58
|
+
|
|
59
|
+
options:
|
|
60
|
+
-h, --help show this help message and exit
|
|
61
|
+
-c HOST, --host HOST IP-address of the device
|
|
62
|
+
-p PORT, --port PORT Port of the device
|
|
63
|
+
-t TYPE, --type TYPE Device type
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Example:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
bluetti-modread -c 10.2.1.60 -p 502 -t balco260
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Example output:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
num_inverters: 1 pcs
|
|
76
|
+
ac_load_power_total: 0 W
|
|
77
|
+
pv_power_total: 0 W
|
|
78
|
+
grid_power_total: 0 W
|
|
79
|
+
inverter_out_power_total: 0 W
|
|
80
|
+
pv_to_ac_power: 0 W
|
|
81
|
+
ac_load_energy_total: 0.1 kWh
|
|
82
|
+
pv_to_ac_load_energy_total: 0.1 kWh
|
|
83
|
+
pc_charging_energy_total: 0.0 kWh
|
|
84
|
+
grid_charging_energy_total: 0.0 kWh
|
|
85
|
+
grid_export_energy_total: 0.0 kWh
|
|
86
|
+
input_power_pv1: 0 W
|
|
87
|
+
input_voltage_pv1: 0.0 V
|
|
88
|
+
input_current_pv1: 0.0 A
|
|
89
|
+
input_power_pv2: 0 W
|
|
90
|
+
input_voltage_pv2: 0.0 V
|
|
91
|
+
input_current_pv2: 0.0 A
|
|
92
|
+
input_power_pv3: 0 W
|
|
93
|
+
input_voltage_pv3: 0.0 V
|
|
94
|
+
input_current_pv3: 0.0 A
|
|
95
|
+
input_power_pv4: 0 W
|
|
96
|
+
input_voltage_pv4: 0.0 V
|
|
97
|
+
input_current_pv4: 0.0 A
|
|
98
|
+
num_packs: 0 pcs
|
|
99
|
+
total_bat_voltage: 25.900000000000002 V
|
|
100
|
+
total_bat_current: 0.7000000000000001 A
|
|
101
|
+
total_bat_soc: 0 %
|
|
102
|
+
total_bat_soh: 0 %
|
|
103
|
+
total_bat_charge_time: 0 Min
|
|
104
|
+
total_bat_discharge_time: 0 Min
|
|
105
|
+
pack_voltage: 25.900000000000002 V
|
|
106
|
+
pack_current: 2999.3 A
|
|
107
|
+
pack_soc: 36 %
|
|
108
|
+
pack_soh: 100 %
|
|
109
|
+
pack_cycles: 0 times
|
|
110
|
+
pack_temp_avg: 0 °C
|
|
111
|
+
pack_cell_count: 8 pcs
|
|
112
|
+
pack_ntc_count: 4 pcs
|
|
113
|
+
pack_energy_charged: 2580 Wh
|
|
114
|
+
pack_energy_discharged: 2500 Wh
|
|
115
|
+
```
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
setup.py
|
|
4
|
+
bluetti_modbus_lib/__init__.py
|
|
5
|
+
bluetti_modbus_lib.egg-info/PKG-INFO
|
|
6
|
+
bluetti_modbus_lib.egg-info/SOURCES.txt
|
|
7
|
+
bluetti_modbus_lib.egg-info/dependency_links.txt
|
|
8
|
+
bluetti_modbus_lib.egg-info/entry_points.txt
|
|
9
|
+
bluetti_modbus_lib.egg-info/requires.txt
|
|
10
|
+
bluetti_modbus_lib.egg-info/top_level.txt
|
|
11
|
+
bluetti_modbus_lib/base_devices/__init__.py
|
|
12
|
+
bluetti_modbus_lib/base_devices/balco.py
|
|
13
|
+
bluetti_modbus_lib/base_devices/bluetti_device.py
|
|
14
|
+
bluetti_modbus_lib/devices/__init__.py
|
|
15
|
+
bluetti_modbus_lib/devices/balco260.py
|
|
16
|
+
bluetti_modbus_lib/devices/transfer_hub.py
|
|
17
|
+
bluetti_modbus_lib/fields/DeviceField.py
|
|
18
|
+
bluetti_modbus_lib/fields/UIntField.py
|
|
19
|
+
bluetti_modbus_lib/fields/__init__.py
|
|
20
|
+
bluetti_modbus_lib/modbus/__init__.py
|
|
21
|
+
bluetti_modbus_lib/modbus/client.py
|
|
22
|
+
bluetti_modbus_lib/scripts/__init__.py
|
|
23
|
+
bluetti_modbus_lib/scripts/bluetti_modread.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
bluetti_modbus_lib
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""Setup for pypi package"""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import codecs
|
|
5
|
+
from setuptools import setup, find_packages
|
|
6
|
+
|
|
7
|
+
here = os.path.abspath(os.path.dirname(__file__))
|
|
8
|
+
|
|
9
|
+
with codecs.open(os.path.join(here, "README.md"), encoding="utf-8") as fh:
|
|
10
|
+
long_description = "\n" + fh.read()
|
|
11
|
+
|
|
12
|
+
VERSION = os.getenv("LIB_VERSION")
|
|
13
|
+
DESCRIPTION = "Bluetti Modbus"
|
|
14
|
+
|
|
15
|
+
# Setting up
|
|
16
|
+
setup(
|
|
17
|
+
name="bluetti-modbus-lib",
|
|
18
|
+
version=VERSION,
|
|
19
|
+
author="Patrick762",
|
|
20
|
+
author_email="<pip-bluetti-modbus-lib@hosting-rt.de>",
|
|
21
|
+
description=DESCRIPTION,
|
|
22
|
+
long_description_content_type="text/markdown",
|
|
23
|
+
long_description=long_description,
|
|
24
|
+
url="https://github.com/Patrick762/bluetti-modbus-lib",
|
|
25
|
+
packages=find_packages(),
|
|
26
|
+
install_requires=[
|
|
27
|
+
"async_timeout",
|
|
28
|
+
"asyncio",
|
|
29
|
+
"pymodbus",
|
|
30
|
+
"logging",
|
|
31
|
+
],
|
|
32
|
+
keywords=[],
|
|
33
|
+
entry_points={
|
|
34
|
+
"console_scripts": [
|
|
35
|
+
"bluetti-modread = bluetti_modbus_lib.scripts.bluetti_modread:start",
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
classifiers=[
|
|
39
|
+
"Development Status :: 4 - Beta",
|
|
40
|
+
"Intended Audience :: Developers",
|
|
41
|
+
"Programming Language :: Python :: 3",
|
|
42
|
+
],
|
|
43
|
+
)
|