🎉 init(init):初始化仓库
This commit is contained in:
336
irrgiation/weatherAndSoilDataRequest.py
Normal file
336
irrgiation/weatherAndSoilDataRequest.py
Normal 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'])
|
||||
Reference in New Issue
Block a user