solax-py-library 1.0.0.2501__py3-none-any.whl → 1.0.0.2503__py3-none-any.whl
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.
- solax_py_library/device/constant/cabinet.py +2 -0
- solax_py_library/device/types/alarm.py +16 -0
- solax_py_library/smart_scene/constant/message_entry.py +174 -336
- solax_py_library/smart_scene/core/action/base.py +9 -0
- solax_py_library/smart_scene/core/action/ems_action.py +19 -0
- solax_py_library/smart_scene/core/action/system_action.py +241 -0
- solax_py_library/smart_scene/core/condition/base.py +4 -7
- solax_py_library/smart_scene/core/condition/cabinet_condition.py +13 -89
- solax_py_library/smart_scene/core/condition/date_condition.py +11 -8
- solax_py_library/smart_scene/core/condition/price_condition.py +29 -21
- solax_py_library/smart_scene/core/condition/system_condition.py +11 -14
- solax_py_library/smart_scene/core/condition/weather_condition.py +21 -22
- solax_py_library/smart_scene/types/action.py +3 -3
- solax_py_library/smart_scene/types/condition.py +32 -26
- solax_py_library/smart_scene/types/smart_scene_content.py +9 -9
- solax_py_library/test/__init__.py +0 -0
- solax_py_library/test/test_utils/__init__.py +0 -0
- solax_py_library/test/test_utils/test_cloud_client.py +14 -0
- solax_py_library/utils/cloud_client.py +11 -14
- solax_py_library/utils/time_util.py +33 -0
- {solax_py_library-1.0.0.2501.dist-info → solax_py_library-1.0.0.2503.dist-info}/METADATA +2 -1
- {solax_py_library-1.0.0.2501.dist-info → solax_py_library-1.0.0.2503.dist-info}/RECORD +23 -15
- {solax_py_library-1.0.0.2501.dist-info → solax_py_library-1.0.0.2503.dist-info}/WHEEL +0 -0
@@ -0,0 +1,241 @@
|
|
1
|
+
# from solax_py_library.smart_scene.core.action.base import BaseAction
|
2
|
+
# from solax_py_library.smart_scene.types.action import SystemActionType
|
3
|
+
# from solax_py_library.smart_scene.types.condition import SystemConditionItemData
|
4
|
+
#
|
5
|
+
#
|
6
|
+
# class SystemAction(BaseAction):
|
7
|
+
# def __init__(self, smart_scene_service, app_log):
|
8
|
+
# super().__init__(smart_scene_service)
|
9
|
+
# self.log = app_log
|
10
|
+
# self.do_func = self.do_system_action
|
11
|
+
# self.cabinet_type = None
|
12
|
+
#
|
13
|
+
# def do_system_action(self, scene_id, data: SystemConditionItemData):
|
14
|
+
# child_data = data.childData
|
15
|
+
# child_type = data.childType
|
16
|
+
# data = child_data.data
|
17
|
+
# if self.cabinet_type is None:
|
18
|
+
# self.cabinet_type = self.smart_scene_service.get_cabinet_type()
|
19
|
+
# if child_type == SystemActionType.systemSwitch:
|
20
|
+
# return self.system_switch(data[0], scene_id)
|
21
|
+
# elif child_type == SystemActionType.exportControl:
|
22
|
+
# return self.export_control(data, scene_id)
|
23
|
+
# elif child_type == SystemActionType.importControl:
|
24
|
+
# return self.import_control(data, scene_id)
|
25
|
+
# elif child_type == SystemActionType.workMode:
|
26
|
+
# return self.work_mode(data, scene_id)
|
27
|
+
# return False
|
28
|
+
#
|
29
|
+
#
|
30
|
+
# class SystemSwitchAction(SystemAction):
|
31
|
+
# def system_switch(self, value, scene_id) -> bool:
|
32
|
+
# """系统开关机"""
|
33
|
+
# if value not in [0, 1]:
|
34
|
+
# value = 1
|
35
|
+
# if self.cabinet_type in ["TRENE"]:
|
36
|
+
# self.ems_tcp_service.set_trene_switch(value)
|
37
|
+
# return True
|
38
|
+
# else:
|
39
|
+
# master_sn = self.device_service.get_master_inv_by_device()
|
40
|
+
# # 如果为AELIO,则只需要操控主机
|
41
|
+
# if master_sn:
|
42
|
+
# data = {"sn": master_sn, "switch": value}
|
43
|
+
# self.log.info(f"执行: 系统开关机, data: {data}")
|
44
|
+
# t = threading.Thread(
|
45
|
+
# target=self.smart_scene_service.request_local_server,
|
46
|
+
# args=("setSystemSwitch", data, scene_id),
|
47
|
+
# daemon=True,
|
48
|
+
# )
|
49
|
+
# t.start()
|
50
|
+
# return True
|
51
|
+
#
|
52
|
+
#
|
53
|
+
# class ExportControlAction(SystemAction):
|
54
|
+
# def export_control(self, value, scene_id) -> bool:
|
55
|
+
# """零输出控制"""
|
56
|
+
# if len(value) != 4:
|
57
|
+
# value.extend([1, 0, 1])
|
58
|
+
# data = {
|
59
|
+
# "isEnable": value[0],
|
60
|
+
# "controlMode": value[1],
|
61
|
+
# "exportValue": value[2],
|
62
|
+
# "unitType": value[3],
|
63
|
+
# }
|
64
|
+
# self.log.info(f"执行: 馈网控制, data: {data}")
|
65
|
+
# ret = self.smart_scene_service.request_local_server(
|
66
|
+
# "editOutputControl", data, scene_id
|
67
|
+
# )
|
68
|
+
# if not ret or ret["success"] is False:
|
69
|
+
# return False
|
70
|
+
# return True
|
71
|
+
#
|
72
|
+
#
|
73
|
+
# class ImportControlAction(SystemAction):
|
74
|
+
# def import_control(self, value, scene_id) -> bool:
|
75
|
+
# """需量控制"""
|
76
|
+
# if self.cabinet_type in ["TRENE"]:
|
77
|
+
# if len(value) != 3:
|
78
|
+
# value.extend([1, 0])
|
79
|
+
# data = {
|
80
|
+
# "isAllowDischarge": value[1],
|
81
|
+
# "demandLimitValue": value[2],
|
82
|
+
# "isEnable": value[0],
|
83
|
+
# }
|
84
|
+
# else:
|
85
|
+
# if len(value) != 2:
|
86
|
+
# value.append(0)
|
87
|
+
# data = {
|
88
|
+
# "isAllowDischarge": 1,
|
89
|
+
# "demandLimitValue": value[1],
|
90
|
+
# "isEnable": value[0],
|
91
|
+
# }
|
92
|
+
# self.log.info(f"执行: 需量控制, data: {data}")
|
93
|
+
# ret = self.smart_scene_service.request_local_server(
|
94
|
+
# "editDemandControl", data, scene_id
|
95
|
+
# )
|
96
|
+
# if not ret or ret["success"] is False:
|
97
|
+
# return False
|
98
|
+
# return True
|
99
|
+
#
|
100
|
+
#
|
101
|
+
# class WorkModeAction(SystemAction):
|
102
|
+
# def work_mode(self, value, scene_id) -> bool:
|
103
|
+
# # 0: self use; 1: 并网优先; 2: 备用模式; 3: 手动; 4: 削峰填谷 5: TOU(暂不用); 16: VPP
|
104
|
+
# if value[0] not in [0, 1, 2, 3, 4, 16]:
|
105
|
+
# return False
|
106
|
+
# data = None
|
107
|
+
# if self.cabinet_type in ["AELIO"]:
|
108
|
+
# if value[0] in [0, 1, 2, 3, 4]:
|
109
|
+
# data = {"useMode": value[0]}
|
110
|
+
# elif self.cabinet_type in ["TRENE"]:
|
111
|
+
# if value[0] in [0, 1, 3, 4]:
|
112
|
+
# data = {"useMode": value[0]}
|
113
|
+
# else:
|
114
|
+
# return False
|
115
|
+
# if data is not None: # 普通模式
|
116
|
+
# self.log.info(f"普通模式控制 data: {data}")
|
117
|
+
# # 手动模式
|
118
|
+
# if data["useMode"] == 3:
|
119
|
+
# if value[1] == 5:
|
120
|
+
# value.extend([0, 10])
|
121
|
+
# self.smart_scene_service.set_manual_mode(
|
122
|
+
# value[1], value[2], value[3], self.cabinet_type
|
123
|
+
# )
|
124
|
+
# else:
|
125
|
+
# self.smart_scene_service.request_local_server(
|
126
|
+
# "setAelioUseMode", data, scene_id
|
127
|
+
# )
|
128
|
+
# else: # VPP模式
|
129
|
+
# if self.cabinet_type in ["AELIO"]:
|
130
|
+
# if value[1] == 1:
|
131
|
+
# reg_value_list = [1]
|
132
|
+
# # 有功功率
|
133
|
+
# reg_value_list.extend(
|
134
|
+
# self.smart_scene_service.struct_transform(
|
135
|
+
# value[2] * 1000, "int32", "little"
|
136
|
+
# )
|
137
|
+
# )
|
138
|
+
# # 无功功率
|
139
|
+
# reg_value_list.extend(
|
140
|
+
# self.smart_scene_service.struct_transform(
|
141
|
+
# value[3] * 1000, "int32", "little"
|
142
|
+
# )
|
143
|
+
# )
|
144
|
+
# # 持续时间35秒, 控制超时 35s,控制类型为set
|
145
|
+
# reg_value_list.extend([35, 35, 1])
|
146
|
+
# elif value[1] == 2:
|
147
|
+
# reg_value_list = [2, 1]
|
148
|
+
# # 能量目标
|
149
|
+
# reg_value_list.extend(
|
150
|
+
# self.smart_scene_service.struct_transform(
|
151
|
+
# value[2] * 1000, "uint32", "little"
|
152
|
+
# )
|
153
|
+
# )
|
154
|
+
# # 功率目标
|
155
|
+
# reg_value_list.extend(
|
156
|
+
# self.smart_scene_service.struct_transform(
|
157
|
+
# value[3] * 1000, "int32", "little"
|
158
|
+
# )
|
159
|
+
# )
|
160
|
+
# # 控制超时 35s
|
161
|
+
# reg_value_list.extend([35])
|
162
|
+
# elif value[1] == 3:
|
163
|
+
# # 控制类型为set,SOC:value[2]
|
164
|
+
# reg_value_list = [3, 1, value[2]]
|
165
|
+
# # 充放电功率目标
|
166
|
+
# reg_value_list.extend(
|
167
|
+
# self.smart_scene_service.struct_transform(
|
168
|
+
# value[3] * 1000, "int32", "little"
|
169
|
+
# )
|
170
|
+
# )
|
171
|
+
# # 控制超时 35s
|
172
|
+
# reg_value_list.extend([35])
|
173
|
+
# elif value[1] == 4:
|
174
|
+
# reg_value_list = [4]
|
175
|
+
# # 电池功率目标
|
176
|
+
# reg_value_list.extend(
|
177
|
+
# self.smart_scene_service.struct_transform(
|
178
|
+
# value[2] * 1000, "int32", "little"
|
179
|
+
# )
|
180
|
+
# )
|
181
|
+
# # 控制超时 35s, # 远程控制超时后需设备执行的模式 0xA0 关闭VPP,0xA1 默认的VPP模式
|
182
|
+
# reg_value_list.extend([35, 0xA0])
|
183
|
+
# elif value[1] == 5:
|
184
|
+
# reg_value_list = [5]
|
185
|
+
# # 控制超时 35s, # 远程控制超时后需设备执行的模式 0xA0 关闭VPP,0xA1 默认的VPP模式
|
186
|
+
# reg_value_list.extend([35, 0xA0])
|
187
|
+
# elif value[1] == 6:
|
188
|
+
# reg_value_list = [6]
|
189
|
+
# # 控制超时 35s, # 远程控制超时后需设备执行的模式 0xA0 关闭VPP,0xA1 默认的VPP模式
|
190
|
+
# reg_value_list.extend([35, 0xA0])
|
191
|
+
# elif value[1] == 7:
|
192
|
+
# reg_value_list = [7]
|
193
|
+
# # 控制超时 35s, # 远程控制超时后需设备执行的模式 0xA0 关闭VPP,0xA1 默认的VPP模式
|
194
|
+
# reg_value_list.extend([35, 0xA0])
|
195
|
+
# elif value[1] == 8:
|
196
|
+
# # 控制类型为set,
|
197
|
+
# reg_value_list = [8, 1]
|
198
|
+
# # PV功率限制
|
199
|
+
# reg_value_list.extend(
|
200
|
+
# self.smart_scene_service.struct_transform(
|
201
|
+
# value[2] * 1000, "uint32", "little"
|
202
|
+
# )
|
203
|
+
# )
|
204
|
+
# # 电池功率限制
|
205
|
+
# reg_value_list.extend(
|
206
|
+
# self.smart_scene_service.struct_transform(
|
207
|
+
# value[3] * 1000, "int32", "little"
|
208
|
+
# )
|
209
|
+
# )
|
210
|
+
# # 控制超时 35s, # 远程控制超时后需设备执行的模式 0xA0 关闭VPP,0xA1 默认的VPP模式
|
211
|
+
# reg_value_list.extend([35, 0xA0])
|
212
|
+
# elif value[1] == 9:
|
213
|
+
# # 控制类型为set,
|
214
|
+
# reg_value_list = [9, 1]
|
215
|
+
# # PV功率限制
|
216
|
+
# reg_value_list.extend(
|
217
|
+
# self.smart_scene_service.struct_transform(
|
218
|
+
# value[2] * 1000, "uint32", "little"
|
219
|
+
# )
|
220
|
+
# )
|
221
|
+
# # 电池功率限制
|
222
|
+
# reg_value_list.extend(
|
223
|
+
# self.smart_scene_service.struct_transform(
|
224
|
+
# value[3] * 1000, "int32", "little"
|
225
|
+
# )
|
226
|
+
# )
|
227
|
+
# # 控制超时 35s, # 远程控制超时后需设备执行的模式 0xA0 关闭VPP,0xA1 默认的VPP模式
|
228
|
+
# reg_value_list.extend([value[4], 35, 0xA0])
|
229
|
+
# else:
|
230
|
+
# reg_value_list = []
|
231
|
+
# func_name = PCSOperateFunctionName.SET_AELIO_VPP_MODE
|
232
|
+
# channel = options.REDIS_WRITE_SERIAL_DEVICE
|
233
|
+
# future_data = {}
|
234
|
+
# future_data["func_name"] = func_name
|
235
|
+
# future_data["operationMode"] = Enumeration.SINGLE_DEVICE_MODE
|
236
|
+
# future_data["data"] = {"value_list": reg_value_list}
|
237
|
+
# app_log.info(f"VPP模式控制 data: {future_data}")
|
238
|
+
# self.smart_scene_service.request_local_redis(
|
239
|
+
# channel, json.dumps(future_data)
|
240
|
+
# )
|
241
|
+
# return True
|
@@ -1,12 +1,9 @@
|
|
1
1
|
class BaseCondition(object):
|
2
|
-
def __init__(self):
|
3
|
-
# 子条件类型
|
4
|
-
self.child_type_list = []
|
5
|
-
# 各子条件的值
|
2
|
+
def __init__(self, **kwargs):
|
6
3
|
self.value = {}
|
7
|
-
# 判断是否满足条件的子条件-判断函数的映射
|
8
|
-
self.meet_func_dict = {}
|
9
4
|
|
10
5
|
def update_value(self):
|
11
|
-
|
6
|
+
...
|
7
|
+
|
8
|
+
def meet_func(self, data, ctx):
|
12
9
|
...
|
@@ -1,8 +1,13 @@
|
|
1
|
+
from collections import defaultdict
|
2
|
+
|
3
|
+
from solax_py_library.smart_scene.core.condition.base import BaseCondition
|
4
|
+
from solax_py_library.smart_scene.types.condition import CabinetConditionItemData
|
5
|
+
from solax_py_library.device.types.alarm import AlarmLevel
|
6
|
+
|
1
7
|
|
2
8
|
class CabinetCondition(BaseCondition):
|
3
|
-
def __init__(self,
|
4
|
-
super().__init__(
|
5
|
-
self.type = IF_ELE_TYPE
|
9
|
+
def __init__(self, **kwargs):
|
10
|
+
super().__init__()
|
6
11
|
self.value = defaultdict(
|
7
12
|
lambda: {
|
8
13
|
"soc": None,
|
@@ -13,92 +18,11 @@ class CabinetCondition(BaseCondition):
|
|
13
18
|
},
|
14
19
|
}
|
15
20
|
)
|
16
|
-
self.
|
21
|
+
self.redis_service = kwargs.get("redis_service")
|
22
|
+
self.db_service = kwargs.get("db_service")
|
17
23
|
|
18
24
|
def update_value(self):
|
19
|
-
|
20
|
-
cabinet_sns = [c.SN for c in self.db_service.get_all_cabinet()]
|
21
|
-
self._update_cabinet_soc(cabinet_sns)
|
22
|
-
self._update_cabinet_alarm(cabinet_sns)
|
23
|
-
|
24
|
-
def _update_cabinet_alarm(self, cabinet_sns):
|
25
|
-
all_alarm_code = self.redis_service.get_all_device_alarm_code()
|
26
|
-
if not all_alarm_code:
|
27
|
-
return
|
28
|
-
|
29
|
-
cabinet_sn_pcs_sn_map = defaultdict(list)
|
30
|
-
for pcs in self.db_service.get_pcs_by_cabinet(cabinet_sns):
|
31
|
-
cabinet_sn_pcs_sn_map[pcs.cabinetSN].append(pcs.SN)
|
32
|
-
|
33
|
-
cabinet_sn_bms_sn_map = defaultdict(list)
|
34
|
-
for bms in self.db_service.get_bms_by_cabinet(cabinet_sns):
|
35
|
-
cabinet_sn_bms_sn_map[bms.cabinetSN].append(bms.SN)
|
36
|
-
|
37
|
-
cabinet_sn_io_sn_map = defaultdict(list)
|
38
|
-
for io in self.db_service.get_io_by_cabinet(cabinet_sns):
|
39
|
-
cabinet_sn_io_sn_map[io.cabinetSN].append(io.SN)
|
40
|
-
|
41
|
-
for sn in cabinet_sns:
|
42
|
-
cabinet_alarm = set(all_alarm_code.get(sn, []))
|
43
|
-
pcs_alarm = set()
|
44
|
-
for pcs_sn in cabinet_sn_pcs_sn_map.get(sn, []):
|
45
|
-
pcs_alarm.update(all_alarm_code.get(pcs_sn, []))
|
46
|
-
|
47
|
-
bms_alarm = set()
|
48
|
-
for bms_sn in cabinet_sn_bms_sn_map.get(sn, []):
|
49
|
-
bms_alarm.update(all_alarm_code.get(bms_sn, []))
|
50
|
-
|
51
|
-
io_alarm = set()
|
52
|
-
for io_sn in cabinet_sn_io_sn_map.get(sn, []):
|
53
|
-
io_alarm.update(all_alarm_code.get(io_sn, []))
|
54
|
-
|
55
|
-
self.value[sn]["alarm_level"][AlarmLevel.TIPS] = any(
|
56
|
-
[
|
57
|
-
bool(cabinet_alarm & set(AlarmPointInfo.CABINET_TIPS_ALARM_DATA)),
|
58
|
-
bool(pcs_alarm & set(AlarmPointInfo.PCS_TIPS_ALARM_DATA)),
|
59
|
-
bool(bms_alarm & set(AlarmPointInfo.BMS_TIPS_ALARM_DATA)),
|
60
|
-
bool(io_alarm & set(AlarmPointInfo.IO_TIPS_ALARM_DATA)),
|
61
|
-
]
|
62
|
-
)
|
63
|
-
self.value[sn]["alarm_level"][AlarmLevel.NORMAL] = any(
|
64
|
-
[
|
65
|
-
bool(cabinet_alarm & set(AlarmPointInfo.CABINET_NORMAL_ALARM_DATA)),
|
66
|
-
bool(pcs_alarm & set(AlarmPointInfo.PCS_NORMAL_ALARM_DATA)),
|
67
|
-
bool(bms_alarm & set(AlarmPointInfo.BMS_NORMAL_ALARM_DATA)),
|
68
|
-
bool(io_alarm & set(AlarmPointInfo.IO_NORMAL_ALARM_DATA)),
|
69
|
-
]
|
70
|
-
)
|
71
|
-
self.value[sn]["alarm_level"][AlarmLevel.EMERGENCY] = any(
|
72
|
-
[
|
73
|
-
bool(
|
74
|
-
cabinet_alarm & set(AlarmPointInfo.CABINET_EMERGENCY_ALARM_DATA)
|
75
|
-
),
|
76
|
-
bool(pcs_alarm & set(AlarmPointInfo.PCS_EMERGENCY_ALARM_DATA)),
|
77
|
-
bool(bms_alarm & set(AlarmPointInfo.BMS_EMERGENCY_ALARM_DATA)),
|
78
|
-
bool(io_alarm & set(AlarmPointInfo.IO_EMERGENCY_ALARM_DATA)),
|
79
|
-
]
|
80
|
-
)
|
81
|
-
|
82
|
-
def _update_cabinet_soc(self, cabinet_sns):
|
83
|
-
for sn in cabinet_sns or []:
|
84
|
-
result = self.smart_scene_service.redis_service.get_bms_current_data(sn)
|
85
|
-
self.value[sn]["soc"] = result[14] if result else 0
|
25
|
+
...
|
86
26
|
|
87
|
-
def
|
88
|
-
|
89
|
-
return False
|
90
|
-
cabinet = ctx["cabinet"] or []
|
91
|
-
for cabinet_sn in cabinet:
|
92
|
-
if data.childType == CabinetConditionType.cabinetSoc:
|
93
|
-
if self.value[cabinet_sn]["soc"] is None:
|
94
|
-
return False
|
95
|
-
if self.smart_scene_service.compare_the_magnitudes(
|
96
|
-
data.childData.function,
|
97
|
-
compare_value=self.value[cabinet_sn]["soc"],
|
98
|
-
base_value=data.childData.data[0],
|
99
|
-
):
|
100
|
-
return True
|
101
|
-
elif data.childType == CabinetConditionType.cabinetAlarm:
|
102
|
-
if self.value[cabinet_sn]["alarm_level"][data.childData.data[0]]:
|
103
|
-
return True
|
104
|
-
return False
|
27
|
+
def meet_func(self, data: CabinetConditionItemData, ctx):
|
28
|
+
...
|
@@ -1,13 +1,18 @@
|
|
1
1
|
from datetime import datetime
|
2
2
|
|
3
3
|
from solax_py_library.smart_scene.core.condition.base import BaseCondition
|
4
|
-
from solax_py_library.smart_scene.types.condition import
|
4
|
+
from solax_py_library.smart_scene.types.condition import (
|
5
|
+
DateConditionItemData,
|
6
|
+
DateConditionType,
|
7
|
+
)
|
5
8
|
|
6
9
|
|
7
10
|
class DateCondition(BaseCondition):
|
8
|
-
def __init__(self):
|
9
|
-
super().__init__()
|
10
|
-
|
11
|
+
def __init__(self, **kwargs):
|
12
|
+
super().__init__(**kwargs)
|
13
|
+
now = datetime.now()
|
14
|
+
self.hour = now.hour
|
15
|
+
self.minute = now.minute
|
11
16
|
|
12
17
|
def update_value(self):
|
13
18
|
"""获取time 类型需要的数据"""
|
@@ -17,10 +22,8 @@ class DateCondition(BaseCondition):
|
|
17
22
|
|
18
23
|
def meet_func(self, data: DateConditionItemData, ctx):
|
19
24
|
if data.childType == DateConditionType.time:
|
20
|
-
"""判断是否满足日期时间类条件"""
|
21
25
|
date = data.childData.data[0]
|
22
|
-
hour =
|
23
|
-
|
24
|
-
if hour == self.hour and minute == self.minute:
|
26
|
+
hour, minute = date.split(":")
|
27
|
+
if int(hour) == self.hour and int(minute) == self.minute:
|
25
28
|
return True
|
26
29
|
return False
|
@@ -1,34 +1,45 @@
|
|
1
1
|
from datetime import datetime
|
2
2
|
|
3
3
|
from solax_py_library.smart_scene.core.condition.base import BaseCondition
|
4
|
-
from solax_py_library.smart_scene.types.condition import
|
4
|
+
from solax_py_library.smart_scene.types.condition import (
|
5
|
+
PriceConditionItemData,
|
6
|
+
PriceConditionType,
|
7
|
+
SmartSceneUnit,
|
8
|
+
ConditionFunc,
|
9
|
+
)
|
10
|
+
from solax_py_library.utils.cloud_client import CloudClient
|
11
|
+
from solax_py_library.utils.time_util import (
|
12
|
+
trans_str_time_to_index,
|
13
|
+
get_highest_or_lowest_value,
|
14
|
+
)
|
5
15
|
|
6
16
|
|
7
17
|
class ElePriceCondition(BaseCondition):
|
8
|
-
def __init__(self):
|
9
|
-
super().__init__()
|
10
|
-
self.buy =
|
11
|
-
self.value = {}
|
18
|
+
def __init__(self, **kwargs):
|
19
|
+
super().__init__(**kwargs)
|
20
|
+
self.buy = None
|
12
21
|
self.unit = None
|
22
|
+
self.cloud_url = kwargs.pop("cloud_url")
|
23
|
+
self.sn = kwargs.pop("ems_sn")
|
24
|
+
self.secret = kwargs.pop("secret")
|
25
|
+
self.client = CloudClient(base_url=self.cloud_url)
|
13
26
|
|
14
27
|
def update_value(self):
|
15
28
|
"""获取电价 类型需要的数据"""
|
16
|
-
ele_info = self.
|
29
|
+
ele_info = self.client.get_electrovalence_data_from_cloud()
|
17
30
|
if self.buy:
|
18
31
|
self.value = ele_info.get("buy", [])
|
19
32
|
else:
|
20
33
|
self.value = ele_info.get("sell", [])
|
21
34
|
self.unit = ele_info.get("ele_unit", " ")
|
22
35
|
|
23
|
-
def meet_func_price(self, function_value, data_value, index) -> bool:
|
36
|
+
def meet_func_price(self, function_value: ConditionFunc, data_value, index) -> bool:
|
24
37
|
"""电价条件的判定"""
|
25
38
|
if index < 0 or index > len(self.value):
|
26
39
|
return False
|
27
40
|
if self.value[index] is None:
|
28
41
|
return False
|
29
|
-
return self.
|
30
|
-
function_value, self.value[index], data_value[0]
|
31
|
-
)
|
42
|
+
return function_value.function()(self.value[index], data_value[0])
|
32
43
|
|
33
44
|
def meet_func_highest_price(self, data_value, index) -> bool:
|
34
45
|
value, unit = data_value
|
@@ -56,16 +67,13 @@ class ElePriceCondition(BaseCondition):
|
|
56
67
|
else:
|
57
68
|
return False
|
58
69
|
|
59
|
-
def meet_func_highest_or_lowest_hours(self, data_value, index,
|
60
|
-
sort_index, start_index =
|
61
|
-
data_value[0], data_value[1], data_value[2], self.value,
|
70
|
+
def meet_func_highest_or_lowest_hours(self, data_value, index, reverse) -> bool:
|
71
|
+
sort_index, start_index = get_highest_or_lowest_value(
|
72
|
+
data_value[0], data_value[1], data_value[2], self.value, reverse=reverse
|
62
73
|
)
|
63
|
-
if
|
64
|
-
return False
|
65
|
-
if index - start_index in sort_index:
|
74
|
+
if sort_index and index - start_index in sort_index:
|
66
75
|
return True
|
67
|
-
|
68
|
-
return False
|
76
|
+
return False
|
69
77
|
|
70
78
|
def meet_func(self, data: PriceConditionItemData, ctx):
|
71
79
|
if not self.value:
|
@@ -75,7 +83,7 @@ class ElePriceCondition(BaseCondition):
|
|
75
83
|
child_type = data.childType
|
76
84
|
data_value = child_data.data
|
77
85
|
now_time = datetime.strftime(datetime.now(), "%H:%M")
|
78
|
-
index =
|
86
|
+
index = trans_str_time_to_index(now_time)
|
79
87
|
if child_type == PriceConditionType.price:
|
80
88
|
return self.meet_func_price(child_data.function, data_value, index)
|
81
89
|
elif child_type == PriceConditionType.lowerPrice:
|
@@ -84,11 +92,11 @@ class ElePriceCondition(BaseCondition):
|
|
84
92
|
return self.meet_func_lowest_price(data_value, index)
|
85
93
|
elif child_type == PriceConditionType.expensiveHours:
|
86
94
|
return self.meet_func_highest_or_lowest_hours(
|
87
|
-
data_value, index,
|
95
|
+
data_value, index, reverse=True
|
88
96
|
)
|
89
97
|
elif child_type == PriceConditionType.cheapestHours:
|
90
98
|
return self.meet_func_highest_or_lowest_hours(
|
91
|
-
data_value, index,
|
99
|
+
data_value, index, reverse=False
|
92
100
|
)
|
93
101
|
return False
|
94
102
|
|
@@ -1,16 +1,17 @@
|
|
1
|
+
from solax_py_library.smart_scene.core.condition.base import BaseCondition
|
2
|
+
from solax_py_library.smart_scene.types.condition import (
|
3
|
+
SystemConditionItemData,
|
4
|
+
SystemConditionType,
|
5
|
+
)
|
1
6
|
|
2
7
|
|
3
8
|
class SystemCondition(BaseCondition):
|
4
|
-
def __init__(self,
|
5
|
-
super().__init__(
|
6
|
-
self.
|
7
|
-
self.value = {}
|
8
|
-
self.meet_func = self.meet_system_condition
|
9
|
+
def __init__(self, **kwargs):
|
10
|
+
super().__init__(**kwargs)
|
11
|
+
self.redis_service = kwargs.pop("redis_service")
|
9
12
|
|
10
13
|
def update_value(self):
|
11
|
-
overview_statistic_data = (
|
12
|
-
self.smart_scene_service.redis_service.get_overview_statistic_data()
|
13
|
-
)
|
14
|
+
overview_statistic_data = self.redis_service.get_overview_statistic_data()
|
14
15
|
self.value["grid_active_power"] = overview_statistic_data[8]
|
15
16
|
self.value["system_soc"] = overview_statistic_data[16]
|
16
17
|
|
@@ -20,7 +21,6 @@ class SystemCondition(BaseCondition):
|
|
20
21
|
child_data = data.childData
|
21
22
|
function_value = child_data.function
|
22
23
|
compare_value = None
|
23
|
-
app_log.info(self.value)
|
24
24
|
if data.childType == SystemConditionType.systemExportPower:
|
25
25
|
compare_value = self.value["grid_active_power"]
|
26
26
|
if compare_value < 0:
|
@@ -33,9 +33,6 @@ class SystemCondition(BaseCondition):
|
|
33
33
|
compare_value = self.value["system_soc"]
|
34
34
|
if compare_value is None:
|
35
35
|
return False
|
36
|
-
return
|
37
|
-
|
38
|
-
compare_value=abs(compare_value),
|
39
|
-
base_value=child_data.data[0],
|
36
|
+
return function_value.function()(
|
37
|
+
compare_value=abs(compare_value), base_value=child_data.data[0]
|
40
38
|
)
|
41
|
-
|
@@ -1,18 +1,22 @@
|
|
1
|
+
from solax_py_library.smart_scene.core.condition.base import BaseCondition
|
2
|
+
from solax_py_library.smart_scene.types.condition import (
|
3
|
+
WeatherConditionItemData,
|
4
|
+
WeatherConditionType,
|
5
|
+
)
|
6
|
+
from solax_py_library.utils.cloud_client import CloudClient
|
7
|
+
from solax_py_library.utils.time_util import get_rounded_times
|
8
|
+
|
1
9
|
|
2
10
|
class WeatherCondition(BaseCondition):
|
3
|
-
def __init__(self,
|
4
|
-
super().__init__(
|
5
|
-
self.
|
6
|
-
self.
|
7
|
-
self.
|
8
|
-
self.
|
9
|
-
self.unit = ""
|
10
|
-
self.meet_func = self.meet_weather_condition
|
11
|
+
def __init__(self, **kwargs):
|
12
|
+
super().__init__(**kwargs)
|
13
|
+
self.cloud_url = kwargs.pop("cloud_url")
|
14
|
+
self.sn = kwargs.pop("ems_sn")
|
15
|
+
self.secret = kwargs.pop("secret")
|
16
|
+
self.client = CloudClient(base_url=self.cloud_url)
|
11
17
|
|
12
|
-
def update_value(
|
13
|
-
self
|
14
|
-
):
|
15
|
-
self.value = self.smart_scene_service.get_weather_data_from_redis()
|
18
|
+
def update_value(self):
|
19
|
+
self.value = self.client.get_weather_data_from_redis()
|
16
20
|
|
17
21
|
def meet_weather_condition(self, data: WeatherConditionItemData, ctx):
|
18
22
|
if not self.value:
|
@@ -21,21 +25,16 @@ class WeatherCondition(BaseCondition):
|
|
21
25
|
child_type = data.childType
|
22
26
|
function_value = child_data.function
|
23
27
|
data_value = child_data.data
|
24
|
-
nearest_time, right_time =
|
28
|
+
nearest_time, right_time = get_rounded_times()
|
25
29
|
if nearest_time not in self.value["timeList"]:
|
26
30
|
time_now = right_time
|
27
31
|
else:
|
28
32
|
time_now = nearest_time
|
29
33
|
index = self.value["timeList"].index(time_now)
|
30
|
-
app_log.info(
|
31
|
-
f"最近时间点为: {nearest_time}, 右侧时间点为: {right_time}, 数组索引为: {index}"
|
32
|
-
)
|
33
34
|
if child_type == WeatherConditionType.irradiance:
|
34
|
-
return
|
35
|
+
return function_value.function()(function_value, data_value, index)
|
35
36
|
elif child_type == WeatherConditionType.temperature:
|
36
|
-
|
37
|
-
return self.smart_scene_service.compare_the_magnitudes(
|
38
|
-
function_value,
|
37
|
+
return function_value.function()(
|
39
38
|
self.value[child_type]["valueList"][index],
|
40
39
|
data_value[0],
|
41
40
|
)
|
@@ -62,6 +61,6 @@ class WeatherCondition(BaseCondition):
|
|
62
61
|
if not meet_flag:
|
63
62
|
return False
|
64
63
|
# 2. 再判断当前太阳辐照度
|
65
|
-
return
|
66
|
-
|
64
|
+
return function_value.function()(
|
65
|
+
self.value["irradiance"]["valueList"][index], irradiance
|
67
66
|
)
|
@@ -3,8 +3,8 @@ from typing import List, Union
|
|
3
3
|
|
4
4
|
from pydantic import BaseModel
|
5
5
|
|
6
|
-
from
|
7
|
-
from
|
6
|
+
from solax_py_library.device.constant.cabinet import TRENE_CABINET_ENUM
|
7
|
+
from solax_py_library.smart_scene.constant.message_entry import MESSAGE_ENTRY
|
8
8
|
|
9
9
|
|
10
10
|
class ActionType(str, Enum):
|
@@ -59,7 +59,7 @@ class SystemActionItemData(BaseModel):
|
|
59
59
|
if self.childData.data[0] == 0:
|
60
60
|
return MESSAGE_ENTRY["importControlOff"][lang]
|
61
61
|
else:
|
62
|
-
if cabinet_type in
|
62
|
+
if cabinet_type in TRENE_CABINET_ENUM:
|
63
63
|
msg = (
|
64
64
|
"importControl_standby"
|
65
65
|
if self.childData.data[1] == 0
|