Files
irrigation-model/irrgiation/weatherAndSoilDataRequest.py
2025-12-23 08:38:08 +08:00

336 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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'])