优化influxdb链接,修改采集端和设备关联,添加告警功能相关表

iot
DESKTOP-1JS6RSM\Admin 3 months ago
parent 675d2fad8f
commit 191ef60413

@ -14,3 +14,6 @@ from .iot.iot_workshop import IotWorkshop, IotWorkshopSchema
from .iot.iot_device import IotDevice, IotDeviceSchema from .iot.iot_device import IotDevice, IotDeviceSchema
from .iot.iot_endpoint import IotEndpoint, IotEndpointSchema from .iot.iot_endpoint import IotEndpoint, IotEndpointSchema
from .iot.iot_node import IotNode, IotNodeSchema from .iot.iot_node import IotNode, IotNodeSchema
from .iot.iot_alert_rule import IotAlertRule, IotAlertRuleSchema
from .iot.iot_alert_log import IotAlertLog, IotAlertLogSchema
from .iot.iot_alert_push import IotAlertPush, IotAlertPushSchema

@ -0,0 +1,40 @@
from iti.applications.extensions import db
from iti.applications.common.crud import TimeModelMixin
from iti.applications.common.utils import BaseSchema
from apiflask.fields import String, Integer, DateTime, Nested
class IotAlertLog(db.Model, TimeModelMixin):
"""
告警日志表
"""
__tablename__ = "iot_alert_log"
id = db.Column(
db.Integer,
primary_key=True,
autoincrement=True,
comment="标识",
)
alert_tag = db.Column(db.String(255), nullable=False, comment="告警标签")
alert_target_name = db.Column(db.String(255), nullable=False, comment="告警对象名称")
alert_content = db.Column(db.String(2048), nullable=False, comment="告警文本")
alert_level = db.Column(db.Integer, nullable=False, comment="告警级别 0-预警,1-一般,2-紧急,3-严重")
status = db.Column(db.Integer, nullable=False, default=1, comment="状态 1-告警中,0-已恢复")
trigger_count = db.Column(db.Integer, nullable=False, default=0, comment="触发次数")
class IotAlertLogSchema(BaseSchema):
"""
告警日志表响应结构
"""
class Meta:
name = "IotAlertLog"
id = Integer()
alert_tag = String()
alert_target_name = String()
alert_content = String()
alert_level = Integer()
status = Integer()
trigger_count = Integer()
created_at = DateTime(format="%Y-%m-%d %H:%M:%S")
updated_at = DateTime(format="%Y-%m-%d %H:%M:%S")

@ -0,0 +1,31 @@
from iti.applications.extensions import db
from iti.applications.common.crud import TimeModelMixin
from iti.applications.common.utils import BaseSchema
from apiflask.fields import String, Integer, DateTime, Nested
class IotAlertPush(TimeModelMixin, db.Model):
"""
告警推送表
"""
__tablename__ = "iot_alert_push"
id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment="标识")
target_name = db.Column(db.String(255), nullable=False, comment="接收对象名称")
push_url = db.Column(db.String(2048), nullable=False, comment="告警推送URL")
alert_level = db.Column(db.String(255), nullable=False, comment="告警等级")
status = db.Column(db.Integer, nullable=False, default=1, comment="状态 1-启用,0-禁用")
class IotAlertPushSchema(BaseSchema):
"""
告警推送表响应结构
"""
class Meta:
name = "IotAlertPush"
id = Integer()
target_name = String()
push_url = String()
alert_level = String()
status = Integer()
created_at = DateTime(format="%Y-%m-%d %H:%M:%S")
updated_at = DateTime(format="%Y-%m-%d %H:%M:%S")

@ -0,0 +1,42 @@
from iti.applications.extensions import db
from iti.applications.common.crud import TimeModelMixin
from iti.applications.common.utils import BaseSchema
from apiflask.fields import String, Integer, DateTime, Nested
class IotAlertRule(db.Model, TimeModelMixin):
"""
告警规则表
"""
__tablename__ = "iot_alert_rule"
id = db.Column(
db.Integer,
primary_key=True,
autoincrement=True,
comment="标识",
)
rule_name = db.Column(db.String(255), nullable=False, comment="告警规则名称")
node_id = db.Column(db.Integer, nullable=False, comment="采集节点ID")
trigger_count = db.Column(db.Integer, nullable=False, comment="阈值触发次数,超过次数后告警")
alert_rule = db.Column(db.String(255), nullable=False, comment="告警触发表达式")
alert_text = db.Column(db.String(2048), nullable=False, comment="告警文本")
alert_level = db.Column(db.Integer, nullable=False, comment="告警级别 0-预警,1-一般,2-紧急,3-严重")
status = db.Column(db.Integer, nullable=False, default=1, comment="状态 1-启用,0-禁用")
class IotAlertRuleSchema(BaseSchema):
"""
告警规则表响应结构
"""
class Meta:
name = "IotAlertRule"
id = Integer()
rule_name = String()
node_id = Integer()
trigger_count = Integer()
alert_rule = String()
alert_text = String()
alert_level = Integer()
status = Integer()
created_at = DateTime(format="%Y-%m-%d %H:%M:%S")
updated_at = DateTime(format="%Y-%m-%d %H:%M:%S")

@ -16,8 +16,6 @@ class IotEndpoint(db.Model, TimeModelMixin):
autoincrement=True, autoincrement=True,
comment="标识", comment="标识",
) )
workshop_id = db.Column(db.Integer, nullable=False, default=0, unique=True, comment="车间ID")
device_id = db.Column(db.Integer, nullable=False, default=0, unique=True, comment="设备ID")
endpoint_name = db.Column(db.String(255), nullable=False, unique=True, comment="采集端名称") endpoint_name = db.Column(db.String(255), nullable=False, unique=True, comment="采集端名称")
endpoint_number = db.Column(db.String(20), nullable=False, comment="采集端编号") endpoint_number = db.Column(db.String(20), nullable=False, comment="采集端编号")
description = db.Column(db.Text, nullable=True, comment="采集端描述") description = db.Column(db.Text, nullable=True, comment="采集端描述")
@ -27,15 +25,6 @@ class IotEndpoint(db.Model, TimeModelMixin):
specification_model = db.Column(db.String(255), nullable=False, comment="规格型号") specification_model = db.Column(db.String(255), nullable=False, comment="规格型号")
is_online = db.Column(db.Integer, nullable=False, default=0, comment="在线状态 0:离线 1:在线") is_online = db.Column(db.Integer, nullable=False, default=0, comment="在线状态 0:离线 1:在线")
status = db.Column(db.Integer, nullable=False, default=0, comment="状态 0:停用 1:运行中 2:维修中") status = db.Column(db.Integer, nullable=False, default=0, comment="状态 0:停用 1:运行中 2:维修中")
#关系
workshop = db.relationship(
"IotWorkshop",
primaryjoin="foreign(IotEndpoint.workshop_id) == IotWorkshop.id",
)
device = db.relationship(
"IotDevice",
primaryjoin="foreign(IotEndpoint.device_id) == IotDevice.id",
)
class IotEndpointSchema(BaseSchema): class IotEndpointSchema(BaseSchema):
@ -46,8 +35,6 @@ class IotEndpointSchema(BaseSchema):
name = "IotEndpoint" name = "IotEndpoint"
id = Integer() id = Integer()
workshop_id = Integer()
device_id = Integer()
endpoint_name = String() endpoint_name = String()
endpoint_number = String() endpoint_number = String()
description = String() description = String()
@ -59,9 +46,6 @@ class IotEndpointSchema(BaseSchema):
status = Integer() status = Integer()
created_at = DateTime(format="%Y-%m-%d %H:%M:%S") created_at = DateTime(format="%Y-%m-%d %H:%M:%S")
updated_at = DateTime(format="%Y-%m-%d %H:%M:%S") updated_at = DateTime(format="%Y-%m-%d %H:%M:%S")
#关系
workshop = Nested("IotWorkshopSimpleSchema")
device = Nested("IotDeviceSimpleSchema")
class IotEndpointSimpleSchema(BaseSchema): class IotEndpointSimpleSchema(BaseSchema):

@ -3,6 +3,9 @@ from .workshop_ctl import bp as workshop_bp
from .device_ctl import bp as device_bp from .device_ctl import bp as device_bp
from .endpoint_ctl import bp as endpoint_bp from .endpoint_ctl import bp as endpoint_bp
from .node_ctl import bp as node_bp from .node_ctl import bp as node_bp
from .alert_rule_ctl import bp as alert_rule_bp
from .alert_log_ctl import bp as alert_log_bp
from .alert_push_ctl import bp as alert_push_bp
iot_bp = APIBlueprint("iot", __name__, url_prefix="/iot") iot_bp = APIBlueprint("iot", __name__, url_prefix="/iot")
@ -12,5 +15,8 @@ def register_iot_bp(app):
iot_bp.register_blueprint(device_bp) iot_bp.register_blueprint(device_bp)
iot_bp.register_blueprint(endpoint_bp) iot_bp.register_blueprint(endpoint_bp)
iot_bp.register_blueprint(node_bp) iot_bp.register_blueprint(node_bp)
iot_bp.register_blueprint(alert_rule_bp)
iot_bp.register_blueprint(alert_log_bp)
iot_bp.register_blueprint(alert_push_bp)
app.register_blueprint(iot_bp) app.register_blueprint(iot_bp)

@ -0,0 +1,96 @@
from apiflask import APIBlueprint
from iti.applications.service.iot.alert import add_endpoint_alert_log
from iti.applications.extensions import db
from iti.applications.common.utils import success, page_schema, page
from iti.applications.models import (
IotAlertLog,
IotAlertLogSchema,
)
from .schemas.alert_log import (
AlertLogQuery,
AlertLogAddRequest,
AlertLogUpdateRequest,
)
from iti.applications.common import ModelFilter
from iti.applications.common.exceptions.biz_exp import BizException
from flask_jwt_extended import jwt_required
from sqlalchemy import select, delete, exists
from sqlalchemy.sql.functions import func
from sqlalchemy.orm import noload
from iti.applications.common import permission
bp = APIBlueprint("iot_alert_log", __name__, url_prefix="/alertLog", tag="告警中心")
@bp.get("/list")
@jwt_required()
@bp.doc(security="JWT")
@permission("iot:alertLog:list")
@bp.input(AlertLogQuery.Schema(partial=True), location="query")
@bp.output(IotAlertLogSchema(many=True))
def list_alert_log(query_data: AlertLogQuery):
"""
获取告警日志列表
"""
return success(get_list_or_page(query_data))
@bp.get("/page")
@jwt_required()
@bp.doc(security="JWT")
@permission("iot:alertLog:list")
@bp.input(AlertLogQuery.Schema(partial=True), location="query")
@bp.output(page_schema(IotAlertLogSchema))
def page_alert_log(query_data: AlertLogQuery):
"""
获取告警日志分页列表
"""
return success(get_list_or_page(query_data))
@bp.post("/add/<int:endpoint_id>")
# @jwt_required()
# @bp.doc(security="JWT")
# @permission("iot:alertLog:add")
def add_alert_log(endpoint_id: int):
"""
添加采集端网络不可达告警日志
"""
result = add_endpoint_alert_log(endpoint_id)
if len(result) > 0:
raise BizException(result)
return success()
@bp.post("/recover/<int:id>")
@jwt_required()
@bp.doc(security="JWT")
@permission("iot:alertLog:update")
def recover_alert_log(id: int):
"""
恢复告警日志
"""
alert_log = db.session.scalar(select(IotAlertLog).filter_by(id=id))
if not alert_log:
raise BizException("告警日志不存在")
alert_log.trigger_count =0
alert_log.status = 0
db.session.commit()
return success()
def get_list_or_page(query_data: AlertLogQuery):
"""
获取告警日志列表
"""
query = select(IotAlertLog).order_by(IotAlertLog.created_at.desc())
if query_data.alert_tag is not None:
query = query.filter(IotAlertLog.alert_tag == query_data.alert_tag)
if query_data.status is not None:
query = query.filter(IotAlertLog.status == query_data.status)
if query_data.page and query_data.size:
return db.paginate(query, page=query_data.page, per_page=query_data.size)
else:
return db.session.scalars(query).all()

@ -0,0 +1,83 @@
from apiflask import APIBlueprint
from iti.applications.extensions import db, sys_log
from iti.applications.common.utils import success, page_schema, page
from iti.applications.models import (
IotAlertPush,
IotAlertPushSchema,
)
from .schemas.alert_push import (
AlertPushQuery,
AlertPushAddRequest,
AlertPushUpdateRequest,
)
from iti.applications.common import ModelFilter
from iti.applications.common.exceptions.biz_exp import BizException
from flask_jwt_extended import jwt_required
from sqlalchemy import select, delete, exists
from sqlalchemy.sql.functions import func
from sqlalchemy.orm import noload
from iti.applications.common import permission
bp = APIBlueprint("iot_alert_push", __name__, url_prefix="/alertPush", tag="消息通知")
@bp.get("/list")
@jwt_required()
@bp.doc(security="JWT")
@permission("iot:alertPush:list")
@bp.input(AlertPushQuery.Schema(partial=True), location="query")
@bp.output(IotAlertPushSchema(many=True))
def list_alert_push(query_data: AlertPushQuery):
"""
获取消息通知列表
"""
return success(get_list_or_page(query_data))
@bp.get("/page")
@jwt_required()
@bp.doc(security="JWT")
@permission("iot:alertPush:list")
@bp.input(AlertPushQuery.Schema(partial=True), location="query")
@bp.output(page_schema(IotAlertPushSchema))
def page_alert_push(query_data: AlertPushQuery):
"""
获取消息通知分页列表
"""
return success(get_list_or_page(query_data))
@bp.post("/add")
@jwt_required()
@bp.doc(security="JWT")
@permission("iot:alertPush:add")
@bp.input(AlertPushAddRequest,location="json")
def add_alert_push(json_data: dict):
"""
添加消息通知
"""
alert_push = IotAlertPush(**json_data)
alert_push.status = 0
db.session.add(alert_push)
db.session.commit()
return success()
def get_list_or_page(query_data: AlertPushQuery):
"""
获取消息通知列表
"""
query = select(IotAlertPush).order_by(IotAlertPush.created_at.desc())
if query_data.keyword:
kw = ModelFilter.escape_like(query_data.keyword)
query = query.filter(
IotAlertPush.target_name.like(f"%{kw}%")
)
if query_data.status is not None:
query = query.filter(IotAlertPush.status == query_data.status)
if query_data.page and query_data.size:
return db.paginate(query, page=query_data.page, per_page=query_data.size)
else:
return db.session.scalars(query).all()

@ -0,0 +1,21 @@
from apiflask import APIBlueprint
from iti.applications.extensions import db, sys_log
from iti.applications.common.utils import success, page_schema, page
from iti.applications.models import (
IotAlertRule,
IotAlertRuleSchema,
)
from .schemas.alert_rule import (
AlertRuleQuery,
AlertRuleAddRequest,
AlertRuleUpdateRequest,
)
from iti.applications.common import ModelFilter
from iti.applications.common.exceptions.biz_exp import BizException
from flask_jwt_extended import jwt_required
from sqlalchemy import select, delete, exists
from sqlalchemy.sql.functions import func
from sqlalchemy.orm import noload
from iti.applications.common import permission
bp = APIBlueprint("iot_alert_rule", __name__, url_prefix="/alertRule", tag="告警规则")

@ -33,7 +33,7 @@ def list_endpoint(query_data: EndpointQuery):
获取采集端列表 获取采集端列表
""" """
return success(get_list(query_data)) return success(get_list_or_page(query_data))
@bp.get("/page") @bp.get("/page")
@ -47,7 +47,7 @@ def page_endpoint(query_data: EndpointQuery):
分页获取采集端列表 分页获取采集端列表
""" """
return page(get_page(query_data)) return page(get_list_or_page(query_data))
@bp.post("/add") @bp.post("/add")
@ -72,10 +72,6 @@ def add_endpoint(json_data: dict):
raise BizException("同编号采集端已存在") raise BizException("同编号采集端已存在")
endpoint = IotEndpoint(**json_data) endpoint = IotEndpoint(**json_data)
device = db.session.scalar(select(IotDevice).options(noload(IotDevice.workshop)).filter_by(id = endpoint.device_id))
if not device:
raise BizException("设备信息不存在")
endpoint.workshop_id = device.workshop_id
endpoint.status = 0 endpoint.status = 0
db.session.add(endpoint) db.session.add(endpoint)
db.session.commit() db.session.commit()
@ -104,9 +100,7 @@ def update_endpoint(id: int, json_data: dict):
raise BizException("同编号采集端已存在") raise BizException("同编号采集端已存在")
endpoint = db.session.scalar( endpoint = db.session.scalar(
select(IotEndpoint) select(IotEndpoint).filter_by(id=id))
.options(noload(IotEndpoint.workshop), noload(IotEndpoint.device))
.filter_by(id=id))
if not endpoint: if not endpoint:
raise BizException("采集端信息不存在") raise BizException("采集端信息不存在")
for key, value in json_data.items(): for key, value in json_data.items():
@ -128,7 +122,6 @@ def delete_endpoint(id: int):
endpoint = db.session.scalar( endpoint = db.session.scalar(
select(IotEndpoint) select(IotEndpoint)
.options(noload(IotEndpoint.workshop), noload(IotEndpoint.device))
.filter_by(id=id)) .filter_by(id=id))
if not endpoint: if not endpoint:
raise BizException("采集端不存在") raise BizException("采集端不存在")
@ -158,43 +151,21 @@ def count_endpoint():
return success(countData) return success(countData)
def get_page(query_data: EndpointQuery):
"""
获取采集端信息分页
"""
query = select(IotEndpoint).order_by(IotEndpoint.created_at.desc())
if query_data.keyword:
kw = ModelFilter.escape_like(query_data.keyword)
query = query.filter(
IotEndpoint.endpoint_name.like(f"%{kw}%")
| IotEndpoint.endpoint_number.like(f"%{kw}%")
)
if query_data.device_id:
query = query.filter(IotEndpoint.device_id == query_data.device_id)
elif query_data.workshop_id:
query = query.filter(IotEndpoint.workshop_id == query_data.workshop_id)
if query_data.status is not None:
query = query.filter(IotEndpoint.status == query_data.status)
return db.paginate(query, page=query_data.page, per_page=query_data.size) def get_list_or_page(query_data: EndpointQuery):
def get_list(query_data: EndpointQuery):
""" """
获取采集端信息列表 获取采集端信息列表
""" """
query = select(IotEndpoint).options(noload(IotEndpoint.device), noload(IotEndpoint.workshop)).order_by(IotEndpoint.created_at.desc()) query = select(IotEndpoint).order_by(IotEndpoint.created_at.desc())
if query_data.keyword: if query_data.keyword:
kw = ModelFilter.escape_like(query_data.keyword) kw = ModelFilter.escape_like(query_data.keyword)
query = query.filter( query = query.filter(
IotEndpoint.endpoint_name.like(f"%{kw}%") IotEndpoint.endpoint_name.like(f"%{kw}%")
| IotEndpoint.endpoint_number.like(f"%{kw}%") | IotEndpoint.endpoint_number.like(f"%{kw}%")
) )
if query_data.device_id:
query = query.filter(IotEndpoint.device_id == query_data.device_id)
elif query_data.workshop_id:
query = query.filter(IotEndpoint.workshop_id == query_data.workshop_id)
if query_data.status is not None: if query_data.status is not None:
query = query.filter(IotEndpoint.status == query_data.status) query = query.filter(IotEndpoint.status == query_data.status)
if query_data.page and query_data.size:
return db.session.scalars(query).all() return db.paginate(query, page=query_data.page, per_page=query_data.size)
else:
return db.session.scalars(query).all()

@ -18,6 +18,7 @@ from iti.applications.common import ModelFilter
from iti.applications.common.exceptions.biz_exp import BizException from iti.applications.common.exceptions.biz_exp import BizException
from flask_jwt_extended import jwt_required from flask_jwt_extended import jwt_required
from sqlalchemy import select, delete, exists from sqlalchemy import select, delete, exists
from sqlalchemy.sql.functions import func
from sqlalchemy.orm import noload from sqlalchemy.orm import noload
from iti.applications.common import permission from iti.applications.common import permission
@ -51,6 +52,23 @@ def page_node(query_data: NodeQuery):
return page(get_page(query_data)) return page(get_page(query_data))
@bp.get("/count")
@jwt_required()
@bp.doc(security="JWT")
@permission("iot:node:list")
def count_node():
"""
统计采集节点数量
"""
countData = {}
nodeReady = db.session.query(func.count(IotNode.id).label('number')).filter_by(status=1).first().number
nodeUnready = db.session.query(func.count(IotNode.id).label('number')).filter_by(status=0).first().number
countData["ready"] = nodeReady
countData["unReady"] = nodeUnready
countData["total"] = nodeReady + nodeUnready
return success(countData)
@bp.post("/add") @bp.post("/add")
@jwt_required() @jwt_required()
@ -158,7 +176,7 @@ def get_page(query_data: NodeQuery):
query = select(IotNode).order_by(IotNode.created_at.desc()) query = select(IotNode).order_by(IotNode.created_at.desc())
if query_data.endpoint_id: if query_data.endpoint_id:
query = query.filter(IotNode.endpoint_id == query_data.endpoint_id) query = query.filter(IotNode.endpoint_id == query_data.endpoint_id)
elif query_data.device_id: if query_data.device_id:
query = query.filter(IotNode.device_id == query_data.device_id) query = query.filter(IotNode.device_id == query_data.device_id)
elif query_data.workshop_id: elif query_data.workshop_id:
query = query.filter(IotNode.workshop_id == query_data.workshop_id) query = query.filter(IotNode.workshop_id == query_data.workshop_id)
@ -175,7 +193,7 @@ def get_list(query_data: NodeQuery):
query = select(IotNode).options(noload(IotNode.workshop), noload(IotNode.device), noload(IotNode.endpoint)).order_by(IotNode.created_at.desc()) query = select(IotNode).options(noload(IotNode.workshop), noload(IotNode.device), noload(IotNode.endpoint)).order_by(IotNode.created_at.desc())
if query_data.endpoint_id: if query_data.endpoint_id:
query = query.filter(IotNode.endpoint_id == query_data.endpoint_id) query = query.filter(IotNode.endpoint_id == query_data.endpoint_id)
elif query_data.device_id: if query_data.device_id:
query = query.filter(IotNode.device_id == query_data.device_id) query = query.filter(IotNode.device_id == query_data.device_id)
elif query_data.workshop_id: elif query_data.workshop_id:
query = query.filter(IotNode.workshop_id == query_data.workshop_id) query = query.filter(IotNode.workshop_id == query_data.workshop_id)

@ -0,0 +1,122 @@
from dataclasses import field
from marshmallow_dataclass import dataclass
from marshmallow import validates_schema, ValidationError
from iti.applications.common.utils.schema import BaseSchema, Pagination
from typing import ClassVar, Optional
from apiflask import fields
@dataclass(base_schema=BaseSchema)
class AlertLogQuery(Pagination):
"""
告警日志信息查询请求
"""
alert_tag: str = field(
default=None,
metadata={
"required": False,
"metadata": {"example": "ep1-nd0", "description": "告警标签"},
},
)
status: int = field(
default=None,
metadata={
"required": False,
"metadata": {"example": 0, "description": "状态"},
},
)
Schema: ClassVar[BaseSchema] = BaseSchema
class AlertLogAddRequest(BaseSchema):
"""
告警日志信息添加请求
"""
alert_tag = fields.String(
required=True,
metadata={
"example": "ep1-nd0",
"description": "告警标签",
},
)
alert_target_name = fields.String(
required=True,
metadata={
"example": "ep1-nd0",
"description": "告警对象名称",
},
)
trigger_count = fields.Integer(
required=True,
metadata={
"example": 1,
"description": "触发次数",
},
)
status = fields.Integer(
required=True,
metadata={
"example": 0,
"description": "状态",
},
)
alert_content = fields.String(
required=True,
metadata={
"example": "ep1-nd0",
"description": "告警内容",
},
)
alert_level = fields.Integer(
required=True,
metadata={
"example": 0,
"description": "告警级别",
},
)
class AlertLogUpdateRequest(BaseSchema):
"""
告警日志信息更新请求
"""
alert_tag = fields.String(
required=True,
metadata={
"example": "ep1-nd0",
"description": "告警标签",
},
)
alert_target_name = fields.String(
required=True,
metadata={
"example": "ep1-nd0",
"description": "告警对象名称",
},
)
trigger_count = fields.Integer(
required=True,
metadata={
"example": 1,
"description": "触发次数",
},
)
status = fields.Integer(
required=True,
metadata={
"example": 0,
"description": "状态",
},
)
alert_content = fields.String(
required=True,
metadata={
"example": "ep1-nd0",
"description": "告警内容",
},
)
alert_level = fields.Integer(
required=True,
metadata={
"example": 0,
"description": "告警级别",
},
)

@ -0,0 +1,80 @@
from dataclasses import field
from marshmallow_dataclass import dataclass
from marshmallow import validates_schema, ValidationError
from iti.applications.common.utils.schema import BaseSchema, Pagination
from typing import ClassVar, Optional
from apiflask import fields
@dataclass(base_schema=BaseSchema)
class AlertPushQuery(Pagination):
"""
告警推送信息查询请求
"""
keyword: Optional[str] = field(
default=None,
metadata={
"required": False,
"metadata": {
"description": "关键字 [消息对象名称] 模糊查询"
},
},
)
status: int = field(
default=None,
metadata={
"required": False,
"metadata": {"example": 0, "description": "状态"},
},
)
Schema: ClassVar[BaseSchema] = BaseSchema
class AlertPushAddRequest(BaseSchema):
"""
告警推送信息添加请求
"""
target_name = fields.String(
required=True,
metadata={
"example": "ERP",
"description": "告警对象名称",
},
)
push_url = fields.String(
required=True,
metadata={
"example": "https://www.baidu.com",
"description": "告警推送URL",
},
)
status = fields.Integer(
required=False,
metadata={
"example": 1,
"description": "状态 0-禁用,1-启用",
},
load_default=1,
)
class AlertPushUpdateRequest(BaseSchema):
"""
告警推送信息更新请求
"""
target_name = fields.String(
required=True,
metadata={
"example": "ERP",
"description": "告警对象名称",
},
)
push_url = fields.String(
required=True,
metadata={
"example": "https://www.baidu.com",
"description": "告警推送URL",
},
)
status = fields.Integer(
required=False,
metadata={"example": 1, "description": "状态 0-禁用,1-启用"},
load_default=1,
)

@ -0,0 +1,100 @@
from dataclasses import field
from marshmallow_dataclass import dataclass
from marshmallow import validates_schema, ValidationError
from iti.applications.common.utils.schema import BaseSchema, Pagination
from typing import ClassVar, Optional
from apiflask import fields
@dataclass(base_schema=BaseSchema)
class AlertRuleQuery(Pagination):
"""
告警规则信息查询请求
"""
node_id: int = field(
default=None,
metadata={
"required": False,
"metadata": {"example": 1, "description": "节点ID"},
},
)
status: int = field(
default=None,
metadata={
"required": False,
"metadata": {"example": 0, "description": "状态"},
},
)
Schema: ClassVar[BaseSchema] = BaseSchema
class AlertRuleAddRequest(BaseSchema):
"""
告警规则信息添加请求
"""
node_id = fields.Integer(
required=True,
metadata={"example": 1, "description": "节点ID"},
)
rule_name = fields.String(
required=True,
metadata={"example": "告警规则1", "description": "告警规则名称"},
)
alert_rule = fields.String(
required=True,
metadata={"example": "x<4", "description": "告警规则表达式"},
)
alert_text = fields.String(
required=False,
metadata={"example": "节点{{node.title}}告警内容", "description": "告警内容文本模板"},
)
alert_level = fields.Integer(
required=False,
metadata={"example": 0, "description": "告警级别 0-预警,1-一般,2-紧急,3-严重"},
load_default=0,
)
trigger_count = fields.Integer(
required=False,
metadata={"example": 1, "description": "阈值触发次数,超过次数后告警"},
load_default=1,
)
status = fields.Integer(
required=False,
metadata={"example": 1, "description": "状态 1-启用,0-禁用"},
load_default=1,
)
class AlertRuleUpdateRequest(BaseSchema):
"""
告警规则信息更新请求
"""
node_id = fields.Integer(
required=True,
metadata={"example": 1, "description": "节点ID"},
)
rule_name = fields.String(
required=False,
metadata={"example": "告警规则1", "description": "告警规则名称"},
)
alert_rule = fields.String(
required=False,
metadata={"example": "x<4", "description": "告警规则表达式"},
)
alert_text = fields.String(
required=False,
metadata={"example": "节点{{node.title}}告警内容", "description": "告警内容文本模板"},
)
alert_level = fields.Integer(
required=False,
metadata={"example": 0, "description": "告警级别 0-预警,1-一般,2-紧急,3-严重"},
)
trigger_count = fields.Integer(
required=False,
metadata={"example": 1, "description": "阈值触发次数,超过次数后告警"},
load_default=1,
)
status = fields.Integer(
required=False,
metadata={"example": 1, "description": "状态 1-启用,0-禁用"},
load_default=1,
)

@ -21,20 +21,6 @@ class EndpointQuery(Pagination):
}, },
}, },
) )
workshop_id: int = field(
default=None,
metadata={
"required": False,
"metadata": {"example": 1, "description": "车间ID"},
},
)
device_id: int = field(
default=None,
metadata={
"required": False,
"metadata": {"example": 1, "description": "设备ID"},
},
)
status: int = field( status: int = field(
default=None, default=None,
metadata={ metadata={
@ -50,10 +36,6 @@ class EndpointAddRequest(BaseSchema):
采集端新增信息 采集端新增信息
""" """
device_id = fields.Integer(
required=True,
metadata={"example": 1, "description": "设备ID"},
)
endpoint_name = fields.String( endpoint_name = fields.String(
required=True, required=True,
metadata={"example": "采集端名称", "descriptrion": "采集端名称"}, metadata={"example": "采集端名称", "descriptrion": "采集端名称"},
@ -92,10 +74,6 @@ class EndpointUpdateRequest(BaseSchema):
更新采集端信息 更新采集端信息
""" """
device_id = fields.Integer(
required=True,
metadata={"example": 1, "description": "设备ID"},
)
endpoint_name = fields.String( endpoint_name = fields.String(
required=True, required=True,
metadata={"example": "采集端名称", "descriptrion": "采集端名称"}, metadata={"example": "采集端名称", "descriptrion": "采集端名称"},

@ -0,0 +1,58 @@
from sqlalchemy.orm import noload
from sqlalchemy.sql._typing import ColumnExpressionArgument
from typing import List, Dict, Any, Optional, Set
from iti.applications.extensions import db
from flask import current_app
from iti.applications.models import (
IotAlertLog,
IotAlertRule,
IotAlertPush,
IotEndpoint,
)
from sqlalchemy import select, distinct
def add_endpoint_alert_log(endpoint_id: int):
"""
添加采集端告警日志
Args:
endpoint_id: 采集端ID
"""
endpoint = db.session.scalar(select(IotEndpoint).filter_by(id=endpoint_id))
if not endpoint:
return "采集端不存在"
alert_tag = f"ep{endpoint.id}_nd0"
alert_log = db.session.scalar(select(IotAlertLog).filter_by(alert_tag=alert_tag))
if alert_log:
alert_log.trigger_count += 1
if alert_log.trigger_count >= 3:
alert_log.status = 1
push_alert(alert_log)
else:
dict_data = dict(
alert_tag=alert_tag,
alert_target_name=f"{endpoint.endpoint_name}({endpoint.endpoint_number})",
alert_level=1,
status=0,
trigger_count=1,
alert_content=f"采集端 {endpoint.endpoint_name}({endpoint.endpoint_number}) 网络不可达",
)
alert_log = IotAlertLog(**dict_data)
db.session.add(alert_log)
db.session.commit()
return ""
def push_alert(alert_log: IotAlertLog):
"""
推送告警消息
Args:
alert_log: 告警日志
"""
level = f"{alert_log.alert_level}"
alert_push_list = db.session.scalars(select(IotAlertPush).filter(IotAlertPush.alert_level.contains(level))).all()
if alert_push_list:
for alert_push in alert_push_list:
# TODO 调用地址发送告警消息
current_app.logger.info(f"推送告警消息到 {alert_push.push_url},内容:{alert_log.alert_content}")

@ -102,7 +102,7 @@ class InfluxDBMgr:
if not hasattr(self, '_query_api') or not self._query_api: if not hasattr(self, '_query_api') or not self._query_api:
self._query_api = self.client.query_api() self._query_api = self.client.query_api()
test_query = f'from(bucket: "{self.bucket}") |> range(start: -1m) |> limit(n: 1)' test_query = f'from(bucket: "{self.bucket}") |> range(start: -5s) |> limit(n: 1)'
self._query_api.query(test_query) self._query_api.query(test_query)
return True return True
except Exception as e: except Exception as e:
@ -154,7 +154,7 @@ class InfluxDBMgr:
flux_query = f''' flux_query = f'''
from(bucket: "{self.bucket}") from(bucket: "{self.bucket}")
|> range(start: -15m) |> range(start: -5m)
|> filter(fn: (r) => r._measurement == "{query_measurement}") |> filter(fn: (r) => r._measurement == "{query_measurement}")
|> filter(fn: (r) => r._field == "{query_field}") |> filter(fn: (r) => r._field == "{query_field}")
|> yield(name: "mean") |> yield(name: "mean")

Loading…
Cancel
Save