solax-py-library 1.0.0.24__py3-none-any.whl → 1.0.0.26__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 (71) hide show
  1. solax_py_library/__init__.py +1 -1
  2. solax_py_library/device/constant/cabinet.py +2 -0
  3. solax_py_library/device/constant/inverter_model_info.py +312 -312
  4. solax_py_library/device/core/interver/__init__.py +36 -36
  5. solax_py_library/device/core/interver/base.py +215 -215
  6. solax_py_library/device/types/alarm.py +16 -0
  7. solax_py_library/device/types/inverter_config.py +41 -41
  8. solax_py_library/device/types/modbus_point.py +30 -30
  9. solax_py_library/exception.py +10 -10
  10. solax_py_library/smart_scene/__init__.py +0 -0
  11. solax_py_library/smart_scene/constant/__init__.py +0 -0
  12. solax_py_library/smart_scene/constant/message_entry.py +179 -0
  13. solax_py_library/smart_scene/core/__init__.py +0 -0
  14. solax_py_library/smart_scene/core/action/__init__.py +0 -0
  15. solax_py_library/smart_scene/core/action/base.py +10 -0
  16. solax_py_library/smart_scene/core/action/ems_action.py +6 -0
  17. solax_py_library/smart_scene/core/action/system_action.py +6 -0
  18. solax_py_library/smart_scene/core/condition/__init__.py +17 -0
  19. solax_py_library/smart_scene/core/condition/base.py +17 -0
  20. solax_py_library/smart_scene/core/condition/cabinet_condition.py +44 -0
  21. solax_py_library/smart_scene/core/condition/date_condition.py +23 -0
  22. solax_py_library/smart_scene/core/condition/price_condition.py +110 -0
  23. solax_py_library/smart_scene/core/condition/system_condition.py +35 -0
  24. solax_py_library/smart_scene/core/condition/weather_condition.py +61 -0
  25. solax_py_library/smart_scene/core/service/__init__.py +3 -0
  26. solax_py_library/smart_scene/core/service/runner.py +156 -0
  27. solax_py_library/smart_scene/exceptions/__init__.py +7 -0
  28. solax_py_library/smart_scene/exceptions/price.py +5 -0
  29. solax_py_library/smart_scene/exceptions/smart_scene.py +82 -0
  30. solax_py_library/smart_scene/exceptions/weather.py +5 -0
  31. solax_py_library/smart_scene/types/__init__.py +0 -0
  32. solax_py_library/smart_scene/types/action.py +164 -0
  33. solax_py_library/smart_scene/types/condition.py +299 -0
  34. solax_py_library/smart_scene/types/smart_scene_content.py +173 -0
  35. solax_py_library/snap_shot/__init__.py +3 -3
  36. solax_py_library/snap_shot/constant/__init__.py +5 -5
  37. solax_py_library/snap_shot/constant/crc_table.py +258 -258
  38. solax_py_library/snap_shot/core/__init__.py +9 -9
  39. solax_py_library/snap_shot/core/base_modbus.py +14 -14
  40. solax_py_library/snap_shot/exceptions/__init__.py +3 -3
  41. solax_py_library/snap_shot/exceptions/snap_shot.py +9 -9
  42. solax_py_library/snap_shot/types/__init__.py +15 -15
  43. solax_py_library/snap_shot/types/address.py +39 -39
  44. solax_py_library/test/__init__.py +0 -0
  45. solax_py_library/test/test_smart_scene/__init__.py +0 -0
  46. solax_py_library/test/test_smart_scene/test_condition.py +11 -0
  47. solax_py_library/test/test_utils/__init__.py +0 -0
  48. solax_py_library/test/test_utils/test_cloud_client.py +14 -0
  49. solax_py_library/upload/__init__.py +3 -3
  50. solax_py_library/upload/api/__init__.py +3 -3
  51. solax_py_library/upload/api/service.py +24 -24
  52. solax_py_library/upload/core/__init__.py +3 -3
  53. solax_py_library/upload/core/data_adapter/__init__.py +5 -5
  54. solax_py_library/upload/core/data_adapter/base.py +9 -9
  55. solax_py_library/upload/core/data_adapter/csv.py +26 -26
  56. solax_py_library/upload/core/upload_service/__init__.py +15 -15
  57. solax_py_library/upload/core/upload_service/base.py +43 -43
  58. solax_py_library/upload/exceptions/__init__.py +8 -8
  59. solax_py_library/upload/exceptions/upload_error.py +21 -21
  60. solax_py_library/upload/test/test_ftp.py +113 -113
  61. solax_py_library/upload/types/__init__.py +11 -11
  62. solax_py_library/upload/types/client.py +19 -19
  63. solax_py_library/upload/types/ftp.py +37 -37
  64. solax_py_library/utils/cloud_client.py +210 -0
  65. solax_py_library/utils/common.py +38 -38
  66. solax_py_library/utils/struct_util.py +42 -30
  67. solax_py_library/utils/time_util.py +38 -0
  68. {solax_py_library-1.0.0.24.dist-info → solax_py_library-1.0.0.26.dist-info}/METADATA +2 -1
  69. solax_py_library-1.0.0.26.dist-info/RECORD +80 -0
  70. solax_py_library-1.0.0.24.dist-info/RECORD +0 -46
  71. {solax_py_library-1.0.0.24.dist-info → solax_py_library-1.0.0.26.dist-info}/WHEEL +0 -0
@@ -1,10 +1,10 @@
1
- class SolaxBaseError(Exception):
2
- code = 0x1000
3
- message = "upload error"
4
-
5
- def __init__(self, *args, message=None):
6
- super().__init__(*args)
7
- self.message = message or self.message
8
-
9
- def __str__(self):
10
- return self.message
1
+ class SolaxBaseError(Exception):
2
+ code = 0x1000
3
+ message = "upload error"
4
+
5
+ def __init__(self, *args, message=None):
6
+ super().__init__(*args)
7
+ self.message = message or self.message
8
+
9
+ def __str__(self):
10
+ return self.message
File without changes
File without changes
@@ -0,0 +1,179 @@
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": {"zh_CN": "IF条件", "en_US": "IF"},
19
+ "THEN": {"zh_CN": "THEN动作", "en_US": "THEN"},
20
+ "date": {"zh_CN": "日期: \n\t", "en_US": "Date: \n\t"},
21
+ "time": {"zh_CN": "时间", "en_US": "Time"},
22
+ "103": {"zh_CN": "仅一次", "en_US": "Once"},
23
+ "104": {"zh_CN": "每天", "en_US": "Everyday"},
24
+ "105": {"zh_CN": "工作日", "en_US": "Weekdays"},
25
+ "106": {"zh_CN": "周末", "en_US": "Weekends"},
26
+ "1": {"zh_CN": "周一", "en_US": "Mon"},
27
+ "2": {"zh_CN": "周二", "en_US": "Tues"},
28
+ "3": {"zh_CN": "周三", "en_US": "Wed"},
29
+ "4": {"zh_CN": "周四", "en_US": "Thur"},
30
+ "5": {"zh_CN": "周五", "en_US": "Fri"},
31
+ "6": {"zh_CN": "周六", "en_US": "Sat"},
32
+ "7": {"zh_CN": "周日", "en_US": "Sun"},
33
+ "weather": {"zh_CN": "天气: \n\t", "en_US": "Weather: \n\t"},
34
+ "irradiance": {
35
+ "zh_CN": "太阳辐照度 {} {}W/m² 且一天内累计有 {} 小时大于200W/m²",
36
+ "en_US": "The solar irradiance {} {}W/m², and totally there are {} hours in a day with a solar irradiance greater than 200W/m²",
37
+ },
38
+ "temperature": {"zh_CN": "温度 {} {} ℃", "en_US": "Temperature {} {} ℃"},
39
+ "humidity": {"zh_CN": "湿度 {} {} %RH", "en_US": "Humidity {} {} %RH"},
40
+ "wind": {"zh_CN": "风速 {} {} m/s", "en_US": "Wind speed {} {} m/s"},
41
+ "barometricPressure": {
42
+ "zh_CN": "气压 {} {} hPa",
43
+ "en_US": "Air pressure {} {} hPa",
44
+ },
45
+ "rain": {"zh_CN": "{} 下雨", "en_US": "It {} rain"},
46
+ "108": {"zh_CN": "会", "en_US": "will"},
47
+ "109": {"zh_CN": "不会", "en_US": "won''t"},
48
+ "forcastRain": {
49
+ "zh_CN": "未来 {} 小时会下雨",
50
+ "en_US": "It will rain in the next {} hours",
51
+ },
52
+ "100": {"zh_CN": "大于", "en_US": "is greater than"},
53
+ "101": {"zh_CN": "小于", "en_US": "is less than"},
54
+ "102": {"zh_CN": "等于", "en_US": "is equal to"},
55
+ "electricityPrice": {"zh_CN": "电价: \n\t", "en_US": "Electricity price: \n\t"},
56
+ "buyingPrice": {"zh_CN": "买电电价\n\t", "en_US": "Import price\n\t"},
57
+ "sellingPrice": {"zh_CN": "卖电电价\n\t", "en_US": "Export price\n\t"},
58
+ "price": {"zh_CN": "电价 {} {}{}", "en_US": "Electricity price {} {}{}"},
59
+ "lowerPrice": {
60
+ "zh_CN": "比最高的电价低 {}{}",
61
+ "en_US": "Lower than the highest electricity price by {}{} ",
62
+ },
63
+ "higherPrice": {
64
+ "zh_CN": "比最低的电价高 {}{}",
65
+ "en_US": "Higher than the lowest electricity price by {}{} ",
66
+ },
67
+ "expensiveHours": {
68
+ "zh_CN": "在 {} 到 {} 期间,电价最高的 {}小时",
69
+ "en_US": "During the period from {} to {}, the {}h with the highest electricity price",
70
+ },
71
+ "cheapestHours": {
72
+ "zh_CN": "在 {} 到 {} 期间,电价最低的 {} 小时",
73
+ "en_US": "During the period from {} to {}, the {}h with the lowest electricity price",
74
+ },
75
+ "system": {"zh_CN": "系统动作\n\t", "en_US": "System\n\t"},
76
+ "systemSwitch": {"zh_CN": "系统开关 {}", "en_US": "System {}"},
77
+ "on": {"zh_CN": "开", "en_US": "ON"},
78
+ "off": {"zh_CN": "关", "en_US": "OFF"},
79
+ "exportControl": {
80
+ "zh_CN": "馈网控制 {}, {}, 设置值为 {}{}",
81
+ "en_US": "Export_control {}, the mode is {}, the value is {}{}",
82
+ },
83
+ "exportControlOff": {"zh_CN": "馈网控制 关", "en_US": "Export_control off"},
84
+ "total": {"zh_CN": "总和方式", "en_US": "Total"},
85
+ "per phase": {"zh_CN": "分相模式", "en_US": "Per phase"},
86
+ "importControl_AELIO": {
87
+ "zh_CN": "需量控制 {}, 设置值为 {} kW",
88
+ "en_US": "Import_control {}, the value is {} kW",
89
+ },
90
+ "importControl": {
91
+ "zh_CN": "需量控制 {}, 模式: {}, 设置值为 {} kW",
92
+ "en_US": "Import_control {}, Control mode: {}, the value is {} kW",
93
+ },
94
+ "importControl_standby": {
95
+ "zh_CN": "降低储能充电功率,直到待机",
96
+ "en_US": "Reduce battery charge power until standby",
97
+ },
98
+ "importControl_discharge": {
99
+ "zh_CN": "降低储能充电功率,必要时储能放电",
100
+ "en_US": "Reduce battery charge power and discharge battery if necessary",
101
+ },
102
+ "importControlOff": {"zh_CN": "需量控制 关", "en_US": "Import_control off"},
103
+ "workMode": {"zh_CN": "工作模式为 {}", "en_US": "Work_mode is {}"},
104
+ "Self-use": {"zh_CN": "自发自用", "en_US": "Self-use"},
105
+ "Feedin priority": {"zh_CN": "并网优先", "en_US": "Feedin priority"},
106
+ "Back up mode": {"zh_CN": "备用模式", "en_US": "Back up mode"},
107
+ "Manual mode": {"zh_CN": "手动模式 - {}", "en_US": "Manual mode - {}"},
108
+ "Forced charging": {
109
+ "zh_CN": "以{}kW的功率充电至{}%",
110
+ "en_US": "Charge at a power of {} kW until it reaches {}%",
111
+ },
112
+ "Forced discharging": {
113
+ "zh_CN": "以{}kW的功率放电至{}%",
114
+ "en_US": "Discharge at a power of {} kW until it reaches {}%",
115
+ },
116
+ "Stop charging and discharging": {
117
+ "zh_CN": "停止充放电",
118
+ "en_US": "Stop charging and discharging",
119
+ },
120
+ "Peak Shaving": {"zh_CN": "削峰填谷", "en_US": "Peak Shaving"},
121
+ "VPP": {"zh_CN": "VPP", "en_US": "VPP"},
122
+ "Power Control Mode": {
123
+ "zh_CN": "有功功率目标为 {}kW,无功功率目标为 {}kVar",
124
+ "en_US": "Active power target is {}kW. Reactive power target is {}kVar",
125
+ },
126
+ "Electric Quantity Target Control Mode": {
127
+ "zh_CN": "电能目标 {}kWh, 充放电功率目标 {}kW",
128
+ "en_US": "Energy target is {}kWh, Charge or Discharge power target is {}kW",
129
+ },
130
+ "SOC Target Control Mode": {
131
+ "zh_CN": "目标SOC {}%, 充放电功率目标 {}kW",
132
+ "en_US": "target SOC is {}%, Charge or Discharge power target is {}kW",
133
+ },
134
+ "Push Power - Positive/Negative Mode": {
135
+ "zh_CN": "电池功率目标 {}kW",
136
+ "en_US": "Battery power target is {}kW",
137
+ },
138
+ "Push Power - Zero Mode": {
139
+ "zh_CN": "电池不充放",
140
+ "en_US": "Battery not charging or discharging",
141
+ },
142
+ "Self-Consume - Charge/Discharge Mode": {
143
+ "zh_CN": "自发自用,电池仅从PV充电",
144
+ "en_US": "Self-use. The battery can be charged from PV only",
145
+ },
146
+ "Self-Consume - Charge Only Mode": {
147
+ "zh_CN": "自发自用,电池仅从PV充电并且不可放电",
148
+ "en_US": "Self-use. The battery can be charged from PV only, and battery discharge is not allowed",
149
+ },
150
+ "PV&BAT Individual Setting – Duration Mode": {
151
+ "zh_CN": "光伏功率目标 {}kW, 电池功率目标 {}kW",
152
+ "en_US": "PV power target is {}kW. Battery power target is {}kW",
153
+ },
154
+ "PV&BAT Individual Setting – Target SOC Mode": {
155
+ "zh_CN": "光伏功率目标 {}kW, 电池功率目标 {}kW, 目标SOC {}%",
156
+ "en_US": "PV power target is {}kW. Battery power target is {}kW. target SOC is {}%",
157
+ },
158
+ "DoControl": {"zh_CN": "DO{}: {};", "en_US": "DO{}: {};"},
159
+ "duration": {"zh_CN": "持续: {}秒", "en_US": "last: {} seconds"},
160
+ "systemSoc": {"zh_CN": "系统soc {} {}%", "en_US": "system soc {} {}%"},
161
+ "systemImportPower": {
162
+ "zh_CN": "电价买电功率 {} {}KW",
163
+ "en_US": "system soc {} {}KW",
164
+ },
165
+ "systemExportPower": {
166
+ "zh_CN": "电价馈电功率 {} {}KW",
167
+ "en_US": "system soc {} {}KW",
168
+ },
169
+ "cabinetSoc": {"zh_CN": "机柜soc {} {}%", "en_US": "cabinet soc {} {}%"},
170
+ "EMERGENCY": {"zh_CN": "紧急告警", "en_US": "Emergency alarm"},
171
+ "TIPS": {"zh_CN": "状态提醒", "en_US": "State Tips"},
172
+ "NORMAL": {"zh_CN": "普通告警", "en_US": "Normal alarm"},
173
+ "cabinetAlarm": {"zh_CN": "机柜发生{}", "en_US": "cabinet occurs {}"},
174
+ "OR": {"zh_CN": "满足任一条件", "en_US": "Meet any of the conditions"},
175
+ "AND": {"zh_CN": "满足所有条件", "en_US": "Meet all conditions"},
176
+ "tips_alarm": {"zh_CN": "状态提醒", "en_US": "Alarm tips"},
177
+ "normal_alarm": {"zh_CN": "普通告警", "en_US": "Normal alarm"},
178
+ "emergency_alarm": {"zh_CN": "紧急告警", "en_US": "Emergency alarm"},
179
+ }
File without changes
File without changes
@@ -0,0 +1,10 @@
1
+ class BaseAction(object):
2
+ def __init__(self, smart_scene_service, do_funcs, **kwargs):
3
+ self.smart_scene_service = smart_scene_service
4
+ self.do_func_map = do_funcs
5
+
6
+ def do_func(self, scene_id, data):
7
+ child_data = data.childData
8
+ child_type = data.childType
9
+ do_func = self.do_func_map.get(child_type)
10
+ return do_func(scene_id, child_data.data)
@@ -0,0 +1,6 @@
1
+ from solax_py_library.smart_scene.core.action.base import BaseAction
2
+ from solax_py_library.smart_scene.types.action import ActionType
3
+
4
+
5
+ class EMS1000Action(BaseAction):
6
+ action_type = ActionType.EMS1000
@@ -0,0 +1,6 @@
1
+ from solax_py_library.smart_scene.core.action.base import BaseAction
2
+ from solax_py_library.smart_scene.types.action import ActionType
3
+
4
+
5
+ class SystemAction(BaseAction):
6
+ action_type = ActionType.system
@@ -0,0 +1,17 @@
1
+ from .base import BaseCondition
2
+ from .cabinet_condition import CabinetCondition
3
+ from .date_condition import DateCondition
4
+ from .weather_condition import WeatherCondition
5
+ from .price_condition import EleSellPriceCondition, ElsBuyPriceCondition
6
+ from .system_condition import SystemCondition
7
+
8
+
9
+ __all__ = [
10
+ "BaseCondition",
11
+ "CabinetCondition",
12
+ "DateCondition",
13
+ "WeatherCondition",
14
+ "ElsBuyPriceCondition",
15
+ "EleSellPriceCondition",
16
+ "SystemCondition",
17
+ ]
@@ -0,0 +1,17 @@
1
+ class BaseCondition(object):
2
+ condition_type = None
3
+
4
+ def __init__(self, update_value_function, **kwargs):
5
+ self.value = {}
6
+ if not callable(update_value_function):
7
+ raise ValueError("update_value_function must be callable")
8
+ self.update_value_function = update_value_function
9
+
10
+ def update_value(self):
11
+ new_value = self.update_value_function()
12
+ if not isinstance(new_value, dict):
13
+ raise ValueError("update_value_function must return a dict")
14
+ self.value.update(new_value)
15
+
16
+ def meet_func(self, data, ctx):
17
+ ...
@@ -0,0 +1,44 @@
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 (
5
+ CabinetConditionItemData,
6
+ CabinetConditionType,
7
+ ConditionType,
8
+ )
9
+ from solax_py_library.device.types.alarm import AlarmLevel
10
+
11
+
12
+ class CabinetCondition(BaseCondition):
13
+ condition_type = ConditionType.cabinet
14
+
15
+ def __init__(self, update_value_function, **kwargs):
16
+ super().__init__(update_value_function, **kwargs)
17
+ self.value = defaultdict(
18
+ lambda: {
19
+ "soc": 0,
20
+ "alarm_level": {
21
+ AlarmLevel.EMERGENCY: False,
22
+ AlarmLevel.NORMAL: False,
23
+ AlarmLevel.TIPS: False,
24
+ },
25
+ }
26
+ )
27
+
28
+ def meet_func(self, data: CabinetConditionItemData, ctx):
29
+ if not self.value:
30
+ return False
31
+ cabinet = ctx["cabinet"] or []
32
+ for cabinet_sn in cabinet:
33
+ if data.childType == CabinetConditionType.cabinetSoc:
34
+ if self.value[cabinet_sn]["soc"] is None:
35
+ return False
36
+ if data.childData.function.function()(
37
+ compare_value=self.value[cabinet_sn]["soc"],
38
+ base_value=data.childData.data[0],
39
+ ):
40
+ return True
41
+ elif data.childType == CabinetConditionType.cabinetAlarm:
42
+ if self.value[cabinet_sn]["alarm_level"][data.childData.data[0]]:
43
+ return True
44
+ return False
@@ -0,0 +1,23 @@
1
+ from solax_py_library.smart_scene.core.condition.base import BaseCondition
2
+ from solax_py_library.smart_scene.types.condition import (
3
+ DateConditionItemData,
4
+ DateConditionType,
5
+ ConditionType,
6
+ )
7
+
8
+
9
+ class DateCondition(BaseCondition):
10
+ condition_type = ConditionType.date
11
+
12
+ def __init__(self, update_value_function, **kwargs):
13
+ super().__init__(update_value_function, **kwargs)
14
+
15
+ def meet_func(self, data: DateConditionItemData, ctx):
16
+ if data.childType == DateConditionType.time:
17
+ date = data.childData.data[0]
18
+ hour, minute = date.split(":")
19
+ if int(hour) == self.value.get("hour") and int(minute) == self.value.get(
20
+ "minute"
21
+ ):
22
+ return True
23
+ return False
@@ -0,0 +1,110 @@
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 (
5
+ PriceConditionItemData,
6
+ PriceConditionType,
7
+ SmartSceneUnit,
8
+ ConditionFunc,
9
+ ConditionType,
10
+ )
11
+ from solax_py_library.utils.time_util import (
12
+ trans_str_time_to_index,
13
+ get_highest_or_lowest_value,
14
+ )
15
+
16
+
17
+ class ElePriceCondition(BaseCondition):
18
+ def __init__(self, update_value_function, **kwargs):
19
+ super().__init__(update_value_function, **kwargs)
20
+ self.buy = None
21
+
22
+ def meet_func_price(self, function_value: ConditionFunc, data_value, index) -> bool:
23
+ """电价条件的判定"""
24
+ price = self.value["price"]
25
+ if index < 0 or index > len(price):
26
+ return False
27
+ if price[index] is None:
28
+ return False
29
+ return function_value.function()(price[index], data_value[0])
30
+
31
+ def meet_func_highest_price(self, data_value, index) -> bool:
32
+ value, unit = data_value
33
+ price = self.value["price"]
34
+ if None in price[0:96]:
35
+ return False
36
+ if unit == SmartSceneUnit.NUM: # 比最高电价低X元
37
+ base = max(price[0:96]) - value
38
+ else: # 比最高电价低X%
39
+ base = round(max(price[0:96]) * (1 - value / 100), 4)
40
+ if self.value[index] <= base:
41
+ return True
42
+ else:
43
+ return False
44
+
45
+ def meet_func_lowest_price(self, data_value, index) -> bool:
46
+ value, unit = data_value
47
+ price = self.value["price"]
48
+ if None in price[0:96]:
49
+ return False
50
+ if unit == SmartSceneUnit.NUM: # 比最低电价高X元
51
+ base = value - min(price[0:96])
52
+ else: # 比最低电价高X%
53
+ base = round(min(price[0:96]) * (1 + value / 100), 4)
54
+ if price[index] >= base:
55
+ return True
56
+ else:
57
+ return False
58
+
59
+ def meet_func_highest_or_lowest_hours(self, data_value, index, reverse) -> bool:
60
+ sort_index, start_index = get_highest_or_lowest_value(
61
+ data_value[0],
62
+ data_value[1],
63
+ data_value[2],
64
+ self.value["price"],
65
+ reverse=reverse,
66
+ )
67
+ if sort_index and index - start_index in sort_index:
68
+ return True
69
+ return False
70
+
71
+ def meet_func(self, data: PriceConditionItemData, ctx):
72
+ if not self.value or not self.value.get("price"):
73
+ # 未获取到价格数据,直接返回
74
+ return False
75
+ child_data = data.childData
76
+ child_type = data.childType
77
+ data_value = child_data.data
78
+ now_time = datetime.strftime(datetime.now(), "%H:%M")
79
+ index = trans_str_time_to_index(now_time)
80
+ if child_type == PriceConditionType.price:
81
+ return self.meet_func_price(child_data.function, data_value, index)
82
+ elif child_type == PriceConditionType.lowerPrice:
83
+ return self.meet_func_highest_price(data_value, index)
84
+ elif child_type == PriceConditionType.higherPrice:
85
+ return self.meet_func_lowest_price(data_value, index)
86
+ elif child_type == PriceConditionType.expensiveHours:
87
+ return self.meet_func_highest_or_lowest_hours(
88
+ data_value, index, reverse=True
89
+ )
90
+ elif child_type == PriceConditionType.cheapestHours:
91
+ return self.meet_func_highest_or_lowest_hours(
92
+ data_value, index, reverse=False
93
+ )
94
+ return False
95
+
96
+
97
+ class EleSellPriceCondition(ElePriceCondition):
98
+ condition_type = ConditionType.sellingPrice
99
+
100
+ def __init__(self, update_value_function, **kwargs):
101
+ super().__init__(update_value_function, **kwargs)
102
+ self.buy = False
103
+
104
+
105
+ class ElsBuyPriceCondition(ElePriceCondition):
106
+ condition_type = ConditionType.buyingPrice
107
+
108
+ def __init__(self, update_value_function, **kwargs):
109
+ super().__init__(update_value_function, **kwargs)
110
+ self.buy = True
@@ -0,0 +1,35 @@
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
+ ConditionType,
6
+ )
7
+
8
+
9
+ class SystemCondition(BaseCondition):
10
+ condition_type = ConditionType.systemCondition
11
+
12
+ def __init__(self, update_value_function, **kwargs):
13
+ super().__init__(update_value_function, **kwargs)
14
+
15
+ def meet_func(self, data: SystemConditionItemData, ctx):
16
+ if not self.value:
17
+ return False
18
+ child_data = data.childData
19
+ function_value = child_data.function
20
+ compare_value = None
21
+ if data.childType == SystemConditionType.systemExportPower:
22
+ compare_value = self.value.get("grid_active_power")
23
+ if compare_value < 0:
24
+ return False
25
+ elif data.childType == SystemConditionType.systemImportPower:
26
+ compare_value = self.value.get("grid_active_power")
27
+ if compare_value > 0:
28
+ return False
29
+ elif data.childType == SystemConditionType.systemSoc:
30
+ compare_value = self.value.get("system_soc")
31
+ if compare_value is None:
32
+ return False
33
+ return function_value.function()(
34
+ compare_value=abs(compare_value), base_value=child_data.data[0]
35
+ )
@@ -0,0 +1,61 @@
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
+ ConditionType,
6
+ )
7
+ from solax_py_library.utils.time_util import get_rounded_times
8
+
9
+
10
+ class WeatherCondition(BaseCondition):
11
+ condition_type = ConditionType.weather
12
+
13
+ def __init__(self, update_value_function, **kwargs):
14
+ super().__init__(update_value_function, **kwargs)
15
+
16
+ def meet_func(self, data: WeatherConditionItemData, ctx):
17
+ if not self.value:
18
+ return False
19
+ child_data = data.childData
20
+ child_type = data.childType
21
+ function_value = child_data.function
22
+ data_value = child_data.data
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
28
+ index = self.value["timeList"].index(time_now)
29
+ if child_type == WeatherConditionType.irradiance:
30
+ return self.meet_func_irradiance(function_value, data_value, index)
31
+ elif child_type == WeatherConditionType.temperature:
32
+ return function_value.function()(
33
+ self.value[child_type]["valueList"][index],
34
+ data_value[0],
35
+ )
36
+ return False
37
+
38
+ def meet_func_irradiance(self, function_value, data_value, index):
39
+ """太阳辐照度判断"""
40
+ irradiance = data_value[0]
41
+ duration = data_value[1]
42
+ meet_num = 0
43
+ meet_flag = False
44
+ if duration == 0:
45
+ meet_flag = True
46
+ elif duration > 24:
47
+ pass
48
+ else:
49
+ # 1. 保证累计duration个小时大于200,
50
+ for value in self.value["irradiance"]["valueList"]:
51
+ if value > 200:
52
+ meet_num += 1
53
+ if meet_num >= duration * 4:
54
+ meet_flag = True
55
+ break
56
+ if not meet_flag:
57
+ return False
58
+ # 2. 再判断当前太阳辐照度
59
+ return function_value.function()(
60
+ self.value["irradiance"]["valueList"][index], irradiance
61
+ )
@@ -0,0 +1,3 @@
1
+ from .runner import SmartSceneRunner
2
+
3
+ __all__ = ["SmartSceneRunner"]