Add WMH code

This commit is contained in:
DingZQ
2025-02-07 22:58:15 +08:00
parent c40903289e
commit 15147b97fc
7 changed files with 3565 additions and 63 deletions

570
main.py
View File

@@ -7,7 +7,9 @@ from urllib.request import Request
from xml.dom import minicompat
from pydantic import BaseModel
from starlette.responses import FileResponse, JSONResponse
from fastapi import FastAPI, File, UploadFile, Response, status, Request, Body, HTTPException
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.types import Receive
from fastapi import FastAPI, File, UploadFile, Response, status, Request, Body, HTTPException,Query
from fastapi.responses import PlainTextResponse
from fastapi.middleware.gzip import GZipMiddleware
from tjnetwork import *
@@ -15,8 +17,14 @@ import asyncio
import threading
import uvicorn
from multiprocessing import Value
import uvicorn
from run_simulation import run_simulation, run_simulation_ex
from online_Analysis import *
import logging
from fastapi.middleware.cors import CORSMiddleware
import random
from datetime import datetime
import shutil
import logging
import redis
import datetime
@@ -39,6 +47,7 @@ tmpDir = "C:/tmpfiles/"
lockedPrjs = {}
if not os.path.exists(inpDir):
os.mkdir(inpDir)
@@ -58,7 +67,11 @@ influx_org_name = "TJWATERORG" # 替换为你的Organization名称
influx_client = InfluxDBClient(url=influx_url, token=influx_token, org=influx_org_name)
# 配置日志记录器
logging.basicConfig(level=logging.INFO)
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger(__name__)
# 配置 CORS 中间件
@@ -69,11 +82,69 @@ app.add_middleware(
allow_methods=["*"], # 允许所有 HTTP 方法
allow_headers=["*"], # 允许所有 HTTP 头
)
# 定义一个共享变量
lock_simulation = Value('i', 0)
app.add_middleware(GZipMiddleware, minimum_size=1000)
async def receive_with_body(body: bytes) -> Receive:
async def receive() -> dict:
return {
"type": "http.request",
"body": body,
"more_body": False,
}
return receive
@app.middleware("http")
async def log_requests(request: Request, call_next):
if request.url.path == "/favicon.ico":
return Response(status_code=204)
# 记录接收请求的时间
request_time = time.time()
request_time_str = datetime.fromtimestamp(request_time).strftime('%Y-%m-%d %H:%M:%S')
# 判断是否为文件上传
is_file_upload = request.headers.get("content-type", "").startswith("multipart/form-data")
# 记录接收的请求数据
logging.info(f"Received request: {request.method} {request.url} at {request_time_str}")
if not is_file_upload:
request_body = await request.body()
logging.info(f"Request body: {request_body.decode('utf-8')}")
# 创建新的 Request 对象,传递缓存的请求体
receive = await receive_with_body(request_body)
request = Request(request.scope, receive=receive)
else:
logging.info(f"Request body: File")
# 处理请求
response = await call_next(request)
# 记录发送响应的时间
response_time = time.time()
response_time_str = datetime.fromtimestamp(response_time).strftime('%Y-%m-%d %H:%M:%S')
processing_time = response_time - request_time
# 记录发送的响应数据
# response_body = b""
# async for chunk in response.body_iterator:
# response_body += chunk
# 记录响应的状态码以及是否成功
success_status = response.status_code < 400
logging.info(f"Response status: {response.status_code} at {response_time_str}, success: {success_status}")
# logging.info(f"Response body: {response_body.decode('utf-8')}")
logging.info(f"Processing time: {processing_time:.3f} seconds")
return response
@app.on_event("startup")
async def startup_db():
logger.info('\n')
@@ -82,7 +153,8 @@ async def startup_db():
logger.info("TJWater CloudService is starting...")
logger.info('**********************************************************')
logger.info('\n')
############################################################
# extension_data
############################################################
@@ -382,7 +454,7 @@ async def fastapi_is_pipe(network: str, link: str) -> bool:
@app.get('/ispump/')
async def fastapi_is_pump(network: str, link: str) -> bool:
return is_pump(network, lin)
return is_pump(network, link)
@app.get('/isvalve/')
async def fastapi_is_valve(network: str, link: str) -> bool:
@@ -1712,7 +1784,7 @@ async def fastapi_get_scada_element_schema(network: str) -> dict[str, dict[str,
@app.get('/getscadaelements/')
async def fastapi_get_scada_elements(network: str) -> list[str]:
return get_all_scada_elements(network)
return get_scada_elements(network)
@app.get('/getscadaelement/')
async def fastapi_get_scada_element(network: str, id: str) -> dict[str, Any]:
@@ -2050,8 +2122,492 @@ def generate_openapi_json():
with open(openapi_json_path, "w") as file:
json.dump(app.openapi(), file, indent=4)
############################################################
# real_time api 37
# example: http://127.0.0.1:8000/runsimulation?network=beibeizone&start_time=2024-04-01T08:00:00Z
############################################################
# 必须用这个PlainTextResponse不然每个key都有引号
# @app.get("/runsimulation/", response_class = PlainTextResponse)
# async def fastapi_run_project(network: str,start_time:str,end_time=None) -> str:
# filename = 'c:/lock.simulation'
# filename2 = 'c:/lock.simulation2'
# if os.path.exists(filename2):
# print('file exists')
# raise HTTPException(status_code=409, detail="is in simulation")
# else:
# print('file doesnt exists')
# #os.rename(filename, filename2)
# result = run_simulation(network,start_time,end_time)
# #os.rename(filename2, filename)
# return result
############################################################
# real_time api 37
# example: http://127.0.0.1:8000/runsimulation?network=beibeizone&start_time=2024-04-01T08:00:00Z
############################################################
# 必须用这个PlainTextResponse不然每个key都有引号
@app.get("/runsimulation/", response_class = PlainTextResponse)
async def fastapi_run_project(network: str,start_time:str,end_time=None) -> str:
filename = 'c:/lock.simulation'
filename2 = 'c:/lock.simulation2'
if os.path.exists(filename2):
print('file exists')
raise HTTPException(status_code=409, detail="is in simulation")
else:
print('file doesnt exists')
#os.rename(filename, filename2)
result = run_simulation_ex(name=network, simulation_type='realtime',
start_datetime=start_time, end_datetime=end_time)
#os.rename(filename2, filename)
return result
############################################################
# real_time api 37.5
# example:
# response = requests.post("http://127.0.0.1:8000/runsimulation",
# data=json.dumps({'network': 'bb_server', 'simulation_type': 'extended',
# 'start_time': '2024-05-17T09:30:00Z', 'duration': 900,
# 'pump_control': {'1#': [0, 0], '2#': [1, 1], '3#': [1, 1], '4#': [1, 0],
# '5#': [45, 43], '6#': [0, 0], '7#': [0, 0]}}),
# headers={'accept': 'application/json', 'Content-Type': 'application/json'})
############################################################
# class RunSimuItem(BaseModel):
# network: str
# simulation_type: str
# start_time: str
# end_time: Optional[str] = None
# duration: Optional[int] = 900
# pump_control: Optional[dict] = None
#
#
# @app.post("/runsimulation/")
# async def fastapi_run_project(item: RunSimuItem) -> str:
# item = item.dict()
# filename = 'c:/lock.simulation'
# filename2 = 'c:/lock.simulation2'
# if os.path.exists(filename2):
# print('file exists')
# raise HTTPException(status_code=409, detail="is in simulation")
# else:
# print('file doesnt exists')
# #os.rename(filename, filename2)
# result = run_simulation_ex(item['network'], item['simulation_type'],
# item['start_time'], item['end_time'],
# item['duration'], item['pump_control'])
# #os.rename(filename2, filename)
# return result
############################################################
# burst analysis api 38
#example:http://127.0.0.1:8000/burst_analysis?network=beibeizone&start_time=2024-04-01T08:00:00Z&burst_ID=ZBBGXSZW000001&burst_size=200&duration=1800
############################################################
# @app.get("/burst_analysis/", response_class = PlainTextResponse)
# async def fastapi_burst_analysis(network: str,start_time:str,burst_ID:str,burst_size:float,burst_flow:float=None,duration:int=None) -> str:
# filename = 'c:/lock.simulation'
# filename2 = 'c:/lock.simulation2'
# if os.path.exists(filename2):
# print('file exists')
# raise HTTPException(status_code=409, detail="is in simulation")
# else:
# print('file doesnt exists')
# #os.rename(filename, filename2)
# result = burst_analysis(network,start_time,burst_ID,burst_size,burst_flow,duration)
# #os.rename(filename2, filename)
# return result
############################################################
# burst analysis api 38.5
# example:
# response = requests.post("http://127.0.0.1:8000/burst_analysis",
# data=json.dumps({'network': 'bb_server',
# 'start_time': '2024-05-17T09:30:00Z',
# 'burst_ID': ['ZBBGXSZW000001'],
# 'burst_size': [200],
# 'duration': 1800,
# 'pump_control': {'1#': [0, 0, 0], '2#': [1, 1, 1], '3#': [1, 1, 1], '4#': [1, 1, 1],
# '5#': [45, 45, 45], '6#': [0, 0, 0], '7#': [0, 0, 0]}
# 'valve_closed': ['GSD2307192058576667FF7B41FF']),
# headers={'accept': 'application/json', 'Content-Type': 'application/json'})
############################################################
class BurstAnalysis(BaseModel):
network: str
start_time: str
burst_ID: list[str] | str
burst_size: list[float] | float
duration: int
pump_control: Optional[dict] = None
valve_closed: Optional[list] = None
@app.post("/burst_analysis/")
async def fastapi_burst_analysis(data: BurstAnalysis) -> str:
item = data.dict()
filename = 'c:/lock.simulation'
filename2 = 'c:/lock.simulation2'
if os.path.exists(filename2):
print('file exists')
raise HTTPException(status_code=409, detail="is in simulation")
else:
print('file doesnt exists')
#os.rename(filename, filename2)
result = burst_analysis(prj_name=item['network'],
date_time=item['start_time'],
burst_ID=item['burst_ID'],
burst_size=item['burst_size'],
duration=item['duration'],
pump_control=item['pump_control'],
valve_closed=item['valve_closed'])
#os.rename(filename2, filename)
return result
############################################################
# valve close analysis api 39
#example:http://127.0.0.1:8000/valve_close_analysis?network=beibeizone&start_time=2024-04-01T08:00:00Z&valves=GSD2307192058577780A3287D78&valves=GSD2307192058572E953B707226(S2)&duration=1800
############################################################
@app.get("/valve_close_analysis/", response_class = PlainTextResponse)
async def fastapi_valve_close_analysis(network: str,start_time:str,valves:Annotated[list[str], Query()],duration:int=None) -> str:
filename = 'c:/lock.simulation'
filename2 = 'c:/lock.simulation2'
if os.path.exists(filename2):
print('file exists')
raise HTTPException(status_code=409, detail="is in simulation")
else:
print('file doesnt exists')
#os.rename(filename, filename2)
result = valve_close_analysis(network,start_time,valves,duration)
#os.rename(filename2, filename)
return result
############################################################
# pipe flushing analysis api 40
#example:http://127.0.0.1:8000/flushing_analysis?network=beibeizone&start_time=2024-04-01T08:00:00Z&valves=GSD230719205857733F8F5214FF&valves=GSD230719205857C0AF65B6A170&valves_k=0.5&valves_k=0.5&drainage_node_ID=GSD2307192058570DEDF28E4F73&flush_flow=0&duration=1800
############################################################
@app.get("/flushing_analysis/", response_class = PlainTextResponse)
async def fastapi_flushing_analysis(network: str,start_time:str,valves:Annotated[list[str], Query()],valves_k:Annotated[list[float], Query()],drainage_node_ID:str,flush_flow:float=0,duration:int=None) -> str:
filename = 'c:/lock.simulation'
filename2 = 'c:/lock.simulation2'
if os.path.exists(filename2):
print('file exists')
raise HTTPException(status_code=409, detail="is in simulation")
else:
print('file doesnt exists')
#os.rename(filename, filename2)
result = flushing_analysis(network,start_time,valves,valves_k,drainage_node_ID,flush_flow,duration)
#os.rename(filename2, filename)
return result
############################################################
# contaminant_simulation api 41
#example:http://127.0.0.1:8000/contaminant_simulation?network=beibeizone&start_time=2024-04-01T08:00:00Z&source=ZBBDTZDP002677&concentration=100&duration=1800
############################################################
@app.get("/contaminant_simulation/", response_class = PlainTextResponse)
async def fastapi_contaminant_simulation(network: str,start_time:str,source:str,concentration:float,duration:int=900,pattern:str=None) -> str:
filename = 'c:/lock.simulation'
filename2 = 'c:/lock.simulation2'
if os.path.exists(filename2):
print('file exists')
raise HTTPException(status_code=409, detail="is in simulation")
else:
print('file doesnt exists')
#os.rename(filename, filename2)
result = contaminant_simulation(network,start_time,source,concentration,duration,pattern)
#os.rename(filename2, filename)
return result
############################################################
# age analysis api 42
#example:http://127.0.0.1:8000/age_analysis/?network=bb&start_time=2024-04-01T00:00:00Z&end_time=2024-04-01T08:00:00Z&duration=28800
############################################################
@app.get("/age_analysis/", response_class = PlainTextResponse)
async def fastapi_age_analysis(network: str, start_time:str, end_time:str, duration:int) -> str:
filename = 'c:/lock.simulation'
filename2 = 'c:/lock.simulation2'
if os.path.exists(filename2):
print('file exists')
raise HTTPException(status_code=409, detail="is in simulation")
else:
print('file doesnt exists')
#os.rename(filename, filename2)
result = age_analysis(network,start_time,end_time,duration)
#os.rename(filename2, filename)
return result
############################################################
# scheduling analysis api 43
############################################################
class SchedulingAnalysis(BaseModel):
network: str
start_time: str
pump_control: dict
tank_id: str
water_plant_output_id: str
time_delta: Optional[int] = 300
@app.post("/scheduling_analysis/")
async def fastapi_scheduling_analysis(data: SchedulingAnalysis) -> str:
data = data.dict()
filename = 'c:/lock.simulation'
filename2 = 'c:/lock.simulation2'
if os.path.exists(filename2):
print('file exists')
raise HTTPException(status_code=409, detail="is in simulation")
else:
print('file doesnt exists')
#os.rename(filename, filename2)
result = scheduling_simulation(data['network'], data['start_time'],
data['pump_control'], data['tank_id'],
data['water_plant_output_id'], data['time_delta'])
#os.rename(filename2, filename)
return result
############################################################
# pressure_regulating api 44
# example:
# response = requests.post("http://127.0.0.1:8000/pressure_regulating",
# data=json.dumps({'network': 'bb_server',
# 'start_time': '2024-05-17T09:30:00Z',
# 'pump_control': {'1#': [0, 0], '2#': [1, 1], '3#': [1, 1], '4#': [1, 1],
# '5#': [45, 45], '6#': [0, 0], '7#': [0, 0]}
# 'tank_init_level': {'ZBBDTJSC000002': 2, 'ZBBDTJSC000001': 2}}),
# headers={'accept': 'application/json', 'Content-Type': 'application/json'})
############################################################
class PressureRegulation(BaseModel):
network: str
start_time: str
pump_control: dict
tank_init_level: Optional[dict] = None
@app.post("/pressure_regulation/")
async def fastapi_pressure_regulation(data: PressureRegulation) -> str:
item = data.dict()
filename = 'c:/lock.simulation'
filename2 = 'c:/lock.simulation2'
if os.path.exists(filename2):
print('file exists')
raise HTTPException(status_code=409, detail="is in simulation")
else:
print('file doesnt exists')
#os.rename(filename, filename2)
result = pressure_regulation(prj_name=item['network'],
start_datetime=item['start_time'],
pump_control=item['pump_control'],
tank_initial_level_control=item['tank_init_level'])
#os.rename(filename2, filename)
return result
############################################################
# project_management api 45
# example:
# response = requests.post("http://127.0.0.1:8000/project_management",
# data=json.dumps({'network': 'bb_server',
# 'start_time': '2024-05-17T00:00:00Z',
# 'pump_control':
# {'1#':(list:97), '2#':(list:97), '3#':(list:97), '4#':(list:97),
# '5#':(list:97), '6#':(list:97), '7#':(list:97)}
# 'tank_init_level': {'ZBBDTJSC000002': 2, 'ZBBDTJSC000001': 2}
# 'region_demand': {'hp': 150000, 'lp': 40000}}),
# headers={'accept': 'application/json', 'Content-Type': 'application/json'})
############################################################
class ProjectManagement(BaseModel):
network: str
start_time: str
pump_control: dict
tank_init_level: Optional[dict] = None
region_demand: Optional[dict] = None
@app.post("/project_management/")
async def fastapi_project_management(data: ProjectManagement) -> str:
item = data.dict()
filename = 'c:/lock.simulation'
filename2 = 'c:/lock.simulation2'
if os.path.exists(filename2):
print('file exists')
raise HTTPException(status_code=409, detail="is in simulation")
else:
print('file doesnt exists')
#os.rename(filename, filename2)
result = project_management(prj_name=item['network'],
start_datetime=item['start_time'],
pump_control=item['pump_control'],
tank_initial_level_control=item['tank_init_level'],
region_demand_control=item['region_demand'])
#os.rename(filename2, filename)
return result
############################################################
# project_management api 46
# example:
# with open('./inp/bb_temp.inp', 'rb') as file:
# response = requests.post("http://127.0.0.1:8000/network_project",
# files={'file': file})
############################################################
@app.post("/network_project/")
async def fastapi_network_project(file: UploadFile = File()) -> str:
temp_file_path = './inp/'
if not os.path.exists(temp_file_path):
os.mkdir(temp_file_path)
temp_file_name = f'network_project_{datetime.now().strftime("%Y%m%d")}'
temp_file_path = f'{temp_file_path}{temp_file_name}.inp'
with open(temp_file_path, "wb") as buffer:
shutil.copyfileobj(file.file, buffer)
buffer.close()
filename = 'c:/lock.simulation'
filename2 = 'c:/lock.simulation2'
if os.path.exists(filename2):
print('file exists')
raise HTTPException(status_code=409, detail="is in simulation")
else:
print('file doesnt exists')
result = run_inp(temp_file_name)
#os.rename(filename2, filename)
return result
############################################################
# daily scheduling analysis api 47
############################################################
class DailySchedulingAnalysis(BaseModel):
network: str
start_time: str
pump_control: dict
reservoir_id: str
tank_id: str
water_plant_output_id: str
time_delta: Optional[int] = 300
@app.post("/daily_scheduling_analysis/")
async def fastapi_daily_scheduling_analysis(data: DailySchedulingAnalysis) -> str:
data = data.dict()
filename = 'c:/lock.simulation'
filename2 = 'c:/lock.simulation2'
if os.path.exists(filename2):
print('file exists')
raise HTTPException(status_code=409, detail="is in simulation")
else:
print('file doesnt exists')
#os.rename(filename, filename2)
result = daily_scheduling_simulation(data['network'], data['start_time'],
data['pump_control'], data['reservoir_id'], data['tank_id'],
data['water_plant_output_id'])
#os.rename(filename2, filename)
return result
############################################################
# network_update api 48
############################################################
@app.post("/network_update/")
async def fastapi_network_update(file: UploadFile = File()) -> str:
# 默认文件夹
default_folder = './'
# 使用当前时间生成临时文件名
temp_file_name = f'network_update_{datetime.now().strftime("%Y%m%d")}'
temp_file_path = os.path.join(default_folder, temp_file_name)
# 保存上传的文件到服务器
try:
with open(temp_file_path, "wb") as buffer:
shutil.copyfileobj(file.file, buffer)
buffer.close()
print(f"文件 {temp_file_name} 已成功保存。")
except Exception as e:
raise HTTPException(status_code=500, detail=f"文件保存失败: {e}")
# 更新数据库
try:
network_update(temp_file_path)
return json.dumps({"message": "管网更新成功"})
except Exception as e:
raise HTTPException(status_code=500, detail=f"数据库操作失败: {e}")
############################################################
# pump failure api 49
############################################################
class PumpFailureState(BaseModel):
time: str
pump_status: dict
@app.post("/pump_failure/")
async def fastapi_pump_failure(data: PumpFailureState) -> str:
item = data.dict()
with open('./pump_failure_message.txt', 'a', encoding='utf-8-sig') as f1:
f1.write('[{}] {}\n'.format(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), item)) # save message
status_info = item.copy()
with open('./pump_failure_status.txt', 'r', encoding='utf-8-sig') as f2:
lines = f2.readlines()
first_stage_pump_status_dict = json.loads(json.dumps(eval(lines[0])))
second_stage_pump_status_dict = json.loads(json.dumps(eval(lines[-1]))) # read local file
pump_status_dict = {'first': first_stage_pump_status_dict, # first-stage pump
'second': second_stage_pump_status_dict} # second-stage pump
for pump_type in status_info['pump_status'].keys(): # 'first' or 'second'
if pump_type in pump_status_dict.keys(): # the type of pumps exists
if all(pump_id in pump_status_dict[pump_type].keys()
for pump_id in status_info['pump_status'][pump_type].keys()): # all pump IDs exist
for pump_id in status_info['pump_status'][pump_type].keys():
pump_status_dict[pump_type][pump_id] = int(
status_info['pump_status'][pump_type][pump_id]) # modify status dict
else:
return json.dumps('ERROR: Wrong Pump ID')
else:
return json.dumps('ERROR: Wrong Pump Type')
with open('./pump_failure_status.txt', 'w', encoding='utf-8-sig') as f2_:
f2_.write('{}\n{}'.format(pump_status_dict['first'], pump_status_dict['second'])) # save local file
return json.dumps('SUCCESS')
# DingZQ, 2024-12-31, run main
# if __name__ == "__main__":
# generate_openapi_json()
# uvicorn.run(app, host="127.0.0.1", port=80)
# uvicorn.run(app, host="127.0.0.1", port=80)