solax-py-library 1.0.0.24__py3-none-any.whl → 1.0.0.2502__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.
Files changed (62) hide show
  1. solax_py_library/__init__.py +1 -1
  2. solax_py_library/device/constant/inverter_model_info.py +312 -312
  3. solax_py_library/device/core/interver/__init__.py +36 -36
  4. solax_py_library/device/core/interver/base.py +215 -215
  5. solax_py_library/device/types/inverter_config.py +41 -41
  6. solax_py_library/device/types/modbus_point.py +30 -30
  7. solax_py_library/exception.py +10 -10
  8. solax_py_library/smart_scene/__init__.py +0 -0
  9. solax_py_library/smart_scene/constant/__init__.py +0 -0
  10. solax_py_library/smart_scene/constant/message_entry.py +338 -0
  11. solax_py_library/smart_scene/core/__init__.py +0 -0
  12. solax_py_library/smart_scene/core/action/__init__.py +0 -0
  13. solax_py_library/smart_scene/core/condition/__init__.py +0 -0
  14. solax_py_library/smart_scene/core/condition/base.py +12 -0
  15. solax_py_library/smart_scene/core/condition/cabinet_condition.py +104 -0
  16. solax_py_library/smart_scene/core/condition/date_condition.py +26 -0
  17. solax_py_library/smart_scene/core/condition/price_condition.py +105 -0
  18. solax_py_library/smart_scene/core/condition/system_condition.py +41 -0
  19. solax_py_library/smart_scene/core/condition/weather_condition.py +67 -0
  20. solax_py_library/smart_scene/exceptions/__init__.py +0 -0
  21. solax_py_library/smart_scene/exceptions/price.py +5 -0
  22. solax_py_library/smart_scene/exceptions/smart_scene.py +81 -0
  23. solax_py_library/smart_scene/exceptions/weather.py +5 -0
  24. solax_py_library/smart_scene/types/__init__.py +0 -0
  25. solax_py_library/smart_scene/types/action.py +156 -0
  26. solax_py_library/smart_scene/types/condition.py +293 -0
  27. solax_py_library/smart_scene/types/smart_scene_content.py +173 -0
  28. solax_py_library/snap_shot/__init__.py +3 -3
  29. solax_py_library/snap_shot/constant/__init__.py +5 -5
  30. solax_py_library/snap_shot/constant/crc_table.py +258 -258
  31. solax_py_library/snap_shot/core/__init__.py +9 -9
  32. solax_py_library/snap_shot/core/base_modbus.py +14 -14
  33. solax_py_library/snap_shot/exceptions/__init__.py +3 -3
  34. solax_py_library/snap_shot/exceptions/snap_shot.py +9 -9
  35. solax_py_library/snap_shot/types/__init__.py +15 -15
  36. solax_py_library/snap_shot/types/address.py +39 -39
  37. solax_py_library/test/__init__.py +0 -0
  38. solax_py_library/test/test_utils/__init__.py +0 -0
  39. solax_py_library/test/test_utils/test_cloud_client.py +14 -0
  40. solax_py_library/upload/__init__.py +3 -3
  41. solax_py_library/upload/api/__init__.py +3 -3
  42. solax_py_library/upload/api/service.py +24 -24
  43. solax_py_library/upload/core/__init__.py +3 -3
  44. solax_py_library/upload/core/data_adapter/__init__.py +5 -5
  45. solax_py_library/upload/core/data_adapter/base.py +9 -9
  46. solax_py_library/upload/core/data_adapter/csv.py +26 -26
  47. solax_py_library/upload/core/upload_service/__init__.py +15 -15
  48. solax_py_library/upload/core/upload_service/base.py +43 -43
  49. solax_py_library/upload/exceptions/__init__.py +8 -8
  50. solax_py_library/upload/exceptions/upload_error.py +21 -21
  51. solax_py_library/upload/test/test_ftp.py +113 -113
  52. solax_py_library/upload/types/__init__.py +11 -11
  53. solax_py_library/upload/types/client.py +19 -19
  54. solax_py_library/upload/types/ftp.py +37 -37
  55. solax_py_library/utils/cloud_client.py +210 -0
  56. solax_py_library/utils/common.py +38 -38
  57. solax_py_library/utils/struct_util.py +30 -30
  58. solax_py_library/utils/time_util.py +5 -0
  59. {solax_py_library-1.0.0.24.dist-info → solax_py_library-1.0.0.2502.dist-info}/METADATA +2 -1
  60. solax_py_library-1.0.0.2502.dist-info/RECORD +71 -0
  61. solax_py_library-1.0.0.24.dist-info/RECORD +0 -46
  62. {solax_py_library-1.0.0.24.dist-info → solax_py_library-1.0.0.2502.dist-info}/WHEEL +0 -0
@@ -0,0 +1,338 @@
1
+ MESSAGE_ENTRY = {
2
+ "rec_name_01": {
3
+ "zh_CN":"负买电电价收益优化",
4
+ "en_US":"Optimization of the revenue from negative import electricity prices."
5
+ },
6
+ "rec_name_02": {
7
+ "zh_CN":"负卖电电价收益优化",
8
+ "en_US":"Optimization of the revenue from negative export electricity prices."
9
+ },
10
+ "instruction_01": {
11
+ "zh_CN": "当买电电价为负时,调整光伏和储能功率,将光伏功率降为最低,尽量从市电买电为电池充电",
12
+ "en_US": "When the electricity purchase price is negative, adjust the power of the photovoltaic system and the energy storage system. Reduce the photovoltaic power to the minimum and try to purchase electricity from the municipal power grid as much as possible to charge the battery."
13
+ },
14
+ "instruction_02": {
15
+ "zh_CN": "当卖电电价为负时,调整系统馈网功率,不向电网馈电",
16
+ "en_US": "When the electricity selling price is negative, adjust the power fed back to the grid by the system and refrain from feeding power back to the grid."
17
+ },
18
+ "IF": {
19
+ "zh_CN": "IF条件",
20
+ "en_US": "IF"
21
+ },
22
+ "THEN": {
23
+ "zh_CN": "THEN动作",
24
+ "en_US": "THEN"
25
+ },
26
+ "date": {
27
+ "zh_CN": "日期: \n\t",
28
+ "en_US": "Date: \n\t"
29
+ },
30
+ "time": {
31
+ "zh_CN": "时间",
32
+ "en_US": "Time"
33
+ },
34
+ "103": {
35
+ "zh_CN": "仅一次",
36
+ "en_US": "Once"
37
+ },
38
+ "104": {
39
+ "zh_CN": "每天",
40
+ "en_US": "Everyday"
41
+ },
42
+ "105": {
43
+ "zh_CN": "工作日",
44
+ "en_US": "Weekdays"
45
+ },
46
+ "106": {
47
+ "zh_CN": "周末",
48
+ "en_US": "Weekends"
49
+ },
50
+ "1": {
51
+ "zh_CN": "周一",
52
+ "en_US": "Mon"
53
+ },
54
+ "2": {
55
+ "zh_CN": "周二",
56
+ "en_US": "Tues"
57
+ },
58
+ "3": {
59
+ "zh_CN": "周三",
60
+ "en_US": "Wed"
61
+ },
62
+ "4": {
63
+ "zh_CN": "周四",
64
+ "en_US": "Thur"
65
+ },
66
+ "5": {
67
+ "zh_CN": "周五",
68
+ "en_US": "Fri"
69
+ },
70
+ "6": {
71
+ "zh_CN": "周六",
72
+ "en_US": "Sat"
73
+ },
74
+ "7": {
75
+ "zh_CN": "周日",
76
+ "en_US": "Sun"
77
+ },
78
+ "weather": {
79
+ "zh_CN": "天气: \n\t",
80
+ "en_US": "Weather: \n\t"
81
+ },
82
+ "irradiance": {
83
+ "zh_CN": "太阳辐照度 {} {}W/m² 且一天内累计有 {} 小时大于200W/m²",
84
+ "en_US": "The solar irradiance {} {}W/m², and totally there are {} hours in a day with a solar irradiance greater than 200W/m²"
85
+ },
86
+ "temperature": {
87
+ "zh_CN": "温度 {} {} ℃",
88
+ "en_US": "Temperature {} {} ℃"
89
+ },
90
+ "humidity": {
91
+ "zh_CN": "湿度 {} {} %RH",
92
+ "en_US": "Humidity {} {} %RH"
93
+ },
94
+ "wind": {
95
+ "zh_CN": "风速 {} {} m/s",
96
+ "en_US": "Wind speed {} {} m/s"
97
+ },
98
+ "barometricPressure": {
99
+ "zh_CN": "气压 {} {} hPa",
100
+ "en_US": "Air pressure {} {} hPa"
101
+ },
102
+ "rain": {
103
+ "zh_CN": "{} 下雨",
104
+ "en_US": "It {} rain"
105
+ },
106
+ "108": {
107
+ "zh_CN": "会",
108
+ "en_US": "will"
109
+ },
110
+ "109": {
111
+ "zh_CN": "不会",
112
+ "en_US": "won''t"
113
+ },
114
+ "forcastRain": {
115
+ "zh_CN": "未来 {} 小时会下雨",
116
+ "en_US": "It will rain in the next {} hours"
117
+ },
118
+ "100": {
119
+ "zh_CN": "大于",
120
+ "en_US": "is greater than"
121
+ },
122
+ "101": {
123
+ "zh_CN": "小于",
124
+ "en_US": "is less than"
125
+ },
126
+ "102": {
127
+ "zh_CN": "等于",
128
+ "en_US": "is equal to"
129
+ },
130
+ "electricityPrice": {
131
+ "zh_CN": "电价: \n\t",
132
+ "en_US": "Electricity price: \n\t"
133
+ },
134
+ "buyingPrice": {
135
+ "zh_CN": "买电电价\n\t",
136
+ "en_US": "Import price\n\t"
137
+ },
138
+ "sellingPrice": {
139
+ "zh_CN": "卖电电价\n\t",
140
+ "en_US": "Export price\n\t"
141
+ },
142
+ "price": {
143
+ "zh_CN": "电价 {} {}{}",
144
+ "en_US": "Electricity price {} {}{}"
145
+ },
146
+ "lowerPrice": {
147
+ "zh_CN": "比最高的电价低 {}{}",
148
+ "en_US": "Lower than the highest electricity price by {}{} "
149
+ },
150
+ "higherPrice": {
151
+ "zh_CN": "比最低的电价高 {}{}",
152
+ "en_US": "Higher than the lowest electricity price by {}{} "
153
+ },
154
+ "expensiveHours": {
155
+ "zh_CN": "在 {} 到 {} 期间,电价最高的 {}小时",
156
+ "en_US": "During the period from {} to {}, the {}h with the highest electricity price"
157
+ },
158
+ "cheapestHours": {
159
+ "zh_CN": "在 {} 到 {} 期间,电价最低的 {} 小时",
160
+ "en_US": "During the period from {} to {}, the {}h with the lowest electricity price"
161
+ },
162
+ "system": {
163
+ "zh_CN": "系统动作\n\t",
164
+ "en_US": "System\n\t"
165
+ },
166
+ "systemSwitch": {
167
+ "zh_CN": "系统开关 {}",
168
+ "en_US": "System {}"
169
+ },
170
+ "on": {
171
+ "zh_CN": "开",
172
+ "en_US": "ON"
173
+ },
174
+ "off": {
175
+ "zh_CN": "关",
176
+ "en_US": "OFF"
177
+ },
178
+ "exportControl": {
179
+ "zh_CN": "馈网控制 {}, {}, 设置值为 {}{}",
180
+ "en_US": "Export_control {}, the mode is {}, the value is {}{}"
181
+ },
182
+ "exportControlOff": {
183
+ "zh_CN": "馈网控制 关",
184
+ "en_US": "Export_control off"
185
+ },
186
+ "total": {
187
+ "zh_CN": "总和方式",
188
+ "en_US": "Total"
189
+ },
190
+ "per phase": {
191
+ "zh_CN": "分相模式",
192
+ "en_US": "Per phase"
193
+ },
194
+ "importControl_AELIO": {
195
+ "zh_CN": "需量控制 {}, 设置值为 {} kW",
196
+ "en_US": "Import_control {}, the value is {} kW"
197
+ },
198
+ "importControl": {
199
+ "zh_CN": "需量控制 {}, 模式: {}, 设置值为 {} kW",
200
+ "en_US": "Import_control {}, Control mode: {}, the value is {} kW"
201
+ },
202
+ "importControl_standby": {
203
+ "zh_CN": "降低储能充电功率,直到待机",
204
+ "en_US": "Reduce battery charge power until standby"
205
+ },
206
+ "importControl_discharge": {
207
+ "zh_CN": "降低储能充电功率,必要时储能放电",
208
+ "en_US": "Reduce battery charge power and discharge battery if necessary"
209
+ },
210
+ "importControlOff": {
211
+ "zh_CN": "需量控制 关",
212
+ "en_US": "Import_control off"
213
+ },
214
+ "workMode": {
215
+ "zh_CN": "工作模式为 {}",
216
+ "en_US": "Work_mode is {}"
217
+ },
218
+ "Self-use": {
219
+ "zh_CN": "自发自用",
220
+ "en_US": "Self-use"
221
+ },
222
+ "Feedin priority": {
223
+ "zh_CN": "并网优先",
224
+ "en_US": "Feedin priority"
225
+ },
226
+ "Back up mode": {
227
+ "zh_CN": "备用模式",
228
+ "en_US": "Back up mode"
229
+ },
230
+ "Manual mode": {
231
+ "zh_CN": "手动模式 - {}",
232
+ "en_US": "Manual mode - {}"
233
+ },
234
+ "Forced charging": {
235
+ "zh_CN": "以{}kW的功率充电至{}%",
236
+ "en_US": "Charge at a power of {} kW until it reaches {}%"
237
+ },
238
+ "Forced discharging": {
239
+ "zh_CN": "以{}kW的功率放电至{}%",
240
+ "en_US": "Discharge at a power of {} kW until it reaches {}%"
241
+ },
242
+ "Stop charging and discharging": {
243
+ "zh_CN": "停止充放电",
244
+ "en_US": "Stop charging and discharging"
245
+ },
246
+ "Peak Shaving": {
247
+ "zh_CN": "削峰填谷",
248
+ "en_US": "Peak Shaving"
249
+ },
250
+ "VPP": {
251
+ "zh_CN": "VPP",
252
+ "en_US": "VPP"
253
+ },
254
+ "Power Control Mode": {
255
+ "zh_CN": "有功功率目标为 {}kW,无功功率目标为 {}kVar",
256
+ "en_US": "Active power target is {}kW. Reactive power target is {}kVar"
257
+ },
258
+ "Electric Quantity Target Control Mode": {
259
+ "zh_CN": "电能目标 {}kWh, 充放电功率目标 {}kW",
260
+ "en_US": "Energy target is {}kWh, Charge or Discharge power target is {}kW"
261
+ },
262
+ "SOC Target Control Mode": {
263
+ "zh_CN": "目标SOC {}%, 充放电功率目标 {}kW",
264
+ "en_US": "target SOC is {}%, Charge or Discharge power target is {}kW"
265
+ },
266
+ "Push Power - Positive/Negative Mode": {
267
+ "zh_CN": "电池功率目标 {}kW",
268
+ "en_US": "Battery power target is {}kW"
269
+ },
270
+ "Push Power - Zero Mode": {
271
+ "zh_CN": "电池不充放",
272
+ "en_US": "Battery not charging or discharging"
273
+ },
274
+ "Self-Consume - Charge/Discharge Mode": {
275
+ "zh_CN": "自发自用,电池仅从PV充电",
276
+ "en_US": "Self-use. The battery can be charged from PV only"
277
+ },
278
+ "Self-Consume - Charge Only Mode": {
279
+ "zh_CN": "自发自用,电池仅从PV充电并且不可放电",
280
+ "en_US": "Self-use. The battery can be charged from PV only, and battery discharge is not allowed"
281
+ },
282
+ "PV&BAT Individual Setting – Duration Mode": {
283
+ "zh_CN": "光伏功率目标 {}kW, 电池功率目标 {}kW",
284
+ "en_US": "PV power target is {}kW. Battery power target is {}kW"
285
+ },
286
+ "PV&BAT Individual Setting – Target SOC Mode": {
287
+ "zh_CN": "光伏功率目标 {}kW, 电池功率目标 {}kW, 目标SOC {}%",
288
+ "en_US": "PV power target is {}kW. Battery power target is {}kW. target SOC is {}%"
289
+ },
290
+ "DoControl": {
291
+ "zh_CN": "DO{}: {};",
292
+ "en_US": "DO{}: {};"
293
+ },
294
+ "duration": {
295
+ "zh_CN": "持续: {}秒",
296
+ "en_US": "last: {} seconds"
297
+ },
298
+ "systemSoc": {
299
+ "zh_CN": "系统soc {} {}%",
300
+ "en_US": "system soc {} {}%"
301
+ },
302
+ "systemImportPower": {
303
+ "zh_CN": "电价买电功率 {} {}KW",
304
+ "en_US": "system soc {} {}KW"
305
+ },
306
+ "systemExportPower": {
307
+ "zh_CN": "电价馈电功率 {} {}KW",
308
+ "en_US": "system soc {} {}KW"
309
+ },
310
+ "cabinetSoc": {
311
+ "zh_CN": "机柜soc {} {}%",
312
+ "en_US": "cabinet soc {} {}%"
313
+ },
314
+ "EMERGENCY": {
315
+ "zh_CN": "紧急告警",
316
+ "en_US": "Emergency alarm"
317
+ },
318
+ "TIPS": {
319
+ "zh_CN": "状态提醒",
320
+ "en_US": "State Tips"
321
+ },
322
+ "NORMAL": {
323
+ "zh_CN": "普通告警",
324
+ "en_US": "Normal alarm"
325
+ },
326
+ "cabinetAlarm": {
327
+ "zh_CN": "机柜发生{}",
328
+ "en_US": "cabinet occurs {}"
329
+ },
330
+ "OR": {
331
+ "zh_CN": "满足任一条件",
332
+ "en_US": "Meet any of the conditions"
333
+ },
334
+ "AND": {
335
+ "zh_CN": "满足所有条件",
336
+ "en_US": "Meet all conditions"
337
+ }
338
+ }
File without changes
File without changes
@@ -0,0 +1,12 @@
1
+ class BaseCondition(object):
2
+ def __init__(self):
3
+ # 子条件类型
4
+ self.child_type_list = []
5
+ # 各子条件的值
6
+ self.value = {}
7
+ # 判断是否满足条件的子条件-判断函数的映射
8
+ self.meet_func_dict = {}
9
+
10
+ def update_value(self):
11
+ """更新条件值"""
12
+ ...
@@ -0,0 +1,104 @@
1
+
2
+ class CabinetCondition(BaseCondition):
3
+ def __init__(self, smart_scene_service):
4
+ super().__init__(smart_scene_service)
5
+ self.type = IF_ELE_TYPE
6
+ self.value = defaultdict(
7
+ lambda: {
8
+ "soc": None,
9
+ "alarm_level": {
10
+ AlarmLevel.EMERGENCY: False,
11
+ AlarmLevel.NORMAL: False,
12
+ AlarmLevel.TIPS: False,
13
+ },
14
+ }
15
+ )
16
+ self.meet_func = self.meet_cabinet_condition
17
+
18
+ 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
86
+
87
+ def meet_cabinet_condition(self, data: CabinetConditionItemData, ctx):
88
+ if not self.value:
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
@@ -0,0 +1,26 @@
1
+ from datetime import datetime
2
+
3
+ from solax_py_library.smart_scene.core.condition.base import BaseCondition
4
+ from solax_py_library.smart_scene.types.condition import DateConditionItemData, DateConditionType
5
+
6
+
7
+ class DateCondition(BaseCondition):
8
+ def __init__(self):
9
+ super().__init__()
10
+ self.value = {}
11
+
12
+ def update_value(self):
13
+ """获取time 类型需要的数据"""
14
+ now = datetime.now()
15
+ self.hour = now.hour
16
+ self.minute = now.minute
17
+
18
+ def meet_func(self, data: DateConditionItemData, ctx):
19
+ if data.childType == DateConditionType.time:
20
+ """判断是否满足日期时间类条件"""
21
+ date = data.childData.data[0]
22
+ hour = int(date.split(":")[0])
23
+ minute = int(date.split(":")[1])
24
+ if hour == self.hour and minute == self.minute:
25
+ return True
26
+ return False
@@ -0,0 +1,105 @@
1
+ from datetime import datetime
2
+
3
+ from solax_py_library.smart_scene.core.condition.base import BaseCondition
4
+ from solax_py_library.smart_scene.types.condition import PriceConditionItemData, PriceConditionType, SmartSceneUnit
5
+
6
+
7
+ class ElePriceCondition(BaseCondition):
8
+ def __init__(self):
9
+ super().__init__()
10
+ self.buy = True
11
+ self.value = {}
12
+ self.unit = None
13
+
14
+ def update_value(self):
15
+ """获取电价 类型需要的数据"""
16
+ ele_info = self.smart_scene_service.get_electrovalence_data()
17
+ if self.buy:
18
+ self.value = ele_info.get("buy", [])
19
+ else:
20
+ self.value = ele_info.get("sell", [])
21
+ self.unit = ele_info.get("ele_unit", " ")
22
+
23
+ def meet_func_price(self, function_value, data_value, index) -> bool:
24
+ """电价条件的判定"""
25
+ if index < 0 or index > len(self.value):
26
+ return False
27
+ if self.value[index] is None:
28
+ return False
29
+ return self.smart_scene_service.compare_the_magnitudes(
30
+ function_value, self.value[index], data_value[0]
31
+ )
32
+
33
+ def meet_func_highest_price(self, data_value, index) -> bool:
34
+ value, unit = data_value
35
+ if None in self.value[0:96]:
36
+ return False
37
+ if unit == SmartSceneUnit.NUM: # 比最高电价低X元
38
+ base = max(self.value[0:96]) - value
39
+ else: # 比最高电价低X%
40
+ base = round(max(self.value[0:96]) * (1 - value / 100), 4)
41
+ if self.value[index] <= base:
42
+ return True
43
+ else:
44
+ return False
45
+
46
+ def meet_func_lowest_price(self, data_value, index) -> bool:
47
+ value, unit = data_value
48
+ if None in self.value[0:96]:
49
+ return False
50
+ if unit == SmartSceneUnit.NUM: # 比最低电价高X元
51
+ base = value - min(self.value[0:96])
52
+ else: # 比最低电价高X%
53
+ base = round(min(self.value[0:96]) * (1 + value / 100), 4)
54
+ if self.value[index] >= base:
55
+ return True
56
+ else:
57
+ return False
58
+
59
+ def meet_func_highest_or_lowest_hours(self, data_value, index, func) -> bool:
60
+ sort_index, start_index = self.smart_scene_service.get_highest_or_lowest_price(
61
+ data_value[0], data_value[1], data_value[2], self.value, func=func
62
+ )
63
+ if not sort_index:
64
+ return False
65
+ if index - start_index in sort_index:
66
+ return True
67
+ else:
68
+ return False
69
+
70
+ def meet_func(self, data: PriceConditionItemData, ctx):
71
+ if not self.value:
72
+ # 未获取到价格数据,直接返回
73
+ return False
74
+ child_data = data.childData
75
+ child_type = data.childType
76
+ data_value = child_data.data
77
+ now_time = datetime.strftime(datetime.now(), "%H:%M")
78
+ index = self.smart_scene_service.trans_str_time_to_index(now_time)
79
+ if child_type == PriceConditionType.price:
80
+ return self.meet_func_price(child_data.function, data_value, index)
81
+ elif child_type == PriceConditionType.lowerPrice:
82
+ return self.meet_func_highest_price(data_value, index)
83
+ elif child_type == PriceConditionType.higherPrice:
84
+ return self.meet_func_lowest_price(data_value, index)
85
+ elif child_type == PriceConditionType.expensiveHours:
86
+ return self.meet_func_highest_or_lowest_hours(
87
+ data_value, index, "expensive_hours"
88
+ )
89
+ elif child_type == PriceConditionType.cheapestHours:
90
+ return self.meet_func_highest_or_lowest_hours(
91
+ data_value, index, "cheapest_hours"
92
+ )
93
+ return False
94
+
95
+
96
+ class EleSellPriceCondition(ElePriceCondition):
97
+ def __init__(self):
98
+ super().__init__()
99
+ self.buy = False
100
+
101
+
102
+ class ElsBuyPriceCondition(ElePriceCondition):
103
+ def __init__(self):
104
+ super().__init__()
105
+ self.buy = True
@@ -0,0 +1,41 @@
1
+
2
+
3
+ class SystemCondition(BaseCondition):
4
+ def __init__(self, smart_scene_service):
5
+ super().__init__(smart_scene_service)
6
+ self.type = IF_ELE_TYPE
7
+ self.value = {}
8
+ self.meet_func = self.meet_system_condition
9
+
10
+ def update_value(self):
11
+ overview_statistic_data = (
12
+ self.smart_scene_service.redis_service.get_overview_statistic_data()
13
+ )
14
+ self.value["grid_active_power"] = overview_statistic_data[8]
15
+ self.value["system_soc"] = overview_statistic_data[16]
16
+
17
+ def meet_system_condition(self, data: SystemConditionItemData, ctx):
18
+ if not self.value:
19
+ return False
20
+ child_data = data.childData
21
+ function_value = child_data.function
22
+ compare_value = None
23
+ app_log.info(self.value)
24
+ if data.childType == SystemConditionType.systemExportPower:
25
+ compare_value = self.value["grid_active_power"]
26
+ if compare_value < 0:
27
+ return False
28
+ elif data.childType == SystemConditionType.systemImportPower:
29
+ compare_value = self.value["grid_active_power"]
30
+ if compare_value > 0:
31
+ return False
32
+ elif data.childType == SystemConditionType.systemSoc:
33
+ compare_value = self.value["system_soc"]
34
+ if compare_value is None:
35
+ return False
36
+ return self.smart_scene_service.compare_the_magnitudes(
37
+ function_value,
38
+ compare_value=abs(compare_value),
39
+ base_value=child_data.data[0],
40
+ )
41
+