commit 839d42549e26afc1529c8d11a9f80fc59a2bb799 Author: xyj <10908227994@qq.com> Date: Fri Dec 1 09:21:23 2023 +0800 first diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..da0415a --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..50b418a --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,26 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/lot_manager.iml b/.idea/lot_manager.iml new file mode 100644 index 0000000..f0c20fd --- /dev/null +++ b/.idea/lot_manager.iml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..419a75c --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..890d108 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/MQTT.py b/MQTT.py new file mode 100644 index 0000000..55a29ed --- /dev/null +++ b/MQTT.py @@ -0,0 +1,45 @@ +import json + +import paho.mqtt.client as mqtt + +from tool import push_stream, close_stream, update, exec_sh + + +# Connection success callback +def on_connect(client, userdata, flags, rc): + print(rc) + if rc == 0: + client.subscribe('lot_data') + else: + client.publish('conn_error', payload=rc, qos=0) + + +# Message receiving callback +def on_message(client, userdata, msg): + data = json.loads(msg.payload.decode('utf-8'))["msg"] + if data == "push_stream": + # TODO 启动推流视频 + push_stream() + elif data == "close_stream": + # TODO 关闭推流视频 + close_stream() + elif data == "exec": + # TODO 执行命令 更新配置 + exec_sh() + elif data == "update": + # TODO git更新项目 + update() + else: + client.publish('conn_error', payload='No Such Type', qos=0) + + +if __name__ == '__main__': + client = mqtt.Client() + client.username_pw_set("ceshi", "123456") + # Specify callback function + client.on_connect = on_connect + client.on_message = on_message + # Establish a connection + client.connect('ceshi-mqtt.lihaink.cn', 1883) + # Publish a message + client.loop_forever() diff --git a/__pycache__/api.cpython-310-pytest-7.4.3.pyc b/__pycache__/api.cpython-310-pytest-7.4.3.pyc new file mode 100644 index 0000000..44b7cbc Binary files /dev/null and b/__pycache__/api.cpython-310-pytest-7.4.3.pyc differ diff --git a/__pycache__/tool.cpython-310.pyc b/__pycache__/tool.cpython-310.pyc new file mode 100644 index 0000000..a2d715a Binary files /dev/null and b/__pycache__/tool.cpython-310.pyc differ diff --git a/api.py b/api.py new file mode 100644 index 0000000..700092a --- /dev/null +++ b/api.py @@ -0,0 +1,99 @@ +import os +import subprocess + +import uvicorn +from db.models.base import BaseResponse +from db.models.log_data_model import LOT_DATA +from db.repository import add_kb_to_db, get_kb_detail, get_kb_detail_by_time, delete_kb_detail_by_time + +from fastapi import FastAPI + +app = FastAPI() + + +@app.post("/add/lot_data/{device_name}") +async def add(data: LOT_DATA, device_name: str): + try: + add_kb_to_db(data, device_name) + return BaseResponse() + except Exception as e: + return BaseResponse(code=500, msg=e) + + +@app.get("/get/all/lot_data") +async def get_data(): + try: + data = get_kb_detail() + return BaseResponse(data=data) + except Exception as e: + return BaseResponse(code=404, msg=e) + + +@app.get("/get/data/by/time") +async def get_data(start_time, end_time): + try: + data = get_kb_detail_by_time(start_time, end_time) + return BaseResponse(data=data) + except Exception as e: + return BaseResponse(code=404, msg=e) + + +@app.get("/delete/data/by/time") +async def delete_data(start_time, end_time): + try: + data = delete_kb_detail_by_time(start_time, end_time) + return BaseResponse(data=data) + except Exception as e: + return BaseResponse(code=404, msg=e) + + +@app.get("/create/db") +async def create(): + from db.base import Base, engine + try: + Base.metadata.create_all(bind=engine) + return BaseResponse() + except Exception as e: + return BaseResponse(code=404, msg=e) + + +@app.get("/start") +def device_test(): + ## 不管有没有都进行一个杀死 + # os.popen() + # stop_cmd = r'kill -9 `lsof -t -i:554`' + # os.system(stop_cmd) + start_cmd = r'nohup ffmpeg -rtsp_transport tcp -re -i rtsp://admin:123456@192.168.0.226:554/mpeg4 -c:v copy -c:a aac -preset ultrafast -r 20 -flvflags no_duration_filesize -f rtsp -rtsp_transport tcp rtsp://127.0.0.1/live/test > app.out 2>&1 & echo $! > app.pid' + p = subprocess.Popen(start_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = p.communicate() + return_code = p.returncode + if return_code == 0: + return BaseResponse(code=return_code, msg=out, + data="http://192.168.1.27/live/test.live.mp4?secret=gqig2yFKkDpIMic1uWZY1L5MsIo0eflm") + else: + return BaseResponse(code=return_code, msg=err) + + +@app.get("/stop") +async def device_test2(): + ## 不管有没有都进行一个杀死 + cmd = 'lsof -t -i:554' + p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + # 获取执行结果 + out, err = p.communicate() + # 获取返回值 + return_code = p.returncode + if out == b'': + print("失败") + else: + pid = out + cmd = f'kill -9 {pid}' + print(pid) + os.system(cmd) + if return_code == 0: + return BaseResponse(code=return_code, msg=out) + return BaseResponse(code=return_code, msg=err) + + +if __name__ == '__main__': + uvicorn.run(app, host="127.0.0.1", port=8000) diff --git a/conf/mqtt.conf b/conf/mqtt.conf new file mode 100644 index 0000000..e992409 --- /dev/null +++ b/conf/mqtt.conf @@ -0,0 +1,10 @@ +[program:mqtt] +directory=/home/lihai/PycharmProjects/pythonProject/lot_manager +command=/home/lihai/anaconda3/envs/chatchat/bin/python MQTT.py +user=lihai +autostart=true +autorestart=true +redirect_stderr=true +stopsignal=TERM +stopasgroup=True +priority=1 \ No newline at end of file diff --git a/conf/push_stream.conf b/conf/push_stream.conf new file mode 100644 index 0000000..f2311da --- /dev/null +++ b/conf/push_stream.conf @@ -0,0 +1,9 @@ +[program:push_stream] +directory=/home/lihai/PycharmProjects/pythonProject/lot_manager +command=/usr/bin/ffmpeg -rtsp_transport tcp -re -i rtsp://admin:123456@192.168.0.123:554/mpeg4 -c:v copy -c:a aac -preset ultrafast -r 20 -flvflags no_duration_filesize -f rtsp -rtsp_transport tcp rstp://47.108.186.87:554/live/test9 +user=lihai +autostart=true +autorestart=true +redirect_stderr=true +stopsignal=TERM +stopasgroup=True \ No newline at end of file diff --git a/db/__init__.py b/db/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/db/__pycache__/__init__.cpython-310.pyc b/db/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..69f4cfe Binary files /dev/null and b/db/__pycache__/__init__.cpython-310.pyc differ diff --git a/db/__pycache__/base.cpython-310.pyc b/db/__pycache__/base.cpython-310.pyc new file mode 100644 index 0000000..f5a57d1 Binary files /dev/null and b/db/__pycache__/base.cpython-310.pyc differ diff --git a/db/__pycache__/session.cpython-310.pyc b/db/__pycache__/session.cpython-310.pyc new file mode 100644 index 0000000..77ecb0a Binary files /dev/null and b/db/__pycache__/session.cpython-310.pyc differ diff --git a/db/base.py b/db/base.py new file mode 100755 index 0000000..f7e4b6c --- /dev/null +++ b/db/base.py @@ -0,0 +1,19 @@ +import os + +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta +from sqlalchemy.orm import sessionmaker + +import json +KB_ROOT_PATH = "./" +DB_ROOT_PATH = os.path.join(KB_ROOT_PATH, "lot_data.db") +SQLALCHEMY_DATABASE_URI = f"sqlite:///{DB_ROOT_PATH}" + +engine = create_engine( + SQLALCHEMY_DATABASE_URI, + json_serializer=lambda obj: json.dumps(obj, ensure_ascii=False), +) + +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +Base: DeclarativeMeta = declarative_base() diff --git a/db/models/__init__.py b/db/models/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/db/models/__pycache__/__init__.cpython-310.pyc b/db/models/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..17ff0d9 Binary files /dev/null and b/db/models/__pycache__/__init__.cpython-310.pyc differ diff --git a/db/models/__pycache__/base.cpython-310.pyc b/db/models/__pycache__/base.cpython-310.pyc new file mode 100644 index 0000000..94acc2b Binary files /dev/null and b/db/models/__pycache__/base.cpython-310.pyc differ diff --git a/db/models/__pycache__/log_data_model.cpython-310.pyc b/db/models/__pycache__/log_data_model.cpython-310.pyc new file mode 100644 index 0000000..df6fc00 Binary files /dev/null and b/db/models/__pycache__/log_data_model.cpython-310.pyc differ diff --git a/db/models/base.py b/db/models/base.py new file mode 100755 index 0000000..43c821d --- /dev/null +++ b/db/models/base.py @@ -0,0 +1,25 @@ +from datetime import datetime +from typing import Any, List + +import pydantic +from pydantic import BaseModel +from sqlalchemy import Column, DateTime, String, Integer + +from db.models.log_data_model import LOT_DATA_MODEL, LOT_DATA + + +class BaseResponse(BaseModel): + code: int = 200 + msg: str = "success" + data: Any = None + + +class BaseModel: + """ + 基础模型 + """ + id = Column(Integer, primary_key=True, index=True, comment="主键ID") + create_time = Column(DateTime, default=datetime.utcnow, comment="创建时间") + update_time = Column(DateTime, default=None, onupdate=datetime.utcnow, comment="更新时间") + create_by = Column(String, default=None, comment="创建者") + update_by = Column(String, default=None, comment="更新者") diff --git a/db/models/log_data_model.py b/db/models/log_data_model.py new file mode 100755 index 0000000..4d1c177 --- /dev/null +++ b/db/models/log_data_model.py @@ -0,0 +1,49 @@ +from pydantic import BaseModel, Field +from sqlalchemy import * +from db.base import Base + + +class LOT_DATA(BaseModel): + wind_speed: float = Field(None, description='风速:(0到30)m/s ') + wind_direction: float = Field(None, description='风向:0~360°') + ambient_temperature: float = Field(None, description='环境温度:℃') + ambient_humidity: float = Field(None, description='环境湿度:%RH') + carbon_dioxide: float = Field(None, description='二氧化碳:0~5000ppm') + ambient_air_pressure: float = Field(None, description='环境气压:0~120KPa') + rainfall: float = Field(None, description='雨量:mm') + ambient_lighting: float = Field(None, description='环境光照:0-65535Lux;0-20万Lux') + soil_temperature: float = Field(None, description='土壤温度:-40~80℃') + soil_moisture: float = Field(None, description='土壤湿度:0-100%RH') + soil_conductivity: float = Field(None, description='土壤电导率:0-20000μS/cm') + soil_PH: float = Field(None, description='土壤PH:3~9PH') + soil_potassium_phosphate_nitrogen: float = Field(None, description='土壤磷酸钾:氮的标准值在140-225mg/kg') + soil_potassium_phosphate_phosphorus: float = Field(None, description='土壤磷酸钾:磷的标准值在57-100mg/kg,') + soil_potassium_phosphate_potassium: float = Field(None, description='土壤磷酸钾:钾的标准值在106-150mg/kg') + + +class LOT_DATA_MODEL(Base): + """ + 物联网数据模型 + """ + __tablename__ = 'LOT_DATA_MODEL' + id = Column(Integer, primary_key=True, autoincrement=True, comment='ID') + device_name = Column(String(50), comment='设备编号', default="0") + create_time = Column(Integer, comment="创建时间") + wind_speed = Column(Float, comment='风速:(0到30)m/s ') + wind_direction = Column(Float, comment='风向:0~360°') + ambient_temperature = Column(Float, comment='环境温度:℃') + ambient_humidity = Column(Float, comment='环境湿度:%RH') + carbon_dioxide = Column(Float, comment='二氧化碳:0~5000ppm') + ambient_air_pressure = Column(Float, comment='环境气压:0~120KPa') + rainfall = Column(Float, comment='雨量:mm') + ambient_lighting = Column(Float, comment='环境光照:0-65535Lux;0-20万Lux') + soil_temperature = Column(Float, comment='土壤温度:-40~80℃') + soil_moisture = Column(Float, comment='土壤湿度:0-100%RH') + soil_conductivity = Column(Float, comment='土壤电导率:0-20000μS/cm') + soil_PH = Column(Float, comment='土壤PH:3~9PH') + soil_potassium_phosphate_nitrogen = Column(Float, comment='土壤磷酸钾:氮的标准值在140-225mg/kg') + soil_potassium_phosphate_phosphorus = Column(Float, comment='土壤磷酸钾:磷的标准值在57-100mg/kg,') + soil_potassium_phosphate_potassium = Column(Float, comment='土壤磷酸钾:钾的标准值在106-150mg/kg') + + def __repr__(self): + return f"LOT_DATA_MODEL(id={self.id}, wind_speed={self.wind_speed}, wind_direction={self.wind_direction}, ambient_temperature={self.ambient_temperature}, ambient_humidity={self.ambient_humidity}, carbon_dioxide={self.carbon_dioxide}, ambient_air_pressure={self.ambient_air_pressure}, rainfall={self.rainfall}, ambient_lighting={self.ambient_lighting}, soil_temperature={self.soil_temperature}, soil_moisture={self.soil_moisture}, soil_conductivity={self.soil_conductivity}, Soil_PH={self.soil_PH}, soil_potassium_phosphate_nitrogen={self.soil_potassium_phosphate_nitrogen}, soil_potassium_phosphate_phosphorus={self.soil_potassium_phosphate_phosphorus}, soil_potassium_phosphate_potassium={self.soil_potassium_phosphate_potassium})" diff --git a/db/repository/__init__.py b/db/repository/__init__.py new file mode 100755 index 0000000..747de98 --- /dev/null +++ b/db/repository/__init__.py @@ -0,0 +1 @@ +from .lot_data_repository import * diff --git a/db/repository/__pycache__/__init__.cpython-310.pyc b/db/repository/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..099b649 Binary files /dev/null and b/db/repository/__pycache__/__init__.cpython-310.pyc differ diff --git a/db/repository/__pycache__/lot_data_repository.cpython-310.pyc b/db/repository/__pycache__/lot_data_repository.cpython-310.pyc new file mode 100644 index 0000000..19f5d93 Binary files /dev/null and b/db/repository/__pycache__/lot_data_repository.cpython-310.pyc differ diff --git a/db/repository/lot_data_repository.py b/db/repository/lot_data_repository.py new file mode 100755 index 0000000..926ef86 --- /dev/null +++ b/db/repository/lot_data_repository.py @@ -0,0 +1,51 @@ +import time + +from db.models.log_data_model import LOT_DATA_MODEL, LOT_DATA +from db.session import with_session + + +@with_session +def add_kb_to_db(session, data: LOT_DATA, device_name: str): + # 创建知识库实例 + kb = LOT_DATA_MODEL(**data.__dict__, device_name=device_name, create_time=int(time.time())) + session.add(kb) + + +@with_session +def delete_kb_from_db(session, id): + kb = session.query(LOT_DATA_MODEL).filter_by(id=id).first() + if kb: + session.delete(kb) + return True + + +# 直接查询所有数据 +@with_session +def get_kb_detail(session): + all_data = session.query(LOT_DATA_MODEL).all() + data = [LOT_DATA(**d.__dict__) for d in all_data] + return data + + +# 根据时间查询数据 +@with_session +def get_kb_detail_by_time(session, start_time, end_time): + all_data = session.query(LOT_DATA_MODEL).filter( + start_time <= LOT_DATA_MODEL.create_time, LOT_DATA_MODEL.create_time <= end_time).all() + data = [LOT_DATA(**d.__dict__) for d in all_data] + return data + + +# 删除数据 +@with_session +def delete_kb_detail_by_time(session, start_time, end_time): + d = session.query(LOT_DATA_MODEL).filter(start_time <= LOT_DATA_MODEL.create_time, LOT_DATA_MODEL.create_time <= end_time).delete() + return d + + +# 查询数据 +@with_session +def get_data_by_field(session, field, value): + query = session.query(LOT_DATA_MODEL).filter(getattr(LOT_DATA_MODEL, field) == value) + result = query.all() + return result diff --git a/db/session.py b/db/session.py new file mode 100755 index 0000000..47cb59f --- /dev/null +++ b/db/session.py @@ -0,0 +1,46 @@ +from functools import wraps +from contextlib import contextmanager +from db.base import SessionLocal +from sqlalchemy.orm import Session + + +@contextmanager +def session_scope() -> Session: + """上下文管理器用于自动获取 Session, 避免错误""" + session = SessionLocal() + try: + yield session + session.commit() + except: + session.rollback() + raise + finally: + session.close() + + +def with_session(f): + @wraps(f) + def wrapper(*args, **kwargs): + with session_scope() as session: + try: + result = f(session, *args, **kwargs) + session.commit() + return result + except: + session.rollback() + raise + + return wrapper + + +def get_db() -> SessionLocal: + db = SessionLocal() + try: + yield db + finally: + db.close() + + +def get_db0() -> SessionLocal: + db = SessionLocal() + return db diff --git a/exec_sh.sh b/exec_sh.sh new file mode 100644 index 0000000..a9bf588 --- /dev/null +++ b/exec_sh.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/lot_data.db b/lot_data.db new file mode 100644 index 0000000..c438be4 Binary files /dev/null and b/lot_data.db differ diff --git a/reload_conf.sh b/reload_conf.sh new file mode 100644 index 0000000..f59097e --- /dev/null +++ b/reload_conf.sh @@ -0,0 +1,7 @@ +#!/bin/bash +#复制配置文件 +cp -r conf/*.conf /etc/supervisor/conf.d/ +# 重启所有配置 +supervisorctl reload +# 推流不启动 +supervisorctl stop push_stream diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..0bfef0a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +pydantic~=1.10.13 +sqlalchemy~=2.0.19 +uvicorn~=0.23.2 +fastapi~=0.95.1 +paho-mqtt~=1.6.1 +requests~=2.31.0 \ No newline at end of file diff --git a/start_push.sh b/start_push.sh new file mode 100644 index 0000000..ed60632 --- /dev/null +++ b/start_push.sh @@ -0,0 +1,2 @@ +#!/bin/bash +supervisorctl start push_stream \ No newline at end of file diff --git a/stop_push.sh b/stop_push.sh new file mode 100644 index 0000000..fc96a8f --- /dev/null +++ b/stop_push.sh @@ -0,0 +1,2 @@ +#!/bin/bash +supervisorctl stop push_stream \ No newline at end of file diff --git a/test.py b/test.py new file mode 100644 index 0000000..cd750d7 --- /dev/null +++ b/test.py @@ -0,0 +1,26 @@ +import datetime +import time + +import requests + +while (True): + print(time.time()) + time.sleep(10.0) +# data = { +# "wind_speed": 26, +# "wind_direction": 6, +# "ambient_temperature": 66, +# "ambient_humidity": 78, +# "carbon_dioxide": 94, +# "ambient_air_pressure": 48, +# "rainfall": 3, +# "ambient_lighting": 59, +# "soil_temperature": 71, +# "soil_moisture": 19, +# "soil_conductivity": 62, +# "soil_PH": 49, +# "soil_potassium_phosphate_nitrogen": 5, +# "soil_potassium_phosphate_phosphorus": 5, +# "soil_potassium_phosphate_potassium": 86 +# } +# requests.post("http://192.168.1.27:8000/add/lot_data", json=data) diff --git a/tool.py b/tool.py new file mode 100644 index 0000000..647c333 --- /dev/null +++ b/tool.py @@ -0,0 +1,18 @@ +import subprocess + + +def push_stream(): + print("启动推流") + subprocess.Popen(['start_push.sh'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + +def close_stream(): + subprocess.Popen(['stop_push.sh'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + +def exec_sh(): + subprocess.Popen(['exec_sh.sh'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + +def update(): + subprocess.Popen(['update.sh'], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) diff --git a/update.sh b/update.sh new file mode 100644 index 0000000..35b0308 --- /dev/null +++ b/update.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +# TODO git更新 +git pull \ No newline at end of file