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.
- solax_py_library/__init__.py +1 -1
- solax_py_library/device/constant/cabinet.py +2 -0
- solax_py_library/device/constant/inverter_model_info.py +312 -312
- solax_py_library/device/core/interver/__init__.py +36 -36
- solax_py_library/device/core/interver/base.py +215 -215
- solax_py_library/device/types/alarm.py +16 -0
- solax_py_library/device/types/inverter_config.py +41 -41
- solax_py_library/device/types/modbus_point.py +30 -30
- solax_py_library/exception.py +10 -10
- solax_py_library/smart_scene/__init__.py +0 -0
- solax_py_library/smart_scene/constant/__init__.py +0 -0
- solax_py_library/smart_scene/constant/message_entry.py +179 -0
- solax_py_library/smart_scene/core/__init__.py +0 -0
- solax_py_library/smart_scene/core/action/__init__.py +0 -0
- solax_py_library/smart_scene/core/action/base.py +10 -0
- solax_py_library/smart_scene/core/action/ems_action.py +6 -0
- solax_py_library/smart_scene/core/action/system_action.py +6 -0
- solax_py_library/smart_scene/core/condition/__init__.py +17 -0
- solax_py_library/smart_scene/core/condition/base.py +17 -0
- solax_py_library/smart_scene/core/condition/cabinet_condition.py +44 -0
- solax_py_library/smart_scene/core/condition/date_condition.py +23 -0
- solax_py_library/smart_scene/core/condition/price_condition.py +110 -0
- solax_py_library/smart_scene/core/condition/system_condition.py +35 -0
- solax_py_library/smart_scene/core/condition/weather_condition.py +61 -0
- solax_py_library/smart_scene/core/service/__init__.py +3 -0
- solax_py_library/smart_scene/core/service/runner.py +156 -0
- solax_py_library/smart_scene/exceptions/__init__.py +7 -0
- solax_py_library/smart_scene/exceptions/price.py +5 -0
- solax_py_library/smart_scene/exceptions/smart_scene.py +82 -0
- solax_py_library/smart_scene/exceptions/weather.py +5 -0
- solax_py_library/smart_scene/types/__init__.py +0 -0
- solax_py_library/smart_scene/types/action.py +164 -0
- solax_py_library/smart_scene/types/condition.py +299 -0
- solax_py_library/smart_scene/types/smart_scene_content.py +173 -0
- solax_py_library/snap_shot/__init__.py +3 -3
- solax_py_library/snap_shot/constant/__init__.py +5 -5
- solax_py_library/snap_shot/constant/crc_table.py +258 -258
- solax_py_library/snap_shot/core/__init__.py +9 -9
- solax_py_library/snap_shot/core/base_modbus.py +14 -14
- solax_py_library/snap_shot/exceptions/__init__.py +3 -3
- solax_py_library/snap_shot/exceptions/snap_shot.py +9 -9
- solax_py_library/snap_shot/types/__init__.py +15 -15
- solax_py_library/snap_shot/types/address.py +39 -39
- solax_py_library/test/__init__.py +0 -0
- solax_py_library/test/test_smart_scene/__init__.py +0 -0
- solax_py_library/test/test_smart_scene/test_condition.py +11 -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/upload/__init__.py +3 -3
- solax_py_library/upload/api/__init__.py +3 -3
- solax_py_library/upload/api/service.py +24 -24
- solax_py_library/upload/core/__init__.py +3 -3
- solax_py_library/upload/core/data_adapter/__init__.py +5 -5
- solax_py_library/upload/core/data_adapter/base.py +9 -9
- solax_py_library/upload/core/data_adapter/csv.py +26 -26
- solax_py_library/upload/core/upload_service/__init__.py +15 -15
- solax_py_library/upload/core/upload_service/base.py +43 -43
- solax_py_library/upload/exceptions/__init__.py +8 -8
- solax_py_library/upload/exceptions/upload_error.py +21 -21
- solax_py_library/upload/test/test_ftp.py +113 -113
- solax_py_library/upload/types/__init__.py +11 -11
- solax_py_library/upload/types/client.py +19 -19
- solax_py_library/upload/types/ftp.py +37 -37
- solax_py_library/utils/cloud_client.py +210 -0
- solax_py_library/utils/common.py +38 -38
- solax_py_library/utils/struct_util.py +42 -30
- solax_py_library/utils/time_util.py +38 -0
- {solax_py_library-1.0.0.24.dist-info → solax_py_library-1.0.0.26.dist-info}/METADATA +2 -1
- solax_py_library-1.0.0.26.dist-info/RECORD +80 -0
- solax_py_library-1.0.0.24.dist-info/RECORD +0 -46
- {solax_py_library-1.0.0.24.dist-info → solax_py_library-1.0.0.26.dist-info}/WHEEL +0 -0
@@ -1,37 +1,37 @@
|
|
1
|
-
import os
|
2
|
-
from enum import IntEnum
|
3
|
-
from typing import Any, Optional
|
4
|
-
|
5
|
-
from pydantic import BaseModel
|
6
|
-
|
7
|
-
|
8
|
-
class FTPFileType(IntEnum):
|
9
|
-
CSV = 1
|
10
|
-
|
11
|
-
@classmethod
|
12
|
-
def get_file_suffix(cls, value):
|
13
|
-
return {
|
14
|
-
FTPFileType.CSV: ".csv",
|
15
|
-
}.get(value)
|
16
|
-
|
17
|
-
|
18
|
-
class FTPData(BaseModel):
|
19
|
-
file_type: FTPFileType
|
20
|
-
file_name: str
|
21
|
-
data: Any
|
22
|
-
|
23
|
-
def build_full_path(self, remote_path) -> str:
|
24
|
-
return os.path.join(remote_path, self.file_name)
|
25
|
-
|
26
|
-
|
27
|
-
class FTPServiceConfig(BaseModel):
|
28
|
-
host: str
|
29
|
-
port: int
|
30
|
-
user: Optional[str]
|
31
|
-
password: Optional[str]
|
32
|
-
remote_path: str
|
33
|
-
|
34
|
-
|
35
|
-
class FTPParsedData(BaseModel):
|
36
|
-
file_name: str
|
37
|
-
file_path: str
|
1
|
+
import os
|
2
|
+
from enum import IntEnum
|
3
|
+
from typing import Any, Optional
|
4
|
+
|
5
|
+
from pydantic import BaseModel
|
6
|
+
|
7
|
+
|
8
|
+
class FTPFileType(IntEnum):
|
9
|
+
CSV = 1
|
10
|
+
|
11
|
+
@classmethod
|
12
|
+
def get_file_suffix(cls, value):
|
13
|
+
return {
|
14
|
+
FTPFileType.CSV: ".csv",
|
15
|
+
}.get(value)
|
16
|
+
|
17
|
+
|
18
|
+
class FTPData(BaseModel):
|
19
|
+
file_type: FTPFileType
|
20
|
+
file_name: str
|
21
|
+
data: Any
|
22
|
+
|
23
|
+
def build_full_path(self, remote_path) -> str:
|
24
|
+
return os.path.join(remote_path, self.file_name)
|
25
|
+
|
26
|
+
|
27
|
+
class FTPServiceConfig(BaseModel):
|
28
|
+
host: str
|
29
|
+
port: int
|
30
|
+
user: Optional[str]
|
31
|
+
password: Optional[str]
|
32
|
+
remote_path: str
|
33
|
+
|
34
|
+
|
35
|
+
class FTPParsedData(BaseModel):
|
36
|
+
file_name: str
|
37
|
+
file_path: str
|
@@ -0,0 +1,210 @@
|
|
1
|
+
import json
|
2
|
+
import traceback
|
3
|
+
from datetime import datetime
|
4
|
+
|
5
|
+
import requests
|
6
|
+
|
7
|
+
from solax_py_library.utils.time_util import trans_str_time_to_index
|
8
|
+
|
9
|
+
|
10
|
+
class CloudClient:
|
11
|
+
def __init__(self, base_url):
|
12
|
+
self.base_url = base_url
|
13
|
+
|
14
|
+
def get_token(self, ems_sn, sn_secret):
|
15
|
+
token_url = self.base_url + "/device/token/getByRegistrationSn"
|
16
|
+
try:
|
17
|
+
response = requests.post(
|
18
|
+
token_url,
|
19
|
+
json={
|
20
|
+
"registrationSn": ems_sn,
|
21
|
+
"snSecret": sn_secret,
|
22
|
+
},
|
23
|
+
timeout=5,
|
24
|
+
)
|
25
|
+
if response.content:
|
26
|
+
response_data = json.loads(response.content)
|
27
|
+
print(f"获取token结果 {response_data}")
|
28
|
+
if response_data.get("code") == 0 and response_data.get("result"):
|
29
|
+
token = response_data["result"]
|
30
|
+
return token
|
31
|
+
except Exception as e:
|
32
|
+
print(f"访问token接口失败: {str(e)}")
|
33
|
+
|
34
|
+
def get_weather_data_from_cloud(self, ems_sn, token):
|
35
|
+
"""获取未来24小时天气数据"""
|
36
|
+
try:
|
37
|
+
weather_url = self.base_url + "/ess/web/v1/powerStation/station/solcast/get"
|
38
|
+
headers = {"token": token, "Content-Type": "application/json"}
|
39
|
+
post_dict = {"registerNo": ems_sn, "day": 1}
|
40
|
+
response = requests.post(
|
41
|
+
url=weather_url, data=json.dumps(post_dict), headers=headers, timeout=5
|
42
|
+
)
|
43
|
+
# 访问失败或获取数据失败,则重复插入最后一条数据
|
44
|
+
if response.status_code != 200:
|
45
|
+
print(f"获取天气数据失败 状态码 {response.status_code}")
|
46
|
+
return False
|
47
|
+
response_data = response.json()
|
48
|
+
if response_data.get("result") is None:
|
49
|
+
print(f"获取天气数据失败 返回数据 {response_data}")
|
50
|
+
return False
|
51
|
+
weather_info = {
|
52
|
+
"timeList": [],
|
53
|
+
"irradiance": {"valueList": []},
|
54
|
+
"temperature": {"valueList": []},
|
55
|
+
"humidity": {"valueList": []},
|
56
|
+
"wind": {"valueList": []},
|
57
|
+
"barometricPressure": {"valueList": []},
|
58
|
+
"rain": {"valueList": []},
|
59
|
+
}
|
60
|
+
for info in response_data["result"]:
|
61
|
+
weather_info["timeList"].append(info["localTime"])
|
62
|
+
weather_info["irradiance"]["valueList"].append(float(info["ghi"]))
|
63
|
+
weather_info["temperature"]["valueList"].append(float(info["air_temp"]))
|
64
|
+
weather_info["humidity"]["valueList"].append(
|
65
|
+
float(info["relative_humidity"])
|
66
|
+
)
|
67
|
+
weather_info["wind"]["valueList"].append(float(info["wind_speed_10m"]))
|
68
|
+
weather_info["barometricPressure"]["valueList"].append(
|
69
|
+
float(info.get("surface_pressure", 0))
|
70
|
+
)
|
71
|
+
rain = 1 if float(info["precipitation_rate"]) > 2.5 else 0
|
72
|
+
weather_info["rain"]["valueList"].append(rain)
|
73
|
+
data_length = len(weather_info["irradiance"]["valueList"])
|
74
|
+
if weather_info["timeList"] == []:
|
75
|
+
weather_info = {}
|
76
|
+
else:
|
77
|
+
weather_info["irradiance"]["maxValue"] = max(
|
78
|
+
weather_info["irradiance"]["valueList"]
|
79
|
+
)
|
80
|
+
weather_info["irradiance"]["avgValue"] = round(
|
81
|
+
sum(weather_info["irradiance"]["valueList"]) / data_length, 3
|
82
|
+
)
|
83
|
+
weather_info["irradiance"]["minValue"] = min(
|
84
|
+
weather_info["irradiance"]["valueList"]
|
85
|
+
)
|
86
|
+
|
87
|
+
weather_info["temperature"]["maxValue"] = max(
|
88
|
+
weather_info["temperature"]["valueList"]
|
89
|
+
)
|
90
|
+
weather_info["temperature"]["avgValue"] = round(
|
91
|
+
sum(weather_info["temperature"]["valueList"]) / data_length, 3
|
92
|
+
)
|
93
|
+
weather_info["temperature"]["minValue"] = min(
|
94
|
+
weather_info["temperature"]["valueList"]
|
95
|
+
)
|
96
|
+
|
97
|
+
weather_info["humidity"]["maxValue"] = max(
|
98
|
+
weather_info["humidity"]["valueList"]
|
99
|
+
)
|
100
|
+
weather_info["humidity"]["avgValue"] = round(
|
101
|
+
sum(weather_info["humidity"]["valueList"]) / data_length, 3
|
102
|
+
)
|
103
|
+
weather_info["humidity"]["minValue"] = min(
|
104
|
+
weather_info["humidity"]["valueList"]
|
105
|
+
)
|
106
|
+
|
107
|
+
weather_info["wind"]["maxValue"] = max(
|
108
|
+
weather_info["wind"]["valueList"]
|
109
|
+
)
|
110
|
+
weather_info["wind"]["avgValue"] = round(
|
111
|
+
sum(weather_info["wind"]["valueList"]) / data_length, 3
|
112
|
+
)
|
113
|
+
weather_info["wind"]["minValue"] = min(
|
114
|
+
weather_info["wind"]["valueList"]
|
115
|
+
)
|
116
|
+
|
117
|
+
weather_info["barometricPressure"]["maxValue"] = max(
|
118
|
+
weather_info["barometricPressure"]["valueList"]
|
119
|
+
)
|
120
|
+
weather_info["barometricPressure"]["avgValue"] = round(
|
121
|
+
sum(weather_info["barometricPressure"]["valueList"]) / data_length,
|
122
|
+
3,
|
123
|
+
)
|
124
|
+
weather_info["barometricPressure"]["minValue"] = min(
|
125
|
+
weather_info["barometricPressure"]["valueList"]
|
126
|
+
)
|
127
|
+
|
128
|
+
weather_info["rain"]["maxValue"] = max(
|
129
|
+
weather_info["rain"]["valueList"]
|
130
|
+
)
|
131
|
+
weather_info["rain"]["minValue"] = min(
|
132
|
+
weather_info["rain"]["valueList"]
|
133
|
+
)
|
134
|
+
return weather_info
|
135
|
+
print("获取天气数据成功")
|
136
|
+
except Exception:
|
137
|
+
print(f"获取天气数据失败 异常 {traceback.format_exc()}")
|
138
|
+
return False
|
139
|
+
|
140
|
+
def get_electrovalence_data_from_cloud(self, ems_sn, token):
|
141
|
+
try:
|
142
|
+
price_url = self.base_url + "/powerStation/station/getCurrentElectrovalence"
|
143
|
+
response = requests.post(
|
144
|
+
url=price_url,
|
145
|
+
headers={"token": token, "Content-Type": "application/json"},
|
146
|
+
json={"registerNo": ems_sn},
|
147
|
+
timeout=5,
|
148
|
+
)
|
149
|
+
# 访问失败或获取数据失败,则重复插入最后一条数据
|
150
|
+
if response.status_code != 200:
|
151
|
+
print(f"获取电价数据失败 状态码 {response.status_code}")
|
152
|
+
return False
|
153
|
+
response_data = response.json()
|
154
|
+
if response_data.get("result") is None:
|
155
|
+
print(f"获取电价数据失败 返回数据 {response_data}")
|
156
|
+
return False
|
157
|
+
today = datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M:%S")
|
158
|
+
ele_price_info = {
|
159
|
+
"buy": [None] * 192,
|
160
|
+
"sell": [None] * 192,
|
161
|
+
"date": today,
|
162
|
+
}
|
163
|
+
ele_price_info["ele_unit"] = response_data["result"]["unit"]
|
164
|
+
if ele_price_info["ele_unit"] == "¥":
|
165
|
+
rate = 1
|
166
|
+
ele_price_info["ele_unit"] = "¥/kWh"
|
167
|
+
else:
|
168
|
+
rate = 100
|
169
|
+
ele_price_info["ele_unit"] = "Cents €/kWh"
|
170
|
+
for detail_info in response_data["result"]["list"]:
|
171
|
+
start_index = trans_str_time_to_index(detail_info["startTime"])
|
172
|
+
end_index = trans_str_time_to_index(detail_info["endTime"])
|
173
|
+
# 处理欧分的情况
|
174
|
+
if detail_info["buyPrice"] is not None:
|
175
|
+
buy_price = round(detail_info["buyPrice"] * rate, 5)
|
176
|
+
else:
|
177
|
+
buy_price = detail_info["buyPrice"]
|
178
|
+
if detail_info["salePrice"] is not None:
|
179
|
+
sale_price = round(detail_info["salePrice"] * rate, 5)
|
180
|
+
else:
|
181
|
+
sale_price = detail_info["salePrice"]
|
182
|
+
ele_price_info["buy"][start_index:end_index] = [buy_price] * (
|
183
|
+
end_index - start_index
|
184
|
+
)
|
185
|
+
ele_price_info["sell"][start_index:end_index] = [sale_price] * (
|
186
|
+
end_index - start_index
|
187
|
+
)
|
188
|
+
if response_data["result"].get("tomorrow") is not None:
|
189
|
+
for detail_info in response_data["result"]["tomorrow"]:
|
190
|
+
start_index = trans_str_time_to_index(detail_info["startTime"]) + 96
|
191
|
+
end_index = trans_str_time_to_index(detail_info["endTime"]) + 96
|
192
|
+
if detail_info["buyPrice"] is not None:
|
193
|
+
buy_price = round(detail_info["buyPrice"] * rate, 5)
|
194
|
+
else:
|
195
|
+
buy_price = detail_info["buyPrice"]
|
196
|
+
if detail_info["salePrice"] is not None:
|
197
|
+
sale_price = round(detail_info["salePrice"] * rate, 5)
|
198
|
+
else:
|
199
|
+
sale_price = detail_info["salePrice"]
|
200
|
+
ele_price_info["buy"][start_index:end_index] = [buy_price] * (
|
201
|
+
end_index - start_index
|
202
|
+
)
|
203
|
+
ele_price_info["sell"][start_index:end_index] = [sale_price] * (
|
204
|
+
end_index - start_index
|
205
|
+
)
|
206
|
+
print("获取电价数据成功")
|
207
|
+
return ele_price_info
|
208
|
+
except Exception:
|
209
|
+
print(f"获取电价数据失败 异常 {traceback.format_exc()}")
|
210
|
+
return False
|
solax_py_library/utils/common.py
CHANGED
@@ -1,38 +1,38 @@
|
|
1
|
-
import asyncio
|
2
|
-
from decimal import Decimal, ROUND_HALF_UP
|
3
|
-
|
4
|
-
|
5
|
-
def retry(max_attempts=3, delay=0.5, assign_exception=Exception):
|
6
|
-
def decorator(func):
|
7
|
-
async def wrapper(*args, **kwargs):
|
8
|
-
attempts = 0
|
9
|
-
while attempts < max_attempts:
|
10
|
-
try:
|
11
|
-
return await func(*args, **kwargs)
|
12
|
-
except Exception as e:
|
13
|
-
print(f"尝试 {attempts+1} 失败: {e}")
|
14
|
-
await asyncio.sleep(delay)
|
15
|
-
attempts += 1
|
16
|
-
raise assign_exception(f"操作失败 {max_attempts} 次")
|
17
|
-
|
18
|
-
return wrapper
|
19
|
-
|
20
|
-
return decorator
|
21
|
-
|
22
|
-
|
23
|
-
def round_value(value, decimal_places=0):
|
24
|
-
"""
|
25
|
-
实现四舍五入 代替round函数 遇到5向上取整
|
26
|
-
@param value: 传入数值
|
27
|
-
@param decimal_places: 保留几位小数
|
28
|
-
@return:
|
29
|
-
"""
|
30
|
-
if isinstance(value, int):
|
31
|
-
return value
|
32
|
-
else:
|
33
|
-
# 优化小数位 Decimal函数太耗时 曲线数据直接使用round函数
|
34
|
-
# rounded_value = ("{:.%df}" % decimal_places).format(value)
|
35
|
-
rounded_value = Decimal(str(value)).quantize(
|
36
|
-
Decimal("1e-" + str(decimal_places)), rounding=ROUND_HALF_UP
|
37
|
-
)
|
38
|
-
return float(rounded_value)
|
1
|
+
import asyncio
|
2
|
+
from decimal import Decimal, ROUND_HALF_UP
|
3
|
+
|
4
|
+
|
5
|
+
def retry(max_attempts=3, delay=0.5, assign_exception=Exception):
|
6
|
+
def decorator(func):
|
7
|
+
async def wrapper(*args, **kwargs):
|
8
|
+
attempts = 0
|
9
|
+
while attempts < max_attempts:
|
10
|
+
try:
|
11
|
+
return await func(*args, **kwargs)
|
12
|
+
except Exception as e:
|
13
|
+
print(f"尝试 {attempts+1} 失败: {e}")
|
14
|
+
await asyncio.sleep(delay)
|
15
|
+
attempts += 1
|
16
|
+
raise assign_exception(f"操作失败 {max_attempts} 次")
|
17
|
+
|
18
|
+
return wrapper
|
19
|
+
|
20
|
+
return decorator
|
21
|
+
|
22
|
+
|
23
|
+
def round_value(value, decimal_places=0):
|
24
|
+
"""
|
25
|
+
实现四舍五入 代替round函数 遇到5向上取整
|
26
|
+
@param value: 传入数值
|
27
|
+
@param decimal_places: 保留几位小数
|
28
|
+
@return:
|
29
|
+
"""
|
30
|
+
if isinstance(value, int):
|
31
|
+
return value
|
32
|
+
else:
|
33
|
+
# 优化小数位 Decimal函数太耗时 曲线数据直接使用round函数
|
34
|
+
# rounded_value = ("{:.%df}" % decimal_places).format(value)
|
35
|
+
rounded_value = Decimal(str(value)).quantize(
|
36
|
+
Decimal("1e-" + str(decimal_places)), rounding=ROUND_HALF_UP
|
37
|
+
)
|
38
|
+
return float(rounded_value)
|
@@ -1,30 +1,42 @@
|
|
1
|
-
import copy
|
2
|
-
import struct
|
3
|
-
from typing import List
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
"""
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
11
|
-
"""
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
1
|
+
import copy
|
2
|
+
import struct
|
3
|
+
from typing import List
|
4
|
+
|
5
|
+
format_map = {
|
6
|
+
"int8": {"format_str": "bb", "length": 1},
|
7
|
+
"uint8": {"format_str": "BB", "length": 1},
|
8
|
+
"int16": {"format_str": "h", "length": 1},
|
9
|
+
"uint16": {"format_str": "H", "length": 1},
|
10
|
+
"int32": {"format_str": "i", "length": 2},
|
11
|
+
"uint32": {"format_str": "I", "length": 2},
|
12
|
+
"int64": {"format_str": "q", "length": 4},
|
13
|
+
"uint64": {"format_str": "Q", "length": 4},
|
14
|
+
"float": {"format_str": "f", "length": 1},
|
15
|
+
}
|
16
|
+
|
17
|
+
|
18
|
+
def unpack(data: List, data_format, reversed=False):
|
19
|
+
"""
|
20
|
+
:param data: 数据字节, 入参均是由modbus读取到的list[uint16]进行转换
|
21
|
+
:param data_format: 数据格式
|
22
|
+
:param reversed: 是否翻转大小端
|
23
|
+
"""
|
24
|
+
cur_data = copy.deepcopy(data)
|
25
|
+
data_format = data_format.lower()
|
26
|
+
if data_format not in format_map:
|
27
|
+
raise Exception("暂不支持")
|
28
|
+
pack_str = ("<" if reversed else ">") + "H" * len(cur_data)
|
29
|
+
to_pack_data = struct.pack(pack_str, *cur_data)
|
30
|
+
struct_format = ("<" if reversed else ">") + format_map[data_format]["format_str"]
|
31
|
+
return struct.unpack(struct_format, to_pack_data)
|
32
|
+
|
33
|
+
|
34
|
+
def pack(value, fmt, order="big"):
|
35
|
+
"""将10进制的原始值转换为modbus协议需要的精度与类型的值"""
|
36
|
+
opt = "<" if order == "little" else ">"
|
37
|
+
if fmt not in format_map:
|
38
|
+
raise Exception("暂不支持")
|
39
|
+
value = int(value)
|
40
|
+
ret = struct.pack(f'{opt}{format_map[fmt]["format_str"]}', value)
|
41
|
+
ret_list = struct.unpack(f'{opt}{"H" * format_map[fmt]["length"]}', ret)
|
42
|
+
return list(ret_list)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
from datetime import datetime, timedelta
|
2
|
+
|
3
|
+
|
4
|
+
def trans_str_time_to_index(now_time, minute=15):
|
5
|
+
"""将时间按照minute切换为索引,时间格式为 %H-%M"""
|
6
|
+
time_list = [int(i) for i in now_time.split(":")]
|
7
|
+
time_int = time_list[0] * 4 + time_list[1] // minute
|
8
|
+
return time_int
|
9
|
+
|
10
|
+
|
11
|
+
def get_highest_or_lowest_value(start_time, end_time, hours, price_list, reverse=False):
|
12
|
+
start_index = trans_str_time_to_index(start_time)
|
13
|
+
end_index = trans_str_time_to_index(end_time)
|
14
|
+
arr = price_list[start_index:end_index]
|
15
|
+
if None in arr:
|
16
|
+
return False
|
17
|
+
indices = list(range(end_index - start_index))
|
18
|
+
sorted_indices = sorted(indices, key=lambda i: arr[i], reverse=reverse)
|
19
|
+
return sorted_indices[: int(hours * 4)], start_index
|
20
|
+
|
21
|
+
|
22
|
+
def get_rounded_times():
|
23
|
+
"""
|
24
|
+
返回距离当前时间最近的15min的整点时间以及后一整点5min时间(天气是预测未来15min的,也就是在00:00时,只能拿到00:15的数据)
|
25
|
+
"""
|
26
|
+
now = datetime.now()
|
27
|
+
# 确定当前时间所属的15分钟区间
|
28
|
+
index_1 = now.minute // 15
|
29
|
+
index_2 = now.minute % 15
|
30
|
+
left_time = now.replace(minute=15 * index_1, second=0, microsecond=0)
|
31
|
+
right_time = left_time + timedelta(minutes=15)
|
32
|
+
if index_2 < 8:
|
33
|
+
nearest_time = left_time
|
34
|
+
else:
|
35
|
+
nearest_time = right_time
|
36
|
+
return datetime.strftime(nearest_time, "%Y-%m-%d %H:%M:%S"), datetime.strftime(
|
37
|
+
right_time, "%Y-%m-%d %H:%M:%S"
|
38
|
+
)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: solax-py-library
|
3
|
-
Version: 1.0.0.
|
3
|
+
Version: 1.0.0.26
|
4
4
|
Summary: some common tool
|
5
5
|
Author: shenlvyu
|
6
6
|
Author-email: 13296718439@163.com
|
@@ -13,6 +13,7 @@ Classifier: Programming Language :: Python :: 3.11
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
14
14
|
Classifier: Programming Language :: Python :: 3.13
|
15
15
|
Requires-Dist: pydantic (>=1.10.0,<2.0.0)
|
16
|
+
Requires-Dist: requests (==2.32.3)
|
16
17
|
Requires-Dist: typing-extensions (==4.7.1)
|
17
18
|
Description-Content-Type: text/markdown
|
18
19
|
|
@@ -0,0 +1,80 @@
|
|
1
|
+
solax_py_library/__init__.py,sha256=4wrB7TuGOQaYHQvdn574G4JrcOnH6l8RNSR6AtKAiKc,34
|
2
|
+
solax_py_library/device/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
+
solax_py_library/device/constant/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
+
solax_py_library/device/constant/cabinet.py,sha256=V76qP2JXjdjTnsIo8wXGXYhbUb4YNKANFY-r4CrTFD4,68
|
5
|
+
solax_py_library/device/constant/inverter_model_info.py,sha256=Ujnwv79qycOTV_zqqr21wKXXj_lGLgrA56X_-Vjuxqw,18049
|
6
|
+
solax_py_library/device/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
7
|
+
solax_py_library/device/core/interver/__init__.py,sha256=RKye2D6NawSGdL4YUp_H-LmKIjThBp9CWhb6zwyM97s,1153
|
8
|
+
solax_py_library/device/core/interver/base.py,sha256=2TXHsjigMcIvGDLF3ZD4dw6UDrRRAk9Mq6sdBKRvydc,7191
|
9
|
+
solax_py_library/device/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
10
|
+
solax_py_library/device/types/alarm.py,sha256=kartXs_iRSV9Y3weFSsh9wMXU1_FxHZa6inHThyQCOk,358
|
11
|
+
solax_py_library/device/types/inverter_config.py,sha256=qCInNPbgsWf6yQjSw59kfQtJJWilMYUhvx_qo5qwRlU,912
|
12
|
+
solax_py_library/device/types/modbus_point.py,sha256=YmXe92gWXL_voVXDJE5zzNzr6dpPs7Ff3ciOAW-LgPs,580
|
13
|
+
solax_py_library/exception.py,sha256=ygAccdTqJctRrdt9bu6-vqZP5KadfKVS_1tjt4KcRn8,257
|
14
|
+
solax_py_library/smart_scene/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
|
+
solax_py_library/smart_scene/constant/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
|
+
solax_py_library/smart_scene/constant/message_entry.py,sha256=r-hSUQItc0xEgodXtDct7AltFHQZxj5KH6ZP_ioZtAQ,9191
|
17
|
+
solax_py_library/smart_scene/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
|
+
solax_py_library/smart_scene/core/action/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
|
+
solax_py_library/smart_scene/core/action/base.py,sha256=CCYrlCZeb3CfGZgTWQN673VJmuYNsTbEtdZ4ERUV7RA,395
|
20
|
+
solax_py_library/smart_scene/core/action/ems_action.py,sha256=sML6qasFoqOktTvEcHm0vKPYCj60VcKjAFz8RAaQc2U,206
|
21
|
+
solax_py_library/smart_scene/core/action/system_action.py,sha256=oGXq3yXS9nKcGjJActjk0R2Wr3AoO9uoyRPyuiM053g,204
|
22
|
+
solax_py_library/smart_scene/core/condition/__init__.py,sha256=1nN-N52Oq7LKdn6ApKGtSZq5fB1qJzJq8BOKOumfQvY,475
|
23
|
+
solax_py_library/smart_scene/core/condition/base.py,sha256=saj7dc0Su2Wi_Lx04cesHFgIPDyQUwvHuDElcaDOIHU,596
|
24
|
+
solax_py_library/smart_scene/core/condition/cabinet_condition.py,sha256=HEVifO3rHk2ElfSCEB0MzVdfrFWlkwqjt6tFhtJ8CLY,1581
|
25
|
+
solax_py_library/smart_scene/core/condition/date_condition.py,sha256=Xhca6VjoM8Bq-I-dFj1RPLTTzbBL81ORkBnR8D-YqUw,772
|
26
|
+
solax_py_library/smart_scene/core/condition/price_condition.py,sha256=IkgoB5YhpMxgFVkabilcBXtkjsqae01kkjF3tH10CK0,4006
|
27
|
+
solax_py_library/smart_scene/core/condition/system_condition.py,sha256=q5KDQdK6wjEvq0__WwBR4Sk-59yA2aIAgxTf1xjxJQk,1338
|
28
|
+
solax_py_library/smart_scene/core/condition/weather_condition.py,sha256=Xp7l9m3NW1vyyRGaJC5_gAX4HM-iuj7OGaw5LbZ4ztU,2223
|
29
|
+
solax_py_library/smart_scene/core/service/__init__.py,sha256=wWzHSN2XaHnI-TNtCJWWRHnNC7s3-2GNQo9y0K_PC4Q,69
|
30
|
+
solax_py_library/smart_scene/core/service/runner.py,sha256=SwQ6jb5yFPcyHyfU-THyGDjPEMcNFUOHkvVYA9wB1EE,6201
|
31
|
+
solax_py_library/smart_scene/exceptions/__init__.py,sha256=0hDgr70fFLQB14uorVCwbBhl1yQmZ-uBYGH5XtGm_dg,147
|
32
|
+
solax_py_library/smart_scene/exceptions/price.py,sha256=3bnY6JzeEskUoXVzEs8bpg6hQzgbinBKY4GP4hBITWU,152
|
33
|
+
solax_py_library/smart_scene/exceptions/smart_scene.py,sha256=69khvoFm1Eki4NBT45gVnsyWubEzF7dqnhU-unqT20g,1701
|
34
|
+
solax_py_library/smart_scene/exceptions/weather.py,sha256=bJl1VwiIXEpLQ9VjlVrDoTAIMFqVZdRCas7dtR7eAJc,133
|
35
|
+
solax_py_library/smart_scene/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
36
|
+
solax_py_library/smart_scene/types/action.py,sha256=cYICnxLfLRWFAlOGWpS2HBw-PyaB6TNlNuEmSsme26k,5723
|
37
|
+
solax_py_library/smart_scene/types/condition.py,sha256=mGjd-Kh34EjnHf8IKKAOdYPhPHlLB0HRVzC1pfkZsxo,9564
|
38
|
+
solax_py_library/smart_scene/types/smart_scene_content.py,sha256=C8H17QEicmDBbxN-m550njwaZyUhAL2hUhlLg3Qj1zM,6061
|
39
|
+
solax_py_library/snap_shot/__init__.py,sha256=Ex12q6BCkdU-3OP-f-ehGCetJJWnoZ7KxhEDd_lXh6M,81
|
40
|
+
solax_py_library/snap_shot/constant/__init__.py,sha256=UNfjAlx1wovXc1oH74af9oIe2TljwCCiTzNXzWgtUms,65
|
41
|
+
solax_py_library/snap_shot/constant/crc_table.py,sha256=D-pSxpf1XDzu7YR8LmbnzdLRvI8exDL2dyDh7RRc4Io,3566
|
42
|
+
solax_py_library/snap_shot/core/__init__.py,sha256=lovGQAEfqxPaLlE6gr9HJjgsKjZZLosgaWeGO0Q_JCI,178
|
43
|
+
solax_py_library/snap_shot/core/base_modbus.py,sha256=EdDSRvRC2a4IE_LGvjxGznqi6AX5x4O0_Wn1IkHzIpA,403
|
44
|
+
solax_py_library/snap_shot/core/parser.py,sha256=IM7SWqbRHGk9KwVRwP3jwht6tGIMClagdszodGiEJ_c,8999
|
45
|
+
solax_py_library/snap_shot/core/snap_shot.py,sha256=j6exbbzahmYtoCRsG9e5S64Lw2DOYgOFKtOfa0oz8xY,11109
|
46
|
+
solax_py_library/snap_shot/exceptions/__init__.py,sha256=9wLhmIelRKCXvlymcu3EewasVVYuPu4QQxTDLjGj6NQ,112
|
47
|
+
solax_py_library/snap_shot/exceptions/snap_shot.py,sha256=-oxxh_lUhfZwtggJ4zfNBPdkhdGPvcVvDezNlj4nFfY,154
|
48
|
+
solax_py_library/snap_shot/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
49
|
+
solax_py_library/snap_shot/types/__init__.py,sha256=g9ybB88TntvAMGIhLgJ31Xxn26zluSfI496bg-apSTU,290
|
50
|
+
solax_py_library/snap_shot/types/address.py,sha256=JhyB-t2OnKuE8akKk120sojCNXv4_OlLLuWsl5ChFZ8,1148
|
51
|
+
solax_py_library/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
52
|
+
solax_py_library/test/test_smart_scene/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
53
|
+
solax_py_library/test/test_smart_scene/test_condition.py,sha256=w-REUzkaDrq9acye2qZeAbTQb8bpgAykLfylsLvNrx8,331
|
54
|
+
solax_py_library/test/test_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
55
|
+
solax_py_library/test/test_utils/test_cloud_client.py,sha256=gOrHGXkFXpFV4kXTnjhmyJGem8VaGKw8OmXyW884oJ0,395
|
56
|
+
solax_py_library/upload/__init__.py,sha256=XhZar7BKaRN0XcdPl4QffWr488L3UWvuq5syT8nX2OU,93
|
57
|
+
solax_py_library/upload/api/__init__.py,sha256=ASShe-YQxP0aA3B_I8EmpWKXIdXPWvaANifrzlYrFEk,84
|
58
|
+
solax_py_library/upload/api/service.py,sha256=-APuz86t4loCkjzaxq02kuKrB6jxaPV-Tz1V__j6cY0,763
|
59
|
+
solax_py_library/upload/core/__init__.py,sha256=XMcnyDzCfsLwWaTAZt9-an7TuwYFqVNSt9W1_QRUrwA,89
|
60
|
+
solax_py_library/upload/core/data_adapter/__init__.py,sha256=9CXepLZSOjZMfNjyYKAWQCWZt353kTL_0tFBlIeUIOo,116
|
61
|
+
solax_py_library/upload/core/data_adapter/base.py,sha256=Va-SEe0eL3gobhNOnzHGkYBLIwf5RVawQdYRHHXg9g0,170
|
62
|
+
solax_py_library/upload/core/data_adapter/csv.py,sha256=8nlnV_43mMAR3re50MQJymzT5HYpZOo7eSeMsEfnEVE,861
|
63
|
+
solax_py_library/upload/core/upload_service/__init__.py,sha256=uA-UeH31rDNxByeZwvPhNFHPV_-J8JyCev8geuc---k,269
|
64
|
+
solax_py_library/upload/core/upload_service/base.py,sha256=dxCBVtPxDhN7oRTjnwnjtc2XAF4hyIz9HsYCJePlggg,912
|
65
|
+
solax_py_library/upload/core/upload_service/ftp.py,sha256=3Immu1SfJZ6vXIoUpDSx1_C4Saa0x9pNg-XgJCf7Fhg,3277
|
66
|
+
solax_py_library/upload/exceptions/__init__.py,sha256=12D68_mODfJkVFa1f65QgPUn8bvD5BDAeiHgNgU0258,186
|
67
|
+
solax_py_library/upload/exceptions/upload_error.py,sha256=V2_yEMLj9KQEkdQ0Cm1DOogbjZWGb4p8RVnFx7D9yLY,425
|
68
|
+
solax_py_library/upload/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
69
|
+
solax_py_library/upload/test/test_ftp.py,sha256=NPIt_BjSt_PH6XMP9c_7p7nAuktUyKu82_zTRgO8Cfw,3809
|
70
|
+
solax_py_library/upload/types/__init__.py,sha256=og9KBpYbcs36_S1izURj3vyHeuNOLJQrD9GpxK_JJaw,244
|
71
|
+
solax_py_library/upload/types/client.py,sha256=fG674_QEpOw3ibO171lcxJ0cz27yGR_sd3zgiyr4yuI,492
|
72
|
+
solax_py_library/upload/types/ftp.py,sha256=9kCeLB0g5Je19v4ifz8YYEsGOhJL1lKBO2C6V2VBndc,679
|
73
|
+
solax_py_library/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
74
|
+
solax_py_library/utils/cloud_client.py,sha256=5dZrc5fzrNFSXqTPZd7oHt-Y9Jj6RCigB7aXJQMJ8sQ,9610
|
75
|
+
solax_py_library/utils/common.py,sha256=bfnZcX9uM-PjJrYAFv1UMmZgt6bGR7MaOd7jRPNHGxw,1238
|
76
|
+
solax_py_library/utils/struct_util.py,sha256=pL6L80GXIHasy1ZDIj89-5BzXW1BWI3TPitH7thGGIE,1577
|
77
|
+
solax_py_library/utils/time_util.py,sha256=bY5kj9dmyOuLEQ6uYGQK7jU7y1RMiHZgevEKnkcQcSU,1461
|
78
|
+
solax_py_library-1.0.0.26.dist-info/METADATA,sha256=r0f6Z_QGhZwZehgD063VJ4aQlrakVmJGqmX8WQpxthY,1825
|
79
|
+
solax_py_library-1.0.0.26.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
80
|
+
solax_py_library-1.0.0.26.dist-info/RECORD,,
|
@@ -1,46 +0,0 @@
|
|
1
|
-
solax_py_library/__init__.py,sha256=zLUfOeLUGy1sFFu4tZI8cDlfuEATRZ3VcYywVhPLObE,35
|
2
|
-
solax_py_library/device/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
solax_py_library/device/constant/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
-
solax_py_library/device/constant/inverter_model_info.py,sha256=dbFWwXdHFXXvX_FLgFceYcSlJuuymLKm9CXnlk7szmQ,18361
|
5
|
-
solax_py_library/device/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
-
solax_py_library/device/core/interver/__init__.py,sha256=gnERg9RssRoZvfylG5CgXT8XiwwCf5hQ5_phch6lQM8,1189
|
7
|
-
solax_py_library/device/core/interver/base.py,sha256=8Zexb1ELWQkD_3LzYyEK7Oro0z71nl2m72RSA5w0bZQ,7406
|
8
|
-
solax_py_library/device/types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
-
solax_py_library/device/types/inverter_config.py,sha256=8oNO0PkoBrvCe9XnKpuz8QSs7A0jpW2l-vG6IttV0lA,953
|
10
|
-
solax_py_library/device/types/modbus_point.py,sha256=vukTJhqw7ZxFs4T2hbo975ZW0-oMUIKSF6CLF9muhoU,610
|
11
|
-
solax_py_library/exception.py,sha256=1NNSqi--RC_sEv_1uJ1z01QVBIs8lNe1YemzND_Vluo,267
|
12
|
-
solax_py_library/snap_shot/__init__.py,sha256=50fik3nxjnQoLIFEecc6c557pRtpQ1OxAqjp5HFgfe0,84
|
13
|
-
solax_py_library/snap_shot/constant/__init__.py,sha256=vFoN2ZJWjhpXBQ4BU9vUa9GnvRYA6253bcTZ_nec7AQ,70
|
14
|
-
solax_py_library/snap_shot/constant/crc_table.py,sha256=mTRYF3f7SxvVcVfFNHsgMMiXj2A_GGjRWfWXv4TSMNs,3824
|
15
|
-
solax_py_library/snap_shot/core/__init__.py,sha256=Mnc31li74rkHzNmTrCbSqQiVrs_0OfJDQNlXCR_XURA,187
|
16
|
-
solax_py_library/snap_shot/core/base_modbus.py,sha256=hd8047JdB97X9sF3ZzzjR8YjUNV7qWc0T6xtJEg5Pvs,417
|
17
|
-
solax_py_library/snap_shot/core/parser.py,sha256=IM7SWqbRHGk9KwVRwP3jwht6tGIMClagdszodGiEJ_c,8999
|
18
|
-
solax_py_library/snap_shot/core/snap_shot.py,sha256=j6exbbzahmYtoCRsG9e5S64Lw2DOYgOFKtOfa0oz8xY,11109
|
19
|
-
solax_py_library/snap_shot/exceptions/__init__.py,sha256=PZt5-dSRyBmRVjgBrFseZ_vpOLb8gThRnTtlw4bWP9Y,115
|
20
|
-
solax_py_library/snap_shot/exceptions/snap_shot.py,sha256=8afTk1Y09Pu47yA1yOvu7kxxxZavob1yvDBYlI0WP9w,163
|
21
|
-
solax_py_library/snap_shot/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
|
-
solax_py_library/snap_shot/types/__init__.py,sha256=wQRjRVD-bBTAAoVPh69XgmDQfl-pVmS1DzZYhphixlg,305
|
23
|
-
solax_py_library/snap_shot/types/address.py,sha256=8bheI03XMXXMNr7rFHkf9ZdacyGeQgc63bGP9bsojck,1187
|
24
|
-
solax_py_library/upload/__init__.py,sha256=V8QbJ1xmaJZBHWRxBo_OzIrs50Y56QsH9T7qn3kY3M8,96
|
25
|
-
solax_py_library/upload/api/__init__.py,sha256=VHRXkLLQKsIeUi4T-osSsURmcJS6cM5rhhvUwF6aLG8,87
|
26
|
-
solax_py_library/upload/api/service.py,sha256=FSAz-WWHRG72vE45gu73n0hheyXuB94GQdgSMfqusOA,787
|
27
|
-
solax_py_library/upload/core/__init__.py,sha256=LxE2LrHB9vfyGwb1YbxHfbeyfdOhlSZdXvDp2L2Jtvs,92
|
28
|
-
solax_py_library/upload/core/data_adapter/__init__.py,sha256=AAt7SndlSM3_0iE9q7Uevg51PraUWgoFOgYg9XBKktM,121
|
29
|
-
solax_py_library/upload/core/data_adapter/base.py,sha256=HoN9WVLzOjt-0lg7x0DR0H0Fflg7V97WJmtgBZeY37g,179
|
30
|
-
solax_py_library/upload/core/data_adapter/csv.py,sha256=QaTjHw_aGZyEPUkr2AfBh5ITgRDE9dWN2d8sXh1xlZc,887
|
31
|
-
solax_py_library/upload/core/upload_service/__init__.py,sha256=iVlmUxDNBroqA0yBGf4DnIt-3RMdBoUr2kxuP-z1Y_8,284
|
32
|
-
solax_py_library/upload/core/upload_service/base.py,sha256=U4wyynOtE1dYT11nstPgbCjnEgknqzsk6wQqxfM1MC4,955
|
33
|
-
solax_py_library/upload/core/upload_service/ftp.py,sha256=3Immu1SfJZ6vXIoUpDSx1_C4Saa0x9pNg-XgJCf7Fhg,3277
|
34
|
-
solax_py_library/upload/exceptions/__init__.py,sha256=iSPPPHBP_aG9-9OCR_tCrGihL-uEIpSwvi9JZxSYbUk,194
|
35
|
-
solax_py_library/upload/exceptions/upload_error.py,sha256=sqJvooTZxM9eKqFUV5-sI101xw24ubEdyUZq4mG8sbM,446
|
36
|
-
solax_py_library/upload/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
37
|
-
solax_py_library/upload/test/test_ftp.py,sha256=fIyAABF3v1qLlLehJ7SCRi6WcX7vjYE9swPKLPdSRj8,3922
|
38
|
-
solax_py_library/upload/types/__init__.py,sha256=mgfwypAgvWNfhLMOK-osoF6Nf5QSn-uB02MkaH4m5pY,255
|
39
|
-
solax_py_library/upload/types/client.py,sha256=KqrwTRniunJCV6HjaXkZAYzFryYxXirmIWmfh5V93qI,511
|
40
|
-
solax_py_library/upload/types/ftp.py,sha256=kgjB0DyUQCGLH2iZncMuuRWKrxhh1fBD_KTu_PeEPUE,716
|
41
|
-
solax_py_library/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
42
|
-
solax_py_library/utils/common.py,sha256=Ttzw6ZMjFCS4Qqu3l1A04vR6cPLvVKCNwBAmwgREFbs,1276
|
43
|
-
solax_py_library/utils/struct_util.py,sha256=ER0F6W_QCGM98NItGbQLmdZtbPn1UAZ-qh2tnqHi004,943
|
44
|
-
solax_py_library-1.0.0.24.dist-info/METADATA,sha256=fUbGIBlBiVGeh0hBF0hGDTi-GyOIDMYFYSD3-nI5_aI,1790
|
45
|
-
solax_py_library-1.0.0.24.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
46
|
-
solax_py_library-1.0.0.24.dist-info/RECORD,,
|
File without changes
|