solax-py-library 1.0.0.2601__py3-none-any.whl → 1.0.0.2901__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.
@@ -14,3 +14,13 @@ class DeviceType(IntEnum):
14
14
  FIRE_SAFETY_TYPE = 502
15
15
  COLD_TYPE = 503
16
16
  DEHUMIDIFY_TYPE = 504
17
+
18
+ def __str__(self):
19
+ return {
20
+ DeviceType.PCS_TYPE: "pcs",
21
+ DeviceType.BMS_TYPE: "bms",
22
+ DeviceType.ELM_TYPE: "elm",
23
+ DeviceType.IO_TYPE: "io",
24
+ DeviceType.AIRCONDITIONER_TYPE: "air_conditioner",
25
+ DeviceType.COLD_TYPE: "liquid_cooling_unit",
26
+ }.get(self)
@@ -159,21 +159,33 @@ MESSAGE_ENTRY = {
159
159
  "duration": {"zh_CN": "持续: {}秒", "en_US": "last: {} seconds"},
160
160
  "systemSoc": {"zh_CN": "系统soc {} {}%", "en_US": "system soc {} {}%"},
161
161
  "systemImportPower": {
162
- "zh_CN": "电价买电功率 {} {}KW",
163
- "en_US": "system soc {} {}KW",
162
+ "zh_CN": "电网买电功率 {} {}KW",
163
+ "en_US": "Grid import power {} {}KW",
164
164
  },
165
165
  "systemExportPower": {
166
- "zh_CN": "电价馈电功率 {} {}KW",
167
- "en_US": "system soc {} {}KW",
166
+ "zh_CN": "电网馈电功率 {} {}KW",
167
+ "en_US": "Grid export power {} {}KW",
168
168
  },
169
169
  "cabinetSoc": {"zh_CN": "机柜soc {} {}%", "en_US": "cabinet soc {} {}%"},
170
170
  "EMERGENCY": {"zh_CN": "紧急告警", "en_US": "Emergency alarm"},
171
171
  "TIPS": {"zh_CN": "状态提醒", "en_US": "State Tips"},
172
172
  "NORMAL": {"zh_CN": "普通告警", "en_US": "Normal alarm"},
173
- "cabinetAlarm": {"zh_CN": "机柜发生{}", "en_US": "cabinet occurs {}"},
173
+ "cabinetAlarm": {
174
+ "zh_CN": "机柜下属({})设备发生{}",
175
+ "en_US": "The equipments({}) under the cabinet occurs {}",
176
+ },
174
177
  "OR": {"zh_CN": "满足任一条件", "en_US": "Meet any of the conditions"},
175
178
  "AND": {"zh_CN": "满足所有条件", "en_US": "Meet all conditions"},
176
179
  "tips_alarm": {"zh_CN": "状态提醒", "en_US": "Alarm tips"},
177
180
  "normal_alarm": {"zh_CN": "普通告警", "en_US": "Normal alarm"},
178
181
  "emergency_alarm": {"zh_CN": "紧急告警", "en_US": "Emergency alarm"},
182
+ "pcs": {"zh_CN": "逆变器", "en_US": "Inverter"},
183
+ "bms": {"zh_CN": "电池", "en_US": "Battery"},
184
+ "elm": {
185
+ "zh_CN": "电表",
186
+ "en_US": "Meter",
187
+ },
188
+ "io": {"zh_CN": "IO模块", "en_US": "IO Module"},
189
+ "air_conditioner": {"zh_CN": "空调", "en_US": "Air conditioner"},
190
+ "liquid_cooling_unit": {"zh_CN": "液冷机组", "en_US": "Liquid Cooling Unit"},
179
191
  }
@@ -1,6 +1,5 @@
1
1
  class BaseAction(object):
2
- def __init__(self, smart_scene_service, do_funcs, **kwargs):
3
- self.smart_scene_service = smart_scene_service
2
+ def __init__(self, do_funcs, **kwargs):
4
3
  self.do_func_map = do_funcs
5
4
 
6
5
  def do_func(self, scene_id, data):
@@ -6,7 +6,6 @@ from solax_py_library.smart_scene.types.condition import (
6
6
  CabinetConditionType,
7
7
  ConditionType,
8
8
  )
9
- from solax_py_library.device.types.alarm import AlarmLevel
10
9
  from solax_py_library.smart_scene.types.condition_value import CabinetValue
11
10
 
12
11
 
@@ -15,9 +14,7 @@ class CabinetCondition(BaseCondition):
15
14
 
16
15
  def __init__(self, update_value_function, **kwargs):
17
16
  super().__init__(update_value_function, **kwargs)
18
- self.value = defaultdict(
19
- lambda: CabinetValue
20
- )
17
+ self.value = defaultdict(lambda: CabinetValue)
21
18
 
22
19
  def meet_func(self, data: CabinetConditionItemData, ctx):
23
20
  if not self.value:
@@ -42,6 +39,6 @@ class CabinetCondition(BaseCondition):
42
39
  alarm_info = cabinet_value.alarm_info(device_type)
43
40
  if not alarm_info:
44
41
  continue
45
- if alarm_info[alarm_type-1] is True:
42
+ if alarm_info[alarm_type - 1] is True:
46
43
  return True
47
44
  return False
@@ -21,10 +21,14 @@ class WeatherCondition(BaseCondition):
21
21
  function_value = child_data.function
22
22
  data_value = child_data.data
23
23
  nearest_time, right_time = get_rounded_times()
24
- if nearest_time not in self.value["timeList"]:
25
- time_now = right_time
26
- else:
27
- time_now = nearest_time
24
+ if (
25
+ nearest_time not in self.value["timeList"]
26
+ and right_time not in self.value["timeList"]
27
+ ):
28
+ return False
29
+ time_now = (
30
+ right_time if nearest_time not in self.value["timeList"] else nearest_time
31
+ )
28
32
  index = self.value["timeList"].index(time_now)
29
33
  if child_type == WeatherConditionType.irradiance:
30
34
  return self.meet_func_irradiance(function_value, data_value, index)
@@ -0,0 +1,33 @@
1
+ from typing import List, Dict, Any
2
+
3
+ from solax_py_library.smart_scene.types.action import SmartSceneAction, ActionType
4
+ from solax_py_library.smart_scene.types.condition import (
5
+ SmartSceneCondition,
6
+ ConditionType,
7
+ )
8
+
9
+
10
+ def action_param_check(actions: List[SmartSceneAction], ctx: Dict[str, Any]):
11
+ """动作里的参数范围判定"""
12
+ for action in actions:
13
+ if action.type != ActionType.system:
14
+ continue
15
+ for action_data in action.data:
16
+ ret = action_data.check_param(ctx)
17
+ if ret is not None:
18
+ return ret
19
+ return True
20
+
21
+
22
+ def condition_param_check(condition: SmartSceneCondition, ctx: Dict[str, Any]):
23
+ for condition_data in condition.value:
24
+ if condition_data.type not in [
25
+ ConditionType.systemCondition,
26
+ ConditionType.cabinet,
27
+ ]:
28
+ continue
29
+ for data in condition_data.data:
30
+ ret = data.check_param(ctx)
31
+ if ret is not None:
32
+ return ret
33
+ return True
@@ -1,10 +1,28 @@
1
- from enum import Enum
1
+ from enum import Enum, IntEnum
2
2
  from typing import List, Union, Any
3
3
 
4
4
  from pydantic import BaseModel
5
5
 
6
6
  from solax_py_library.device.constant.cabinet import TRENE_CABINET_ENUM
7
7
  from solax_py_library.smart_scene.constant.message_entry import MESSAGE_ENTRY
8
+ from solax_py_library.smart_scene.exceptions.smart_scene import (
9
+ ExportLimitNum,
10
+ ImportLimitNum,
11
+ ImportOnlyPositive,
12
+ PowerLimitNum,
13
+ SocLimit,
14
+ ActivePowerLimitNum,
15
+ ReactivePowerLimitNum,
16
+ EnergyLimit,
17
+ BatteryPowerLimitNum,
18
+ PvOnlyGe0,
19
+ ExportLimitPercent,
20
+ )
21
+
22
+
23
+ class SmartSceneUnit(IntEnum):
24
+ PERCENT = 1
25
+ NUM = 2
8
26
 
9
27
 
10
28
  class ActionType(str, Enum):
@@ -36,7 +54,12 @@ class SystemActionChildData(ActionChildData):
36
54
  ...
37
55
 
38
56
 
39
- class SystemActionItemData(BaseModel):
57
+ class ActionItemData(BaseModel):
58
+ def check_param(self, ctx):
59
+ ...
60
+
61
+
62
+ class SystemActionItemData(ActionItemData):
40
63
  childType: SystemActionType
41
64
  childData: SystemActionChildData
42
65
 
@@ -136,12 +159,163 @@ class SystemActionItemData(BaseModel):
136
159
  return MESSAGE_ENTRY[work_mode[value_data[0]]][lang]
137
160
  return ""
138
161
 
162
+ def check_param(self, ctx):
163
+ if self.childType == SystemActionType.exportControl:
164
+ export_power_top_limit = ctx.pop("export_power_top_limit")
165
+ switch = self.childData.data[0]
166
+ if not switch:
167
+ return
168
+ _, _, value, unit = self.childData.data
169
+ if unit == SmartSceneUnit.NUM:
170
+ if value > export_power_top_limit or value < 0:
171
+ return ExportLimitNum, {"up_limit": export_power_top_limit}
172
+ else:
173
+ if value > 0 or value < 110:
174
+ return ExportLimitPercent, {}
175
+ elif self.childType == SystemActionType.importControl:
176
+ import_power_top_limit = ctx.pop("import_power_top_limit", None)
177
+ total_power_top_limit = ctx.pop("total_power_top_limit", None)
178
+ switch = self.childData.data[0]
179
+ if not switch:
180
+ return
181
+ value = self.childData.data[-1]
182
+ if import_power_top_limit is not None:
183
+ if value > total_power_top_limit or value < 0:
184
+ return (
185
+ ImportLimitNum.message,
186
+ {"up_limit": import_power_top_limit},
187
+ )
188
+ else:
189
+ if value < 0:
190
+ return ImportOnlyPositive.message, {}
191
+ elif self.childType == SystemActionType.workMode:
192
+ work_mode = self.childData.data[0]
193
+ total_power_top_limit = ctx.pop("total_power_top_limit")
194
+ total_energy_top_limit = ctx.pop("total_energy_top_limit")
195
+ soc_low_limit = ctx.pop("soc_low_limit")
196
+ if work_mode == 3: # 手动模式
197
+ if self.childData.data[1] in [3, 4]: # 强充或强放
198
+ _, _, power, soc = self.childData.data
199
+ if power <= 0 or power > total_power_top_limit:
200
+ return (
201
+ PowerLimitNum.message,
202
+ {"low_limit": 0, "up_limit": total_power_top_limit},
203
+ )
204
+ if soc > 100 or soc < soc_low_limit:
205
+ return (
206
+ SocLimit.message,
207
+ {"low_limit": soc_low_limit},
208
+ )
209
+ elif work_mode == 16: # VPP模式
210
+ vpp_mode = self.childData.data[1]
211
+ if vpp_mode == 1:
212
+ (
213
+ _,
214
+ _,
215
+ active_power,
216
+ reactive_power,
217
+ ) = self.childData.data
218
+ if (
219
+ active_power < -total_power_top_limit
220
+ or active_power > total_power_top_limit
221
+ ):
222
+ return (
223
+ ActivePowerLimitNum.message,
224
+ {
225
+ "low_limit": -total_power_top_limit,
226
+ "up_limit": total_power_top_limit,
227
+ },
228
+ )
229
+ if (
230
+ reactive_power < -total_power_top_limit
231
+ or reactive_power > total_power_top_limit
232
+ ):
233
+ return (
234
+ ReactivePowerLimitNum.message,
235
+ {
236
+ "low_limit": -total_power_top_limit,
237
+ "up_limit": total_power_top_limit,
238
+ },
239
+ )
240
+ elif vpp_mode == 2:
241
+ _, _, energy, power = self.childData.data
242
+ if energy < 0 or energy > total_energy_top_limit:
243
+ return (
244
+ EnergyLimit.message,
245
+ {"up_limit": total_energy_top_limit},
246
+ )
247
+ if power < -total_power_top_limit or power > total_power_top_limit:
248
+ return (
249
+ PowerLimitNum.message,
250
+ {
251
+ "low_limit": -total_power_top_limit,
252
+ "up_limit": total_power_top_limit,
253
+ },
254
+ )
255
+ elif vpp_mode == 3:
256
+ _, _, soc, power = self.childData.data
257
+ if soc < soc_low_limit or soc > 100:
258
+ return (
259
+ SocLimit.message,
260
+ {"low_limit": soc_low_limit},
261
+ )
262
+ if power < -total_power_top_limit or power > total_power_top_limit:
263
+ return (
264
+ PowerLimitNum.message,
265
+ {
266
+ "low_limit": -total_power_top_limit,
267
+ "up_limit": total_power_top_limit,
268
+ },
269
+ )
270
+ elif vpp_mode == 4:
271
+ _, _, power = self.childData.data
272
+ if power < -total_power_top_limit or power > total_power_top_limit:
273
+ return (
274
+ BatteryPowerLimitNum.message,
275
+ {
276
+ "low_limit": -total_power_top_limit,
277
+ "up_limit": total_power_top_limit,
278
+ },
279
+ )
280
+ elif vpp_mode == 8:
281
+ _, _, pv_power, bms_power = self.childData.data
282
+ if pv_power < 0:
283
+ return (PvOnlyGe0.message, {})
284
+ elif (
285
+ bms_power < -total_power_top_limit
286
+ or bms_power > total_power_top_limit
287
+ ):
288
+ return (
289
+ BatteryPowerLimitNum.message,
290
+ {
291
+ "low_limit": -total_power_top_limit,
292
+ "up_limit": total_power_top_limit,
293
+ },
294
+ )
295
+ elif vpp_mode == 9:
296
+ _, _, pv_power, bms_power, soc = self.childData.data
297
+ if pv_power < 0:
298
+ return (PvOnlyGe0.message, {})
299
+ if (
300
+ bms_power < -total_power_top_limit
301
+ or bms_power > total_power_top_limit
302
+ ):
303
+ return (
304
+ BatteryPowerLimitNum.message,
305
+ {
306
+ "low_limit": -total_power_top_limit,
307
+ "up_limit": total_power_top_limit,
308
+ },
309
+ )
310
+ if soc < soc_low_limit or soc > 100:
311
+ return SocLimit.message, {"low_limit": soc_low_limit}
312
+
139
313
 
140
314
  class EmsActionChildData(ActionChildData):
141
315
  data: List[DoControl]
142
316
 
143
317
 
144
- class EmsActionItemData(BaseModel):
318
+ class EmsActionItemData(ActionItemData):
145
319
  childType: EmsActionType
146
320
  childData: EmsActionChildData
147
321
 
@@ -2,10 +2,12 @@ import operator
2
2
  from enum import IntEnum, Enum
3
3
  from typing import Optional, List, Union, Any
4
4
 
5
- from pydantic import BaseModel, validator, root_validator
5
+ from pydantic import BaseModel, validator
6
6
 
7
7
  from solax_py_library.device.types.alarm import AlarmLevel
8
+ from solax_py_library.device.types.device import DeviceType
8
9
  from solax_py_library.smart_scene.constant.message_entry import MESSAGE_ENTRY
10
+ from solax_py_library.smart_scene.exceptions.smart_scene import SocLimit
9
11
 
10
12
 
11
13
  class LogicFunc(IntEnum):
@@ -82,7 +84,12 @@ class ConditionItemChildData(BaseModel):
82
84
  data: List[Any]
83
85
 
84
86
 
85
- class PriceConditionItemData(BaseModel):
87
+ class ConditionItemData(BaseModel):
88
+ def check_param(self, ctx):
89
+ ...
90
+
91
+
92
+ class PriceConditionItemData(ConditionItemData):
86
93
  childType: PriceConditionType
87
94
  childData: ConditionItemChildData
88
95
 
@@ -122,7 +129,7 @@ class PriceConditionItemData(BaseModel):
122
129
  return MESSAGE_ENTRY[self.childType][lang].format(data[0], data[1], data[2])
123
130
 
124
131
 
125
- class SystemConditionItemData(BaseModel):
132
+ class SystemConditionItemData(ConditionItemData):
126
133
  childType: SystemConditionType
127
134
  childData: ConditionItemChildData
128
135
 
@@ -135,8 +142,6 @@ class SystemConditionItemData(BaseModel):
135
142
  }:
136
143
  assert 0 <= value.data[0] <= 100000, ValueError
137
144
  value.data[0] = round(value.data[0], 2) # 功率保留两位小数
138
- elif child_type == SystemConditionType.systemSoc:
139
- assert 5 <= value.data[0] <= 100, ValueError
140
145
  return value
141
146
 
142
147
  def to_text(self, lang, unit):
@@ -154,8 +159,15 @@ class SystemConditionItemData(BaseModel):
154
159
  MESSAGE_ENTRY[str(func.value)][lang], data[0]
155
160
  )
156
161
 
162
+ def check_param(self, ctx):
163
+ soc_low_limit = ctx.pop("soc_low_limit", 5)
164
+ if self.childType == SystemConditionType.systemSoc:
165
+ soc = self.childData.data[0]
166
+ if soc < soc_low_limit or soc > 100:
167
+ return SocLimit.message, {"low_limit": soc_low_limit}
168
+
157
169
 
158
- class CabinetConditionItemData(BaseModel):
170
+ class CabinetConditionItemData(ConditionItemData):
159
171
  childType: CabinetConditionType
160
172
  childData: ConditionItemChildData
161
173
 
@@ -168,8 +180,6 @@ class CabinetConditionItemData(BaseModel):
168
180
  AlarmLevel.NORMAL,
169
181
  AlarmLevel.EMERGENCY,
170
182
  }, ValueError
171
- if child_type == CabinetConditionType.cabinetSoc:
172
- assert 0 <= value.data[0] <= 100, ValueError
173
183
  return value
174
184
 
175
185
  def to_text(self, lang, unit):
@@ -181,16 +191,29 @@ class CabinetConditionItemData(BaseModel):
181
191
  )
182
192
  elif self.childType == CabinetConditionType.cabinetAlarm:
183
193
  return MESSAGE_ENTRY[self.childType][lang].format(
184
- MESSAGE_ENTRY[str(AlarmLevel(data[0]))][lang], lang
194
+ ",".join(
195
+ [
196
+ MESSAGE_ENTRY[str(DeviceType(device_type))][lang]
197
+ for device_type in data[:-1]
198
+ ]
199
+ ),
200
+ MESSAGE_ENTRY[str(AlarmLevel(data[-1]))][lang],
185
201
  )
186
202
 
203
+ def check_param(self, ctx):
204
+ soc_low_limit = ctx.pop("soc_low_limit", 5)
205
+ if self.childType == CabinetConditionType.cabinetSoc:
206
+ soc = self.childData.data[0]
207
+ if soc < soc_low_limit or soc > 100:
208
+ return SocLimit.message, {"low_limit": soc_low_limit}
209
+
187
210
 
188
- class DateConditionItemData(BaseModel):
211
+ class DateConditionItemData(ConditionItemData):
189
212
  childType: DateConditionType
190
213
  childData: ConditionItemChildData
191
214
 
192
215
  @validator("childData", always=True)
193
- def check_param(cls, value, values):
216
+ def _check_child_data(cls, value, values):
194
217
  child_type = values.get("childType")
195
218
  data = value.data
196
219
  if child_type == DateConditionType.time:
@@ -206,7 +229,7 @@ class DateConditionItemData(BaseModel):
206
229
  return MESSAGE_ENTRY[self.childType][lang] + "/" + self.childData.data[0]
207
230
 
208
231
 
209
- class WeatherConditionItemData(BaseModel):
232
+ class WeatherConditionItemData(ConditionItemData):
210
233
  childType: WeatherConditionType
211
234
  childData: ConditionItemChildData
212
235
 
@@ -265,24 +288,6 @@ class SmartSceneCondition(BaseModel):
265
288
  operation: LogicFunc
266
289
  value: List[ConditionItem]
267
290
 
268
- @root_validator
269
- def _root_check(cls, values):
270
- if values.get("operation") == LogicFunc.OR:
271
- new_value = []
272
- for item in values.get("value"):
273
- if item.type != ConditionType.date:
274
- new_value.append(item)
275
- continue
276
- new_data = []
277
- for date_item in item.data:
278
- if date_item.childType != DateConditionType.duration:
279
- new_data.append(date_item)
280
- item.data = new_data
281
- if item.data:
282
- new_value.append(item)
283
- values["value"] = new_value
284
- return values
285
-
286
291
  def to_text(self, lang, unit):
287
292
  ret = {"operation": [MESSAGE_ENTRY[self.operation.name][lang]]}
288
293
  for v in self.value:
@@ -7,12 +7,12 @@ from solax_py_library.device.types.device import DeviceType
7
7
 
8
8
  class CabinetValue(BaseModel):
9
9
  soc: int = None
10
- cabinet_alarm: List[bool] = Field(default_factory=lambda :[False, False, False])
11
- pcs_alarm: List[bool] = Field(default_factory=lambda :[False, False, False])
12
- io_alarm: List[bool] = Field(default_factory=lambda :[False, False, False])
13
- bms_alarm: List[bool] = Field(default_factory=lambda :[False, False, False])
14
- air_alarm: List[bool] = Field(default_factory=lambda :[False, False, False])
15
- liquid_alarm: List[bool] = Field(default_factory=lambda :[False, False, False])
10
+ cabinet_alarm: List[bool] = Field(default_factory=lambda: [False, False, False])
11
+ pcs_alarm: List[bool] = Field(default_factory=lambda: [False, False, False])
12
+ io_alarm: List[bool] = Field(default_factory=lambda: [False, False, False])
13
+ bms_alarm: List[bool] = Field(default_factory=lambda: [False, False, False])
14
+ air_alarm: List[bool] = Field(default_factory=lambda: [False, False, False])
15
+ liquid_alarm: List[bool] = Field(default_factory=lambda: [False, False, False])
16
16
 
17
17
  def alarm_info(self, device_type):
18
18
  if device_type == DeviceType.EMS_TYPE:
@@ -0,0 +1,83 @@
1
+ from unittest import TestCase
2
+
3
+ from solax_py_library.smart_scene.core.service.check import (
4
+ condition_param_check,
5
+ action_param_check,
6
+ )
7
+ from solax_py_library.smart_scene.types.action import (
8
+ SmartSceneAction,
9
+ ActionType,
10
+ SystemActionType,
11
+ SystemActionItemData,
12
+ SystemActionChildData,
13
+ )
14
+ from solax_py_library.smart_scene.types.condition import (
15
+ SmartSceneCondition,
16
+ ConditionItem,
17
+ ConditionType,
18
+ SystemConditionItemData,
19
+ LogicFunc,
20
+ SystemConditionType,
21
+ ConditionItemChildData,
22
+ CabinetConditionItemData,
23
+ CabinetConditionType,
24
+ ConditionFunc,
25
+ )
26
+
27
+
28
+ class TestCheckFunc(TestCase):
29
+ def test_check_condition_func(self):
30
+ con = SmartSceneCondition(
31
+ operation=LogicFunc.AND,
32
+ value=[
33
+ ConditionItem(
34
+ type=ConditionType.systemCondition,
35
+ data=[
36
+ SystemConditionItemData(
37
+ childType=SystemConditionType.systemSoc,
38
+ childData=ConditionItemChildData(
39
+ data=[101], function=ConditionFunc.EQ
40
+ ),
41
+ ),
42
+ ],
43
+ cabinet=None,
44
+ ),
45
+ ConditionItem(
46
+ type=ConditionType.cabinet,
47
+ data=[
48
+ CabinetConditionItemData(
49
+ childType=CabinetConditionType.cabinetSoc,
50
+ childData=ConditionItemChildData(
51
+ data=[4], function=ConditionFunc.EQ
52
+ ),
53
+ )
54
+ ],
55
+ cabinet=["1", "2"],
56
+ ),
57
+ ],
58
+ )
59
+ ret = condition_param_check(con, ctx={"soc_low_limit": 10})
60
+ assert ret is not None
61
+
62
+ def test_check_action_func(self):
63
+ action = [
64
+ SmartSceneAction(
65
+ type=ActionType.system,
66
+ data=[
67
+ SystemActionItemData(
68
+ childType=SystemActionType.importControl,
69
+ childData=SystemActionChildData(data=[1, -10]),
70
+ )
71
+ ],
72
+ )
73
+ ]
74
+ ret = action_param_check(
75
+ actions=action,
76
+ ctx={
77
+ "cabinet_type": 3,
78
+ "total_power": 1,
79
+ "total_power_except_solar_inv": 1,
80
+ "total_energy": 1,
81
+ },
82
+ )
83
+ assert ret is not None
@@ -1,20 +1,36 @@
1
1
  from unittest import TestCase
2
2
 
3
3
  from solax_py_library.device.types.device import DeviceType
4
- from solax_py_library.smart_scene.core.condition import DateCondition, BaseCondition, CabinetCondition
5
- from solax_py_library.smart_scene.types.condition import CabinetConditionItemData, CabinetConditionType, \
6
- ConditionItemChildData
4
+ from solax_py_library.smart_scene.core.condition import (
5
+ DateCondition,
6
+ BaseCondition,
7
+ CabinetCondition,
8
+ )
9
+ from solax_py_library.smart_scene.types.condition import (
10
+ CabinetConditionItemData,
11
+ CabinetConditionType,
12
+ ConditionItemChildData,
13
+ )
7
14
  from solax_py_library.smart_scene.types.condition_value import CabinetValue
8
15
 
9
16
 
10
17
  class TestCondition(TestCase):
11
- def test_condition(self):
18
+ def test_condition_build(self):
12
19
  date_condition = DateCondition(
13
20
  update_value_function=lambda: 1,
14
21
  )
15
22
  assert isinstance(date_condition, BaseCondition)
16
23
 
17
- def test_cabinet_condition(self):
24
+ def test_cabinet_condition_to_text(self):
25
+ cabinet_condition = CabinetConditionItemData(
26
+ childType=CabinetConditionType.cabinetAlarm,
27
+ childData=ConditionItemChildData(
28
+ data=[DeviceType.IO_TYPE, DeviceType.COLD_TYPE, 1]
29
+ ),
30
+ )
31
+ print(cabinet_condition.to_text(lang="zh_CN", unit="嘻嘻"))
32
+
33
+ def test_cabinet_condition_check(self):
18
34
  cabinet_condition = CabinetCondition(
19
35
  update_value_function=lambda: {
20
36
  "SN1": CabinetValue(
@@ -24,22 +40,27 @@ class TestCondition(TestCase):
24
40
  },
25
41
  )
26
42
  cabinet_condition.update_value()
27
- assert cabinet_condition.meet_func(
28
- data=CabinetConditionItemData(
29
- childType=CabinetConditionType.cabinetAlarm,
30
- childData=ConditionItemChildData(
31
- data=[DeviceType.IO_TYPE, DeviceType.COLD_TYPE, 1]
32
- )
33
- ),
34
- ctx={"cabinet": ["SN1"]}
35
- ) is False
36
- assert cabinet_condition.meet_func(
37
- data=CabinetConditionItemData(
38
- childType=CabinetConditionType.cabinetAlarm,
39
- childData=ConditionItemChildData(
40
- data=[DeviceType.IO_TYPE, DeviceType.COLD_TYPE, 2]
41
- )
42
- ),
43
- ctx={"cabinet": ["SN1"]}
44
- ) is True
45
-
43
+ assert (
44
+ cabinet_condition.meet_func(
45
+ data=CabinetConditionItemData(
46
+ childType=CabinetConditionType.cabinetAlarm,
47
+ childData=ConditionItemChildData(
48
+ data=[DeviceType.IO_TYPE, DeviceType.COLD_TYPE, 1]
49
+ ),
50
+ ),
51
+ ctx={"cabinet": ["SN1"]},
52
+ )
53
+ is False
54
+ )
55
+ assert (
56
+ cabinet_condition.meet_func(
57
+ data=CabinetConditionItemData(
58
+ childType=CabinetConditionType.cabinetAlarm,
59
+ childData=ConditionItemChildData(
60
+ data=[DeviceType.IO_TYPE, DeviceType.COLD_TYPE, 2]
61
+ ),
62
+ ),
63
+ ctx={"cabinet": ["SN1"]},
64
+ )
65
+ is True
66
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: solax-py-library
3
- Version: 1.0.0.2601
3
+ Version: 1.0.0.2901
4
4
  Summary: some common tool
5
5
  Author: shenlvyu
6
6
  Author-email: 13296718439@163.com
@@ -8,35 +8,36 @@ solax_py_library/device/core/interver/__init__.py,sha256=RKye2D6NawSGdL4YUp_H-Lm
8
8
  solax_py_library/device/core/interver/base.py,sha256=2TXHsjigMcIvGDLF3ZD4dw6UDrRRAk9Mq6sdBKRvydc,7191
9
9
  solax_py_library/device/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  solax_py_library/device/types/alarm.py,sha256=kartXs_iRSV9Y3weFSsh9wMXU1_FxHZa6inHThyQCOk,358
11
- solax_py_library/device/types/device.py,sha256=fksdxtCyG8Bvzs5lgUHjQm_Whj0NQwQP7PLZVPiwc24,328
11
+ solax_py_library/device/types/device.py,sha256=oGnuJXPpoOFUc3LgrwCMJSAXKX6VQYEjEd_VmU6zcBA,667
12
12
  solax_py_library/device/types/inverter_config.py,sha256=qCInNPbgsWf6yQjSw59kfQtJJWilMYUhvx_qo5qwRlU,912
13
13
  solax_py_library/device/types/modbus_point.py,sha256=YmXe92gWXL_voVXDJE5zzNzr6dpPs7Ff3ciOAW-LgPs,580
14
14
  solax_py_library/exception.py,sha256=ygAccdTqJctRrdt9bu6-vqZP5KadfKVS_1tjt4KcRn8,257
15
15
  solax_py_library/smart_scene/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  solax_py_library/smart_scene/constant/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- solax_py_library/smart_scene/constant/message_entry.py,sha256=r-hSUQItc0xEgodXtDct7AltFHQZxj5KH6ZP_ioZtAQ,9191
17
+ solax_py_library/smart_scene/constant/message_entry.py,sha256=4dItLHwgYjSvEb-UbhjT1l8BIbNGk9EyTNhrqD4HEBY,9667
18
18
  solax_py_library/smart_scene/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  solax_py_library/smart_scene/core/action/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
- solax_py_library/smart_scene/core/action/base.py,sha256=CCYrlCZeb3CfGZgTWQN673VJmuYNsTbEtdZ4ERUV7RA,395
20
+ solax_py_library/smart_scene/core/action/base.py,sha256=GlZQTi7ub0fREV5BUZQUTARw3mleWWsKHOA7eFPVoJs,319
21
21
  solax_py_library/smart_scene/core/action/ems_action.py,sha256=sML6qasFoqOktTvEcHm0vKPYCj60VcKjAFz8RAaQc2U,206
22
22
  solax_py_library/smart_scene/core/action/system_action.py,sha256=oGXq3yXS9nKcGjJActjk0R2Wr3AoO9uoyRPyuiM053g,204
23
23
  solax_py_library/smart_scene/core/condition/__init__.py,sha256=1nN-N52Oq7LKdn6ApKGtSZq5fB1qJzJq8BOKOumfQvY,475
24
24
  solax_py_library/smart_scene/core/condition/base.py,sha256=saj7dc0Su2Wi_Lx04cesHFgIPDyQUwvHuDElcaDOIHU,596
25
- solax_py_library/smart_scene/core/condition/cabinet_condition.py,sha256=mLouKmO9VywSYlnha5lfAAOyPZUUWjEpvUEWEvx0HyQ,1803
25
+ solax_py_library/smart_scene/core/condition/cabinet_condition.py,sha256=HhOmFGs6srnC4oO5h1p3Z09Y9LPeywi1KaL5dG0pJf8,1724
26
26
  solax_py_library/smart_scene/core/condition/date_condition.py,sha256=Xhca6VjoM8Bq-I-dFj1RPLTTzbBL81ORkBnR8D-YqUw,772
27
27
  solax_py_library/smart_scene/core/condition/price_condition.py,sha256=IkgoB5YhpMxgFVkabilcBXtkjsqae01kkjF3tH10CK0,4006
28
28
  solax_py_library/smart_scene/core/condition/system_condition.py,sha256=q5KDQdK6wjEvq0__WwBR4Sk-59yA2aIAgxTf1xjxJQk,1338
29
- solax_py_library/smart_scene/core/condition/weather_condition.py,sha256=Xp7l9m3NW1vyyRGaJC5_gAX4HM-iuj7OGaw5LbZ4ztU,2223
29
+ solax_py_library/smart_scene/core/condition/weather_condition.py,sha256=ZoP5QM0kswQCrb1N22_W358BnhgDc6eXp9XPR5WKAgs,2363
30
30
  solax_py_library/smart_scene/core/service/__init__.py,sha256=wWzHSN2XaHnI-TNtCJWWRHnNC7s3-2GNQo9y0K_PC4Q,69
31
+ solax_py_library/smart_scene/core/service/check.py,sha256=qoNixyjgwHRdb0HnU3UcZDEOeI9t0PxvjZcbgvB79Vs,1031
31
32
  solax_py_library/smart_scene/core/service/runner.py,sha256=SwQ6jb5yFPcyHyfU-THyGDjPEMcNFUOHkvVYA9wB1EE,6201
32
33
  solax_py_library/smart_scene/exceptions/__init__.py,sha256=0hDgr70fFLQB14uorVCwbBhl1yQmZ-uBYGH5XtGm_dg,147
33
34
  solax_py_library/smart_scene/exceptions/price.py,sha256=3bnY6JzeEskUoXVzEs8bpg6hQzgbinBKY4GP4hBITWU,152
34
35
  solax_py_library/smart_scene/exceptions/smart_scene.py,sha256=69khvoFm1Eki4NBT45gVnsyWubEzF7dqnhU-unqT20g,1701
35
36
  solax_py_library/smart_scene/exceptions/weather.py,sha256=bJl1VwiIXEpLQ9VjlVrDoTAIMFqVZdRCas7dtR7eAJc,133
36
37
  solax_py_library/smart_scene/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
- solax_py_library/smart_scene/types/action.py,sha256=cYICnxLfLRWFAlOGWpS2HBw-PyaB6TNlNuEmSsme26k,5723
38
- solax_py_library/smart_scene/types/condition.py,sha256=l6LFLvUCqKNX8qZqLsLUOkb5K_0nVAd0lc92wZcxWns,9565
39
- solax_py_library/smart_scene/types/condition_value.py,sha256=H-45M4HEyBZXOToJZ2ftmV4d9hgDIWxqCaRMVGlQFXk,1247
38
+ solax_py_library/smart_scene/types/action.py,sha256=Xne9t-g-Ob5Le06zfKO7ceP9dtdMeq7EFcFske7GbmM,13227
39
+ solax_py_library/smart_scene/types/condition.py,sha256=etBD6hQHxyhtYucvIhKp0F1rTnaC6D2IEwQyzyuTzgY,9730
40
+ solax_py_library/smart_scene/types/condition_value.py,sha256=by5R3sVNOJCrghLLaNT54jiTqZYT7YvQQ4q9ovIXkqQ,1242
40
41
  solax_py_library/smart_scene/types/smart_scene_content.py,sha256=C8H17QEicmDBbxN-m550njwaZyUhAL2hUhlLg3Qj1zM,6061
41
42
  solax_py_library/snap_shot/__init__.py,sha256=Ex12q6BCkdU-3OP-f-ehGCetJJWnoZ7KxhEDd_lXh6M,81
42
43
  solax_py_library/snap_shot/constant/__init__.py,sha256=UNfjAlx1wovXc1oH74af9oIe2TljwCCiTzNXzWgtUms,65
@@ -52,7 +53,8 @@ solax_py_library/snap_shot/types/__init__.py,sha256=g9ybB88TntvAMGIhLgJ31Xxn26zl
52
53
  solax_py_library/snap_shot/types/address.py,sha256=JhyB-t2OnKuE8akKk120sojCNXv4_OlLLuWsl5ChFZ8,1148
53
54
  solax_py_library/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
55
  solax_py_library/test/test_smart_scene/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
- solax_py_library/test/test_smart_scene/test_condition.py,sha256=gnNliXSLqDsEj-J2-xgBYagxNI5rJlBZSfbkOR7AJZE,1664
56
+ solax_py_library/test/test_smart_scene/test_check_func.py,sha256=mVZedGT2OocqX1-qtVlVHRlimwyR3xtRwxcOGzREZAE,2584
57
+ solax_py_library/test/test_smart_scene/test_condition.py,sha256=du1vqtwmDFPY__SNqQ-RcDjrDO6e2ZnBjNbPxWpihI4,2209
56
58
  solax_py_library/test/test_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
59
  solax_py_library/test/test_utils/test_cloud_client.py,sha256=gOrHGXkFXpFV4kXTnjhmyJGem8VaGKw8OmXyW884oJ0,395
58
60
  solax_py_library/upload/__init__.py,sha256=XhZar7BKaRN0XcdPl4QffWr488L3UWvuq5syT8nX2OU,93
@@ -77,6 +79,6 @@ solax_py_library/utils/cloud_client.py,sha256=5dZrc5fzrNFSXqTPZd7oHt-Y9Jj6RCigB7
77
79
  solax_py_library/utils/common.py,sha256=bfnZcX9uM-PjJrYAFv1UMmZgt6bGR7MaOd7jRPNHGxw,1238
78
80
  solax_py_library/utils/struct_util.py,sha256=pL6L80GXIHasy1ZDIj89-5BzXW1BWI3TPitH7thGGIE,1577
79
81
  solax_py_library/utils/time_util.py,sha256=bY5kj9dmyOuLEQ6uYGQK7jU7y1RMiHZgevEKnkcQcSU,1461
80
- solax_py_library-1.0.0.2601.dist-info/METADATA,sha256=dHRe01IzV0q4TZX6yERl6cdDEWIPWXqtLQKVh75qsOM,1827
81
- solax_py_library-1.0.0.2601.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
82
- solax_py_library-1.0.0.2601.dist-info/RECORD,,
82
+ solax_py_library-1.0.0.2901.dist-info/METADATA,sha256=o28wtYRXED7pZtI7DX-wNJUdvCCyXnOK4btb4JVKiUc,1827
83
+ solax_py_library-1.0.0.2901.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
84
+ solax_py_library-1.0.0.2901.dist-info/RECORD,,