solax-py-library 1.0.0.23__tar.gz → 1.0.0.2501__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.
Files changed (68) hide show
  1. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/PKG-INFO +1 -1
  2. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/README.md +49 -49
  3. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/pyproject.toml +15 -15
  4. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/__init__.py +1 -1
  5. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/device/core/interver/__init__.py +36 -36
  6. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/device/core/interver/base.py +215 -215
  7. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/device/types/inverter_config.py +41 -41
  8. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/device/types/modbus_point.py +30 -30
  9. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/exception.py +10 -10
  10. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/constant/message_entry.py +338 -0
  11. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/core/action/__init__.py +0 -0
  12. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/core/condition/__init__.py +0 -0
  13. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/core/condition/base.py +12 -0
  14. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/core/condition/cabinet_condition.py +104 -0
  15. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/core/condition/date_condition.py +26 -0
  16. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/core/condition/price_condition.py +105 -0
  17. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/core/condition/system_condition.py +41 -0
  18. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/core/condition/weather_condition.py +67 -0
  19. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/exceptions/__init__.py +0 -0
  20. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/exceptions/price.py +5 -0
  21. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/exceptions/smart_scene.py +81 -0
  22. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/exceptions/weather.py +5 -0
  23. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/types/__init__.py +0 -0
  24. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/types/action.py +156 -0
  25. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/types/condition.py +293 -0
  26. solax_py_library-1.0.0.2501/solax_py_library/smart_scene/types/smart_scene_content.py +173 -0
  27. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/snap_shot/__init__.py +3 -3
  28. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/snap_shot/constant/__init__.py +5 -5
  29. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/snap_shot/constant/crc_table.py +258 -258
  30. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/snap_shot/core/base_modbus.py +14 -14
  31. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/snap_shot/core/parser.py +261 -225
  32. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/snap_shot/core/snap_shot.py +25 -7
  33. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/snap_shot/exceptions/__init__.py +3 -3
  34. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/snap_shot/exceptions/snap_shot.py +9 -9
  35. solax_py_library-1.0.0.2501/solax_py_library/snap_shot/test/__init__.py +0 -0
  36. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/snap_shot/types/__init__.py +15 -15
  37. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/snap_shot/types/address.py +39 -39
  38. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/upload/__init__.py +3 -3
  39. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/upload/api/service.py +24 -24
  40. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/upload/core/upload_service/ftp.py +1 -0
  41. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/upload/exceptions/__init__.py +8 -8
  42. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/upload/exceptions/upload_error.py +21 -21
  43. solax_py_library-1.0.0.2501/solax_py_library/upload/test/__init__.py +0 -0
  44. solax_py_library-1.0.0.2501/solax_py_library/utils/__init__.py +0 -0
  45. solax_py_library-1.0.0.2501/solax_py_library/utils/cloud_client.py +213 -0
  46. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/utils/struct_util.py +30 -30
  47. solax_py_library-1.0.0.2501/solax_py_library/utils/time_util.py +5 -0
  48. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/device/__init__.py +0 -0
  49. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/device/constant/__init__.py +0 -0
  50. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/device/constant/inverter_model_info.py +0 -0
  51. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/device/core/__init__.py +0 -0
  52. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/device/types/__init__.py +0 -0
  53. {solax_py_library-1.0.0.23/solax_py_library/snap_shot/test → solax_py_library-1.0.0.2501/solax_py_library/smart_scene}/__init__.py +0 -0
  54. {solax_py_library-1.0.0.23/solax_py_library/upload/test → solax_py_library-1.0.0.2501/solax_py_library/smart_scene/constant}/__init__.py +0 -0
  55. {solax_py_library-1.0.0.23/solax_py_library/utils → solax_py_library-1.0.0.2501/solax_py_library/smart_scene/core}/__init__.py +0 -0
  56. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/snap_shot/core/__init__.py +0 -0
  57. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/upload/api/__init__.py +0 -0
  58. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/upload/core/__init__.py +0 -0
  59. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/upload/core/data_adapter/__init__.py +0 -0
  60. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/upload/core/data_adapter/base.py +0 -0
  61. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/upload/core/data_adapter/csv.py +0 -0
  62. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/upload/core/upload_service/__init__.py +0 -0
  63. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/upload/core/upload_service/base.py +0 -0
  64. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/upload/test/test_ftp.py +0 -0
  65. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/upload/types/__init__.py +0 -0
  66. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/upload/types/client.py +0 -0
  67. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/upload/types/ftp.py +0 -0
  68. {solax_py_library-1.0.0.23 → solax_py_library-1.0.0.2501}/solax_py_library/utils/common.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: solax-py-library
3
- Version: 1.0.0.23
3
+ Version: 1.0.0.2501
4
4
  Summary: some common tool
5
5
  Author: shenlvyu
6
6
  Author-email: 13296718439@163.com
@@ -1,49 +1,49 @@
1
- ### solax common module
2
-
3
- #### install
4
-
5
- ```shell
6
- pip install solax_py_library
7
- ```
8
-
9
- #### struction
10
-
11
- module:
12
- - api: provide the api
13
- - core: core code
14
- - errors: define errors
15
- - test: unit tests
16
- - types: modle define
17
-
18
- #### module
19
-
20
- This package provide some general modules to help us can focus on the real project coding.It`s our own package,we can add more and more general modules.
21
-
22
- - upload: The module define the upload tool.It support the way by Ftp.
23
-
24
-
25
- #### quick start
26
-
27
- ```python
28
- await upload(
29
- upload_type=UploadType.FTP,
30
- configuration=ftp_config,
31
- upload_data=UploadData(
32
- upload_type=UploadType.FTP,
33
- data=dict(
34
- file_type=FTPFileType.CSV,
35
- file_name="new_file.csv",
36
- data=[
37
- {
38
- "EMS1000序列号": "XMG11A011L",
39
- "EMS1000本地时间": "2025-02-11 15:39:10",
40
- "EMS1000版本号": "V007.11.1",
41
- "电站所在国家和地区": None,
42
- "电站所在当前时区": None,
43
- "电站系统类型": None,
44
- }
45
- ],
46
- ),
47
- ),
48
- )
49
- ```
1
+ ### solax common module
2
+
3
+ #### install
4
+
5
+ ```shell
6
+ pip install solax_py_library
7
+ ```
8
+
9
+ #### struction
10
+
11
+ module:
12
+ - api: provide the api
13
+ - core: core code
14
+ - errors: define errors
15
+ - test: unit tests
16
+ - types: modle define
17
+
18
+ #### module
19
+
20
+ This package provide some general modules to help us can focus on the real project coding.It`s our own package,we can add more and more general modules.
21
+
22
+ - upload: The module define the upload tool.It support the way by Ftp.
23
+
24
+
25
+ #### quick start
26
+
27
+ ```python
28
+ await upload(
29
+ upload_type=UploadType.FTP,
30
+ configuration=ftp_config,
31
+ upload_data=UploadData(
32
+ upload_type=UploadType.FTP,
33
+ data=dict(
34
+ file_type=FTPFileType.CSV,
35
+ file_name="new_file.csv",
36
+ data=[
37
+ {
38
+ "EMS1000序列号": "XMG11A011L",
39
+ "EMS1000本地时间": "2025-02-11 15:39:10",
40
+ "EMS1000版本号": "V007.11.1",
41
+ "电站所在国家和地区": None,
42
+ "电站所在当前时区": None,
43
+ "电站系统类型": None,
44
+ }
45
+ ],
46
+ ),
47
+ ),
48
+ )
49
+ ```
@@ -1,15 +1,15 @@
1
- [tool.poetry]
2
- name = "solax-py-library"
3
- version = "1.0.0.23"
4
- description = "some common tool"
5
- authors = ["shenlvyu <13296718439@163.com>", "x5m8944pjl <371630856@qq.com>"]
6
- readme = "README.md"
7
-
8
- [tool.poetry.dependencies]
9
- python = "^3.8"
10
- pydantic = "^1.10.0"
11
- typing-extensions = "==4.7.1"
12
-
13
- [build-system]
14
- requires = ["poetry-core"]
15
- build-backend = "poetry.core.masonry.api"
1
+ [tool.poetry]
2
+ name = "solax-py-library"
3
+ version = "1.0.0.2501"
4
+ description = "some common tool"
5
+ authors = ["shenlvyu <13296718439@163.com>", "x5m8944pjl <371630856@qq.com>"]
6
+ readme = "README.md"
7
+
8
+ [tool.poetry.dependencies]
9
+ python = "^3.8"
10
+ pydantic = "^1.10.0"
11
+ typing-extensions = "==4.7.1"
12
+
13
+ [build-system]
14
+ requires = ["poetry-core"]
15
+ build-backend = "poetry.core.masonry.api"
@@ -1 +1 @@
1
- __all__ = ["upload", "snap_shot"]
1
+ __all__ = ["upload", "snap_shot"]
@@ -1,36 +1,36 @@
1
- from .base import InverterProtocol
2
-
3
-
4
- inverter_protocol_map = {}
5
-
6
-
7
- def register_protocol(protocol_class: InverterProtocol):
8
- if protocol_class.inverter_model is None:
9
- raise RuntimeError("未找到对应的设备类型")
10
- inverter_protocol_map[protocol_class.inverter_model] = protocol_class
11
-
12
-
13
- def ProtocolFactory(inverter_model: int, *args, **kwargs) -> InverterProtocol:
14
- """
15
- 创建协议实例。
16
- inverter_model: 逆变器类型
17
- device_info: 设备信息。
18
- data: 数据。
19
- """
20
- protocol_class = inverter_protocol_map.get(inverter_model)
21
- if not protocol_class:
22
- raise ValueError(f"未找到名为 '{str(inverter_model)}' 的协议")
23
- return protocol_class(*args, **kwargs)
24
-
25
-
26
- def match_pcs(operate_queue, slave_num):
27
- for device_model in inverter_protocol_map.keys():
28
- client = ProtocolFactory(device_model)
29
- sn_data = client.read_sn(operate_queue.modbus_rtu, slave_num)
30
- if not sn_data:
31
- continue
32
- sn = get_char(sn_data)
33
- inverter_model, _ = client.parse_sn(sn)
34
- if inverter_model:
35
- return inverter_model, sn
36
- return None, None
1
+ from .base import InverterProtocol
2
+
3
+
4
+ inverter_protocol_map = {}
5
+
6
+
7
+ def register_protocol(protocol_class: InverterProtocol):
8
+ if protocol_class.inverter_model is None:
9
+ raise RuntimeError("未找到对应的设备类型")
10
+ inverter_protocol_map[protocol_class.inverter_model] = protocol_class
11
+
12
+
13
+ def ProtocolFactory(inverter_model: int, *args, **kwargs) -> InverterProtocol:
14
+ """
15
+ 创建协议实例。
16
+ inverter_model: 逆变器类型
17
+ device_info: 设备信息。
18
+ data: 数据。
19
+ """
20
+ protocol_class = inverter_protocol_map.get(inverter_model)
21
+ if not protocol_class:
22
+ raise ValueError(f"未找到名为 '{str(inverter_model)}' 的协议")
23
+ return protocol_class(*args, **kwargs)
24
+
25
+
26
+ def match_pcs(operate_queue, slave_num):
27
+ for device_model in inverter_protocol_map.keys():
28
+ client = ProtocolFactory(device_model)
29
+ sn_data = client.read_sn(operate_queue.modbus_rtu, slave_num)
30
+ if not sn_data:
31
+ continue
32
+ sn = get_char(sn_data)
33
+ inverter_model, _ = client.parse_sn(sn)
34
+ if inverter_model:
35
+ return inverter_model, sn
36
+ return None, None
@@ -1,215 +1,215 @@
1
- import json
2
- from abc import ABCMeta, abstractmethod
3
- from collections import OrderedDict
4
- from datetime import datetime
5
- from typing import List, Union
6
-
7
- from pydantic.class_validators import Validator
8
-
9
- from solax_py_library.device.types.inverter_config import InverterConfig, InverterPoint
10
- from solax_py_library.device.types.modbus_point import WriteModbusPoint, ReadModbusPoint
11
- from solax_py_library.utils.common import round_value
12
- from solax_py_library.utils.struct_util import unpack
13
-
14
-
15
- class InverterProtocol(metaclass=ABCMeta):
16
- inverter_model: None
17
-
18
- def __init__(self, point_config):
19
- self.col_name_index_map = OrderedDict()
20
- self.col_index_name_map = OrderedDict()
21
- self.col_id_index_map = {}
22
- self.sn_config = None
23
- self.shutdown_config = None
24
- self.boot_up_config = None
25
- self.time_config = None
26
- self.version_config = None
27
- self.error_map = None
28
- self._prepare(point_config)
29
-
30
- def _prepare(self, point_config: str):
31
- point_config = json.loads(point_config)
32
- self.real_data_start_address = None
33
- self.real_data_end_address = None
34
- try:
35
- point_config = InverterConfig(**point_config)
36
- except Validator as e:
37
- print(e)
38
- for index, real_point in enumerate(point_config.real_data):
39
- point_key = real_point.point_key
40
- point_id = real_point.point_id
41
- self.col_name_index_map[point_key] = real_point
42
- self.col_index_name_map[point_id] = real_point
43
- self.col_id_index_map[point_id] = index
44
- self.real_data_start_address = min(
45
- self.real_data_start_address, real_point.starting_address
46
- )
47
- self.real_data_end_address = max(
48
- self.real_data_end_address,
49
- real_point.starting_address + real_point.quantity_of_x - 1,
50
- )
51
-
52
- self.sn_config = point_config.other_data.sn
53
- self.shutdown_config = point_config.other_data.shutdown
54
- self.boot_up_config = point_config.other_data.boot_up
55
- self.time_config = point_config.other_data.time
56
- self.version_config = point_config.other_data.version
57
-
58
- self.error_map = point_config.error_map
59
-
60
- def read_real_data(self, modbus_client, slave):
61
- real_data = self._execute_modbus(
62
- modbus_client,
63
- slave,
64
- ReadModbusPoint(
65
- starting_address=self.real_data_start_address,
66
- quantity_of_x=self.real_data_end_address
67
- - self.real_data_start_address
68
- + 1,
69
- function_code=InverterPoint.function_code,
70
- ),
71
- )
72
- ret_real_data = {}
73
- for point_id, point_info in self.col_index_name_map.items():
74
- offset = point_info.starting_address
75
- data = real_data[offset : offset + point_info.quantity_of_x]
76
- ret_real_data[point_id] = self._parse_point_data(point_info, data)
77
- return ret_real_data
78
-
79
- def read_real_data_to_list(self, modbus_client, slave):
80
- real_data = self.read_real_data(modbus_client, slave)
81
- return list(real_data.values())
82
-
83
- def _parse_point_data(self, point_info: InverterPoint, point_data):
84
- value = unpack(
85
- point_data, data_format=point_info.register_dataformat, reversed=True
86
- )
87
- accuracy = point_info.accuracy
88
- return round_value(value * accuracy, 3)
89
-
90
- def get_data_by_point_id_from_list(self, point_id, real_data):
91
- point_index = self.col_id_index_map[point_id]
92
- return real_data[point_index]
93
-
94
- @abstractmethod
95
- def get_real_power(self, read_data):
96
- raise NotImplementedError()
97
-
98
- @abstractmethod
99
- def get_error_data(self, read_data):
100
- raise NotImplementedError()
101
-
102
- @abstractmethod
103
- def parse_pcs_status(self, read_data):
104
- ...
105
-
106
- @abstractmethod
107
- def parse_error_code(self, error_data):
108
- ...
109
-
110
- def error_to_alarm_code(self, error_codes: List[int]):
111
- if not self.error_map:
112
- return error_codes
113
- alarm_codes = []
114
- for error_code in error_codes:
115
- if alarm_code := self.error_map.get(error_code):
116
- alarm_codes.append(alarm_code)
117
- return alarm_codes
118
-
119
- def pv_power_data(self, real_data):
120
- ...
121
-
122
- def get_pv_capacity(self, real_data, history_data):
123
- ...
124
-
125
- def get_active_power(self, read_data):
126
- ...
127
-
128
- def get_reactive_power(self, read_data):
129
- ...
130
-
131
- # ============================== read or write =========================================
132
-
133
- def _execute_modbus(
134
- self,
135
- modbus_client,
136
- slave_num,
137
- point_info: Union[WriteModbusPoint, ReadModbusPoint],
138
- output_value=None,
139
- ):
140
- try:
141
- ret = modbus_client.read_and_write(
142
- slave_num,
143
- **point_info.dict(
144
- include={"starting_address", "quantity_of_x", "function_code"}
145
- ),
146
- output_value=output_value,
147
- )
148
- except Exception as e:
149
- print(e)
150
- return ret
151
-
152
- def shutdown(self, modbus_client, slave_num):
153
- self._execute_modbus(
154
- modbus_client,
155
- slave_num,
156
- self.shutdown_config,
157
- output_value=self.shutdown_config.output_value,
158
- )
159
-
160
- def boot_up(self, modbus_client, slave_num):
161
- self._execute_modbus(
162
- modbus_client,
163
- slave_num,
164
- self.boot_up_config,
165
- output_value=self.boot_up_config.output_value,
166
- )
167
-
168
- def read_sn(self, modbus_client, slave_num):
169
- return self._execute_modbus(modbus_client, slave_num, self.sn_config)
170
-
171
- def read_soft_version_and_hard_version(self, modbus_client, slave_num):
172
- soft_inv_version = self.read_soft_version(modbus_client, slave_num)
173
- hard_inv_version = self.read_hard_version(modbus_client, slave_num)
174
- return soft_inv_version, hard_inv_version
175
-
176
- def read_soft_version(self, modbus_client, slave_num):
177
- return self._execute_modbus(
178
- modbus_client, slave_num, self.version_config.software
179
- )
180
-
181
- def read_hard_version(self, modbus_client, slave_num):
182
- return self._execute_modbus(
183
- modbus_client, slave_num, self.version_config.hardware
184
- )
185
-
186
- def get_upgrade_value(self, crc, file_size):
187
- crc_nums = [crc[1], crc[0]]
188
- file_size = [file_size[1], file_size[0]]
189
- value = (
190
- [self.inverter_model]
191
- + crc_nums
192
- + [1, 0, 0, 0, 0, 0, 0]
193
- + file_size
194
- + [1, 0, 0]
195
- )
196
- return value
197
-
198
- def write_pcs_time(self, modbus_client, slave_num):
199
- self._execute_modbus(
200
- modbus_client,
201
- slave_num,
202
- self.time_config,
203
- output_value=self._build_pcs_time_value(),
204
- )
205
-
206
- def _build_pcs_time_value(self):
207
- cur_time = datetime.now()
208
- return [
209
- cur_time.year,
210
- cur_time.month,
211
- cur_time.day,
212
- cur_time.hour,
213
- cur_time.minute,
214
- cur_time.second,
215
- ]
1
+ import json
2
+ from abc import ABCMeta, abstractmethod
3
+ from collections import OrderedDict
4
+ from datetime import datetime
5
+ from typing import List, Union
6
+
7
+ from pydantic.class_validators import Validator
8
+
9
+ from solax_py_library.device.types.inverter_config import InverterConfig, InverterPoint
10
+ from solax_py_library.device.types.modbus_point import WriteModbusPoint, ReadModbusPoint
11
+ from solax_py_library.utils.common import round_value
12
+ from solax_py_library.utils.struct_util import unpack
13
+
14
+
15
+ class InverterProtocol(metaclass=ABCMeta):
16
+ inverter_model: None
17
+
18
+ def __init__(self, point_config):
19
+ self.col_name_index_map = OrderedDict()
20
+ self.col_index_name_map = OrderedDict()
21
+ self.col_id_index_map = {}
22
+ self.sn_config = None
23
+ self.shutdown_config = None
24
+ self.boot_up_config = None
25
+ self.time_config = None
26
+ self.version_config = None
27
+ self.error_map = None
28
+ self._prepare(point_config)
29
+
30
+ def _prepare(self, point_config: str):
31
+ point_config = json.loads(point_config)
32
+ self.real_data_start_address = None
33
+ self.real_data_end_address = None
34
+ try:
35
+ point_config = InverterConfig(**point_config)
36
+ except Validator as e:
37
+ print(e)
38
+ for index, real_point in enumerate(point_config.real_data):
39
+ point_key = real_point.point_key
40
+ point_id = real_point.point_id
41
+ self.col_name_index_map[point_key] = real_point
42
+ self.col_index_name_map[point_id] = real_point
43
+ self.col_id_index_map[point_id] = index
44
+ self.real_data_start_address = min(
45
+ self.real_data_start_address, real_point.starting_address
46
+ )
47
+ self.real_data_end_address = max(
48
+ self.real_data_end_address,
49
+ real_point.starting_address + real_point.quantity_of_x - 1,
50
+ )
51
+
52
+ self.sn_config = point_config.other_data.sn
53
+ self.shutdown_config = point_config.other_data.shutdown
54
+ self.boot_up_config = point_config.other_data.boot_up
55
+ self.time_config = point_config.other_data.time
56
+ self.version_config = point_config.other_data.version
57
+
58
+ self.error_map = point_config.error_map
59
+
60
+ def read_real_data(self, modbus_client, slave):
61
+ real_data = self._execute_modbus(
62
+ modbus_client,
63
+ slave,
64
+ ReadModbusPoint(
65
+ starting_address=self.real_data_start_address,
66
+ quantity_of_x=self.real_data_end_address
67
+ - self.real_data_start_address
68
+ + 1,
69
+ function_code=InverterPoint.function_code,
70
+ ),
71
+ )
72
+ ret_real_data = {}
73
+ for point_id, point_info in self.col_index_name_map.items():
74
+ offset = point_info.starting_address
75
+ data = real_data[offset : offset + point_info.quantity_of_x]
76
+ ret_real_data[point_id] = self._parse_point_data(point_info, data)
77
+ return ret_real_data
78
+
79
+ def read_real_data_to_list(self, modbus_client, slave):
80
+ real_data = self.read_real_data(modbus_client, slave)
81
+ return list(real_data.values())
82
+
83
+ def _parse_point_data(self, point_info: InverterPoint, point_data):
84
+ value = unpack(
85
+ point_data, data_format=point_info.register_dataformat, reversed=True
86
+ )
87
+ accuracy = point_info.accuracy
88
+ return round_value(value * accuracy, 3)
89
+
90
+ def get_data_by_point_id_from_list(self, point_id, real_data):
91
+ point_index = self.col_id_index_map[point_id]
92
+ return real_data[point_index]
93
+
94
+ @abstractmethod
95
+ def get_real_power(self, read_data):
96
+ raise NotImplementedError()
97
+
98
+ @abstractmethod
99
+ def get_error_data(self, read_data):
100
+ raise NotImplementedError()
101
+
102
+ @abstractmethod
103
+ def parse_pcs_status(self, read_data):
104
+ ...
105
+
106
+ @abstractmethod
107
+ def parse_error_code(self, error_data):
108
+ ...
109
+
110
+ def error_to_alarm_code(self, error_codes: List[int]):
111
+ if not self.error_map:
112
+ return error_codes
113
+ alarm_codes = []
114
+ for error_code in error_codes:
115
+ if alarm_code := self.error_map.get(error_code):
116
+ alarm_codes.append(alarm_code)
117
+ return alarm_codes
118
+
119
+ def pv_power_data(self, real_data):
120
+ ...
121
+
122
+ def get_pv_capacity(self, real_data, history_data):
123
+ ...
124
+
125
+ def get_active_power(self, read_data):
126
+ ...
127
+
128
+ def get_reactive_power(self, read_data):
129
+ ...
130
+
131
+ # ============================== read or write =========================================
132
+
133
+ def _execute_modbus(
134
+ self,
135
+ modbus_client,
136
+ slave_num,
137
+ point_info: Union[WriteModbusPoint, ReadModbusPoint],
138
+ output_value=None,
139
+ ):
140
+ try:
141
+ ret = modbus_client.read_and_write(
142
+ slave_num,
143
+ **point_info.dict(
144
+ include={"starting_address", "quantity_of_x", "function_code"}
145
+ ),
146
+ output_value=output_value,
147
+ )
148
+ except Exception as e:
149
+ print(e)
150
+ return ret
151
+
152
+ def shutdown(self, modbus_client, slave_num):
153
+ self._execute_modbus(
154
+ modbus_client,
155
+ slave_num,
156
+ self.shutdown_config,
157
+ output_value=self.shutdown_config.output_value,
158
+ )
159
+
160
+ def boot_up(self, modbus_client, slave_num):
161
+ self._execute_modbus(
162
+ modbus_client,
163
+ slave_num,
164
+ self.boot_up_config,
165
+ output_value=self.boot_up_config.output_value,
166
+ )
167
+
168
+ def read_sn(self, modbus_client, slave_num):
169
+ return self._execute_modbus(modbus_client, slave_num, self.sn_config)
170
+
171
+ def read_soft_version_and_hard_version(self, modbus_client, slave_num):
172
+ soft_inv_version = self.read_soft_version(modbus_client, slave_num)
173
+ hard_inv_version = self.read_hard_version(modbus_client, slave_num)
174
+ return soft_inv_version, hard_inv_version
175
+
176
+ def read_soft_version(self, modbus_client, slave_num):
177
+ return self._execute_modbus(
178
+ modbus_client, slave_num, self.version_config.software
179
+ )
180
+
181
+ def read_hard_version(self, modbus_client, slave_num):
182
+ return self._execute_modbus(
183
+ modbus_client, slave_num, self.version_config.hardware
184
+ )
185
+
186
+ def get_upgrade_value(self, crc, file_size):
187
+ crc_nums = [crc[1], crc[0]]
188
+ file_size = [file_size[1], file_size[0]]
189
+ value = (
190
+ [self.inverter_model]
191
+ + crc_nums
192
+ + [1, 0, 0, 0, 0, 0, 0]
193
+ + file_size
194
+ + [1, 0, 0]
195
+ )
196
+ return value
197
+
198
+ def write_pcs_time(self, modbus_client, slave_num):
199
+ self._execute_modbus(
200
+ modbus_client,
201
+ slave_num,
202
+ self.time_config,
203
+ output_value=self._build_pcs_time_value(),
204
+ )
205
+
206
+ def _build_pcs_time_value(self):
207
+ cur_time = datetime.now()
208
+ return [
209
+ cur_time.year,
210
+ cur_time.month,
211
+ cur_time.day,
212
+ cur_time.hour,
213
+ cur_time.minute,
214
+ cur_time.second,
215
+ ]