🎉 init(init):初始化仓库

This commit is contained in:
张鑫
2025-12-23 08:38:08 +08:00
parent 36226cc9fe
commit 066fe58f89
34 changed files with 3402 additions and 2 deletions

View File

@@ -0,0 +1,336 @@
from datetime import datetime, timezone, timedelta, date
import pandas as pd
import requests
import json
from matplotlib import pyplot as plt
#登录接口认证
def loginAuth():
# 接口地址
global auth_token
url = "https://xj-tb.maimaiag.com/api/auth/login" # 请替换为实际地址
# 请求头
headers = {
"Content-Type": "application/json"
}
# 请求体数据
payload = {
"username": "read@xj.com",
"password": "maimai"
}
try:
# 发送POST请求
response = requests.post(
url,
headers=headers,
data=json.dumps(payload) # 或者直接使用 json=payload
)
# 检查响应状态码
if response.status_code == 200:
print("登录成功!")
print("响应数据:", response.json())
# 通常登录接口会返回token可以这样获取
response_data = response.json()
auth_token = response_data.get("token") # 根据实际返回字段调整
if auth_token:
print("获取到的认证Token:", auth_token)
else:
print(f"登录失败,状态码: {response.status_code}")
print("错误信息:", response.text)
except requests.exceptions.RequestException as e:
print(f"请求发生异常: {str(e)}")
except json.JSONDecodeError as e:
print(f"JSON解析错误: {str(e)}")
return auth_token
# 调用数据接口--历史数据
def getWeatherAndSoilData(auth_token,device_id,startTs,endTs,agg,interval,limit,orderBy,keys):
# 配置信息
BASE_URL = "https://xj-tb.maimaiag.com/" # 请替换为实际API地址
TOKEN = auth_token # 替换为实际的Bearer token
DEVICE_ID = device_id # 替换为实际的设备ID
# 构造请求URL
endpoint = f"/api/plugins/telemetry/DEVICE/{DEVICE_ID}/values/timeseries"
url = BASE_URL + endpoint
# 请求头
headers = {
"Content-Type": "application/json",
"X-Authorization": f"Bearer+{TOKEN}"
}
# 查询参数
params = {
"keys": keys, # 要查询的参数,多个用逗号分隔
"startTs": startTs, # 开始时间戳(毫秒)- 可选
"endTs": endTs, # 结束时间戳(毫秒)- 可选
"agg": agg, # 聚合函数 - 可选
"interval": interval, # 聚合间隔(毫秒)- 可选
"limit": limit, # 返回条数 - 可选
"orderBy": orderBy # 排序方式 - 可选
}
try:
# 发送GET请求
response = requests.get(
url,
headers=headers,
params=params
)
# 检查响应状态码
if response.status_code == 200:
# print("请求成功!")
data = response.json()
# print("响应数据:", json.dumps(data, indent=2))
converted_data = {k: convert_timestamp_to_datetime(v) for k, v in data.items()}
return converted_data
elif response.status_code == 401:
print("认证失败请检查Token是否正确")
elif response.status_code == 404:
print("设备不存在或路径错误")
else:
print(f"请求失败,状态码: {response.status_code}")
print("错误信息:", response.text)
except requests.exceptions.RequestException as e:
print(f"请求发生异常: {str(e)}")
except json.JSONDecodeError as e:
print(f"JSON解析错误: {str(e)}")
print("原始响应:", response.text)
def convert_timestamp_to_datetime(data_dict):
"""
递归地将字典中的所有'timestamp'字段转换为可读的日期时间格式
保留原始时间戳的同时添加新的'datetime'字段
"""
if isinstance(data_dict, dict):
if "ts" in data_dict:
# 转换毫秒时间戳为datetime对象
timestamp_sec = data_dict["ts"] / 1000
dt = datetime.fromtimestamp(timestamp_sec)
# 添加新字段,保留原始时间戳
data_dict["datetime"] = dt.strftime("%Y-%m-%d %H:%M:%S")
return data_dict
elif isinstance(data_dict, list):
return [convert_timestamp_to_datetime(item) for item in data_dict]
else:
return data_dict
def dateToTimestamp(date):
# dt = datetime.strptime(date, "%Y-%m-%d %H:%M:%S")
if isinstance(date, datetime):
# 如果已经是datetime对象直接使用
dt = date
elif isinstance(date, str):
# 如果是字符串解析为datetime对象
dt = datetime.strptime(date, "%Y-%m-%d %H:%M:%S.%f")
else:
raise TypeError("date参数必须是字符串或datetime对象")
timestamp_ms = int(dt.timestamp() * 1000)
return timestamp_ms
#调用接口获取未来气象数据
def getFutureWeather(monitor_date):
base_url_future="https://api.open-meteo.com/"
end_point="v1/forecast"
current_date = datetime.now().date()
params = {
"latitude": "41.34252110189814", # 纬度
"longitude": "86.28810755462379", # 经度
"hourly": "temperature_2m,precipitation,precipitation_probability"
}
# if monitor_date.date()<current_date:
# # url = base_url_history + end_point
# params["start_date"] = (monitor_date + timedelta(days=1)).strftime("%Y-%m-%d")
# params["end_date"] = (monitor_date + timedelta(days=3)).strftime("%Y-%m-%d")
#
# else:
url = base_url_future + end_point
params["forecast_days"]= 4
try:
# 发送GET请求
response = requests.get(
url,
params=params
)
# 检查响应状态码
if response.status_code == 200:
data = response.json()
result={}
if monitor_date.date()<current_date:
result["qw_day1"] = get_tjvalue(data['hourly']['temperature_2m'][:24])
result["qw_day2"] = get_tjvalue(data['hourly']['temperature_2m'][24:48])
result["qw_day3"] = get_tjvalue(data['hourly']['temperature_2m'][48:72])
result["js_day1"] = get_tjvalue(data['hourly']['precipitation'][:24])
result["js_day2"] = get_tjvalue(data['hourly']['precipitation'][24:48])
result["js_day3"] = get_tjvalue(data['hourly']['precipitation'][48:72])
else:
result["qw_day1"] = get_tjvalue(data['hourly']['temperature_2m'][24:48])
result["qw_day2"] = get_tjvalue(data['hourly']['temperature_2m'][48:72])
result["qw_day3"] = get_tjvalue(data['hourly']['temperature_2m'][72:96])
result["js_day1"] = get_tjvalue(data['hourly']['precipitation'][24:48])
result["js_day2"] = get_tjvalue(data['hourly']['precipitation'][48:72])
result["js_day3"] = get_tjvalue(data['hourly']['precipitation'][72:96])
return result
elif response.status_code == 401:
print("认证失败请检查Token是否正确")
elif response.status_code == 404:
print("设备不存在或路径错误")
else:
print(f"请求失败,状态码: {response.status_code}")
print("错误信息:", response.text)
except requests.exceptions.RequestException as e:
print(f"请求发生异常: {str(e)}")
except json.JSONDecodeError as e:
print(f"JSON解析错误: {str(e)}")
print("原始响应:", response.text)
def get_tjvalue(data):
result={}
max_val = max(data)
min_val = min(data)
mean_val = sum(data) / len(data)
sum_val = sum(data)
result['max']=max_val
result['min']=min_val
result['mean']=mean_val
result['sum'] = sum_val
return result
soil_params={
"1号传感器":{
"device_id":"31fbb2d0-561b-11f0-a556-4f10f26fc07f"
},
"2号传感器": {
"device_id": "3bf4cc90-561b-11f0-a556-4f10f26fc07f"
},
"3号传感器": {
"device_id": "43a57cf0-561b-11f0-a556-4f10f26fc07f"
},
"4号传感器": {
"device_id": "4ff6b780-561b-11f0-a556-4f10f26fc07f"
},
"5号传感器": {
"device_id": "598c5480-561b-11f0-a556-4f10f26fc07f"
},
"6号传感器": {
"device_id": "6ff07260-561b-11f0-a556-4f10f26fc07f"
},
"7号传感器": {
"device_id": "8637b970-561b-11f0-a556-4f10f26fc07f"
},
"8号传感器": {
"device_id": "955de5f0-561b-11f0-a556-4f10f26fc07f"
},
"9号传感器": {
"device_id": "a24e94d0-561b-11f0-a556-4f10f26fc07f"
},
"10号传感器": {
"device_id": "adb7e060-561b-11f0-a556-4f10f26fc07f"
},
"11号传感器": {
"device_id": "b74c6bf0-561b-11f0-a556-4f10f26fc07f"
},
"12号传感器": {
"device_id": "c0f36e10-561b-11f0-a556-4f10f26fc07f"
},
}
def get_soil_data_dk1(auth_token,startTs, endTs):
keys_soil = "SOIL_MOISTURE_SURFACE,SOIL_MOISTURE_MIDDLE,SOIL_MOISTURE_BOTTOM"
limit = ""
orderBy = ""
result={}
for key in soil_params:
id=soil_params[key]['device_id']
soil_data = getWeatherAndSoilData(auth_token,id, startTs, endTs, "AVG", 3600000, limit, orderBy,
keys_soil)
result[key]=soil_data
return result
def get_soil_data_dk2(auth_token,device_id,startTs, endTs):
keys_soil = "SOIL_MOISTURE_SURFACE,SOIL_MOISTURE_MIDDLE,SOIL_MOISTURE_BOTTOM"
limit = ""
orderBy = ""
result={}
soil_data = getWeatherAndSoilData(auth_token,device_id, startTs, endTs, "AVG", 3600000, limit, orderBy,
keys_soil)
result[device_id]=soil_data
return result
weather_params={
"device_id" : "18d121f0-561b-11f0-a556-4f10f26fc07f",
"agg" :"AVG",
"interval" : 3600000, #1小时
"limit" :"",
"orderBy" : "",
"keys":"AIR_TEMPERATURE,WIND_SPEED,AIR_LUX,AIR_HUMIDITY,RAIN_FALL_REALTIME"
}
def get_plot(data_list):
df = pd.DataFrame(data_list)
df['value'] = pd.to_numeric(df['value'], errors='coerce').round(3)# 转换湿度值为浮点数
df['datetime'] = pd.to_datetime(df['datetime']) # 转换为datetime类型
# 设置画布大小
plt.figure(figsize=(12, 6))
# 绘制折线图
plt.plot(df['datetime'], df['value'],
color='teal',
linestyle='-',
linewidth=2,
marker='o',
markersize=4,
markerfacecolor='orange',
markeredgecolor='orange',
label='Soil Moisture (%)')
# 添加22点后的数据高亮符合你之前获取夜间数据的需求
night_data = df[df['datetime'].dt.hour >= 22]
plt.scatter(night_data['datetime'], night_data['value'],
color='red',
s=30,
label='22:00-06:00 Data')
# 设置标题和坐标轴标签
plt.title('Soil Moisture Time Series (2025-06-22 to 2025-06-30)',
fontsize=14,
pad=15)
plt.xlabel('Datetime', fontsize=12, labelpad=10)
plt.ylabel('Soil Moisture (%)', fontsize=12, labelpad=10)
# 设置x轴刻度旋转避免重叠
plt.xticks(rotation=45, ha='right', fontsize=10)
# 添加网格线
plt.grid(axis='y', linestyle='--', alpha=0.7)
# 添加图例
plt.legend(loc='upper right', fontsize=10)
# 调整布局
plt.tight_layout()
# 显示图表
plt.show()
if __name__ == "__main__":
auth_token = loginAuth()
device_id="18d121f0-561b-11f0-a556-4f10f26fc07f"
agg="AVG"
interval=21600000
limit=""
orderBy=""
keys="RAIN_FALL_REALTIME"
date_start = "2025-06-25 00:00:00.123"
date_end = "2025-07-01 23:59:59.123"
startTs=dateToTimestamp(date_start)
endTs=dateToTimestamp(date_end)
# data=get_soil_data_dk1(auth_token,startTs,endTs)
# print(data)
data=getWeatherAndSoilData(auth_token,device_id,startTs,endTs,"AVG",3600000,limit,orderBy,keys)
print(data['RAIN_FALL'])
# get_plot(data['1号传感器']['SOIL_MOISTURE_SURFACE'])
get_plot(data['RAIN_FALL_REALTIME'])