package data import ( "context" "fmt" "strconv" "strings" "time" "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "fwh-toolbox-server/cmd/mcp/tools/helper" "fwh-toolbox-server/domain" "fwh-toolbox-server/dto" "fwh-toolbox-server/repositories" ) func registerFwhApiTools(s *server.MCPServer) { // 站点信息 s.AddTool( mcp.NewTool("data_fwh_query_site_base_info_list", mcp.WithDescription("查询站点基本信息列表(FWH Pro API)"), mcp.WithString("sn", mcp.Description("站点SN,多个用逗号分隔")), mcp.WithNumber("page", mcp.Description("页码,默认1")), mcp.WithNumber("size", mcp.Description("每页数量,默认20")), ), handleFwhQuerySiteBaseInfoList, ) s.AddTool( mcp.NewTool("data_fwh_query_site_list", mcp.WithDescription("查询站点列表(FWH Pro API,支持SN搜索)"), mcp.WithString("sn", mcp.Description("站点SN搜索")), mcp.WithNumber("page", mcp.Description("页码,默认1")), mcp.WithNumber("size", mcp.Description("每页数量,默认20")), ), handleFwhQuerySiteList, ) s.AddTool( mcp.NewTool("data_fwh_query_site_mode_info", mcp.WithDescription("查询站点工作模式信息(FWH Pro API)"), mcp.WithString("sn", mcp.Required(), mcp.Description("站点SN")), ), handleFwhQuerySiteModeInfo, ) s.AddTool( mcp.NewTool("data_fwh_query_site_power_flow", mcp.WithDescription("查询站点指定日期的功率流数据(FWH Pro API)"), mcp.WithString("sn", mcp.Required(), mcp.Description("站点SN")), mcp.WithString("date", mcp.Required(), mcp.Description("日期,格式 yyyy-MM-dd")), ), handleFwhQuerySitePowerFlow, ) // 告警相关 s.AddTool( mcp.NewTool("data_fwh_query_site_alarm_list", mcp.WithDescription("查询站点当前告警列表(FWH Pro API)"), mcp.WithString("sn", mcp.Required(), mcp.Description("站点SN")), ), handleFwhQuerySiteAlarmList, ) s.AddTool( mcp.NewTool("data_fwh_query_event_alarm_list", mcp.WithDescription("查询站点时间范围内的事件/告警日志(FWH Pro API)。注意:大时间范围查询可能较慢"), mcp.WithString("sn", mcp.Required(), mcp.Description("站点SN")), mcp.WithString("start_time", mcp.Required(), mcp.Description("开始时间,格式 yyyy-MM-dd HH:mm:ss")), mcp.WithString("end_time", mcp.Required(), mcp.Description("结束时间,格式 yyyy-MM-dd HH:mm:ss")), mcp.WithString("type", mcp.Description("类型:all(默认)、event、alarm")), ), handleFwhQueryEventAlarmList, ) s.AddTool( mcp.NewTool("data_fwh_query_alarm_snapshot", mcp.WithDescription("查询站点告警快照信息(FWH Pro API)"), mcp.WithString("sn", mcp.Required(), mcp.Description("站点SN")), mcp.WithString("date", mcp.Required(), mcp.Description("日期,格式 yyyy-MM-dd")), ), handleFwhQueryAlarmSnapshot, ) s.AddTool( mcp.NewTool("data_fwh_query_alarm_statistics", mcp.WithDescription("查询实时告警统计数据(FWH Pro API)"), mcp.WithNumber("country", mcp.Description("国家ID: 0-全部(默认), 2-美国, 3-澳大利亚")), mcp.WithNumber("page", mcp.Description("页码,默认1")), ), handleFwhQueryAlarmStatistics, ) s.AddTool( mcp.NewTool("data_fwh_query_alarm_statistics_from_code", mcp.WithDescription("按告警码查询触发站点列表(FWH Pro API)"), mcp.WithString("alarm_code", mcp.Required(), mcp.Description("告警码")), mcp.WithNumber("country", mcp.Description("国家ID: 0-全部(默认), 2-美国, 3-澳大利亚")), mcp.WithNumber("page", mcp.Description("页码,默认1")), ), handleFwhQueryAlarmStatisticsFromCode, ) // MQTT日志 s.AddTool( mcp.NewTool("data_fwh_query_mqtt_log_list", mcp.WithDescription("查询站点时间范围内的MQTT日志(FWH Pro API)。注意:大时间范围查询可能较慢"), mcp.WithString("sn", mcp.Required(), mcp.Description("站点SN")), mcp.WithString("cmd_type", mcp.Required(), mcp.Description("MQTT命令类型(如 0, 101, 201 等)")), mcp.WithString("start_time", mcp.Required(), mcp.Description("开始时间,格式 yyyy-MM-dd HH:mm:ss")), mcp.WithString("end_time", mcp.Required(), mcp.Description("结束时间,格式 yyyy-MM-dd HH:mm:ss")), ), handleFwhQueryMqttLogList, ) // 停机列表 s.AddTool( mcp.NewTool("data_fwh_query_shutdown_list", mcp.WithDescription("查询Shutdown站点列表(FWH Pro API)"), mcp.WithString("date", mcp.Required(), mcp.Description("日期,格式 yyyy-MM-dd")), mcp.WithNumber("country", mcp.Description("国家ID: 0-全部(默认), 2-美国, 3-澳大利亚")), ), handleFwhQueryShutdownList, ) // EMS日志 s.AddTool( mcp.NewTool("data_fwh_query_ems_log_record", mcp.WithDescription("查询EMS日志召唤记录(FWH Pro API)"), mcp.WithString("sn", mcp.Required(), mcp.Description("站点SN")), ), handleFwhQueryEmsLogRecord, ) // 故障录波 s.AddTool( mcp.NewTool("data_fwh_query_fault_record_list", mcp.WithDescription("查询故障录波日志列表(FWH Pro API)"), mcp.WithString("sn", mcp.Required(), mcp.Description("站点SN")), mcp.WithString("start_time", mcp.Required(), mcp.Description("开始时间,格式 yyyy-MM-dd HH:mm:ss")), mcp.WithString("end_time", mcp.Required(), mcp.Description("结束时间,格式 yyyy-MM-dd HH:mm:ss")), ), handleFwhQueryFaultRecordList, ) s.AddTool( mcp.NewTool("data_fwh_query_fault_record_callable_list", mcp.WithDescription("查询设备可召唤的故障录波数据列表(FWH Pro API)"), mcp.WithString("sn", mcp.Required(), mcp.Description("设备SN(aGate/aPower/aHub)")), mcp.WithNumber("dev_type", mcp.Description("设备类型: 0-aPower, 1-aGate, 2-MPPT, 3-aHub(默认1)")), ), handleFwhQueryFaultRecordCallableList, ) s.AddTool( mcp.NewTool("data_fwh_query_fault_record_call_record_list", mcp.WithDescription("查询故障录波召唤记录(FWH Pro API)"), ), handleFwhQueryFaultRecordCallRecordList, ) s.AddTool( mcp.NewTool("data_fwh_query_fault_record_sub_list", mcp.WithDescription("查询故障录波子记录(FWH Pro API)"), mcp.WithString("fault_id", mcp.Required(), mcp.Description("故障录波记录ID")), ), handleFwhQueryFaultRecordSubList, ) // 系统升级 s.AddTool( mcp.NewTool("data_fwh_query_system_update_log", mcp.WithDescription("查询系统升级记录(FWH Pro API)"), mcp.WithString("sn", mcp.Required(), mcp.Description("站点SN")), ), handleFwhQuerySystemUpdateLog, ) s.AddTool( mcp.NewTool("data_fwh_query_system_update_log_detail", mcp.WithDescription("查询系统升级记录详细信息(FWH Pro API)"), mcp.WithString("order_id", mcp.Required(), mcp.Description("升级单ID")), ), handleFwhQuerySystemUpdateLogDetail, ) s.AddTool( mcp.NewTool("data_fwh_query_ahub_update_log", mcp.WithDescription("查询aHub升级记录(FWH Pro API)"), mcp.WithString("sn", mcp.Required(), mcp.Description("站点SN")), ), handleFwhQueryAHubUpdateLog, ) // TOU模板 s.AddTool( mcp.NewTool("data_fwh_query_tou_template_list", mcp.WithDescription("查询TOU模板列表(FWH Pro API)"), mcp.WithString("search", mcp.Description("搜索关键字")), mcp.WithNumber("page", mcp.Description("页码,默认1")), mcp.WithNumber("size", mcp.Description("每页数量,默认20")), ), handleFwhQueryTouTemplateList, ) s.AddTool( mcp.NewTool("data_fwh_query_tou_template_detail", mcp.WithDescription("查询TOU模板详情(FWH Pro API)"), mcp.WithString("id", mcp.Required(), mcp.Description("模板ID")), ), handleFwhQueryTouTemplateDetail, ) } // === Handlers === func handleFwhQuerySiteBaseInfoList(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { sn := req.GetString("sn", "") page := uint(req.GetFloat("page", 1)) size := uint(req.GetFloat("size", 20)) para := dto.SiteBaseInfoPara{ PageNum: page, PageSize: size, } if sn != "" { snList := strings.Split(sn, ",") para.SiteList = snList } data, err := repositories.QuerySiteBaseInfoList(para) if err != nil { return helper.ServiceError("查询站点基本信息列表", err), nil } return helper.JSONResult(data), nil } func handleFwhQuerySiteList(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { sn := req.GetString("sn", "") page := uint(req.GetFloat("page", 1)) size := uint(req.GetFloat("size", 20)) para := dto.SiteInfoPara{ PageNum: page, PageSize: size, } if sn != "" { para.SN = &sn } data, err := repositories.QuerySiteInfoList(para) if err != nil { return helper.ServiceError("查询站点列表", err), nil } return helper.JSONResult(data), nil } func handleFwhQuerySiteModeInfo(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { sn, err := req.RequireString("sn") if err != nil { return helper.ParamError("sn"), nil } data, err := repositories.QuerySiteModeInfo(sn) if err != nil { return helper.ServiceError("查询站点工作模式", err), nil } return helper.JSONResult(data), nil } func handleFwhQuerySitePowerFlow(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { sn, err := req.RequireString("sn") if err != nil { return helper.ParamError("sn"), nil } dateStr, err := req.RequireString("date") if err != nil { return helper.ParamError("date"), nil } day, err := time.Parse("2006-01-02", dateStr) if err != nil { return helper.ParamInvalidError("date", fmt.Sprintf("需要 yyyy-MM-dd 格式: %v", err)), nil } data, err := repositories.QuerySitePowerFlow(sn, day) if err != nil { return helper.ServiceError("查询功率流", err), nil } return helper.JSONResult(data), nil } func handleFwhQuerySiteAlarmList(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { sn, err := req.RequireString("sn") if err != nil { return helper.ParamError("sn"), nil } data, err := repositories.QuerySiteAlarmList(sn) if err != nil { return helper.ServiceError("查询站点告警列表", err), nil } return helper.JSONResult(data), nil } func handleFwhQueryEventAlarmList(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { sn, err := req.RequireString("sn") if err != nil { return helper.ParamError("sn"), nil } startTimeStr, err := req.RequireString("start_time") if err != nil { return helper.ParamError("start_time"), nil } endTimeStr, err := req.RequireString("end_time") if err != nil { return helper.ParamError("end_time"), nil } startTime, err := time.Parse(time.DateTime, startTimeStr) if err != nil { return helper.ParamInvalidError("start_time", fmt.Sprintf("需要 yyyy-MM-dd HH:mm:ss 格式: %v", err)), nil } endTime, err := time.Parse(time.DateTime, endTimeStr) if err != nil { return helper.ParamInvalidError("end_time", fmt.Sprintf("需要 yyyy-MM-dd HH:mm:ss 格式: %v", err)), nil } typeStr := req.GetString("type", "all") var eventAlarmType repositories.EventAlarmType switch typeStr { case "event": eventAlarmType = repositories.Event case "alarm": eventAlarmType = repositories.Alarm default: eventAlarmType = repositories.EventAndAlarm } data, err := repositories.QueryEventOrAlarmListOnTimeRange(sn, startTime, endTime, eventAlarmType) if err != nil { return helper.ServiceError("查询事件告警日志", err), nil } if len(data) == 0 { return helper.EmptyResult("查询结果为空"), nil } return helper.JSONResult(data), nil } func handleFwhQueryAlarmSnapshot(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { sn, err := req.RequireString("sn") if err != nil { return helper.ParamError("sn"), nil } dateStr, err := req.RequireString("date") if err != nil { return helper.ParamError("date"), nil } // 验证日期格式 if _, err := time.Parse("2006-01-02", dateStr); err != nil { return helper.ParamInvalidError("date", fmt.Sprintf("需要 yyyy-MM-dd 格式: %v", err)), nil } data, err := repositories.QueryAlarmSnapshotInfo(sn, dateStr) if err != nil { return helper.ServiceError("查询告警快照", err), nil } if len(data) == 0 { return helper.EmptyResult("查询结果为空"), nil } return helper.JSONResult(data), nil } func handleFwhQueryAlarmStatistics(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { country := domain.CountryType(int(req.GetFloat("country", 0))) page := int(req.GetFloat("page", 1)) data, err := repositories.QueryAlarmStatistics(country, page) if err != nil { return helper.ServiceError("查询实时告警统计", err), nil } return helper.JSONResult(data), nil } func handleFwhQueryAlarmStatisticsFromCode(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { alarmCode, err := req.RequireString("alarm_code") if err != nil { return helper.ParamError("alarm_code"), nil } country := domain.CountryType(int(req.GetFloat("country", 0))) page := int(req.GetFloat("page", 1)) data, err := repositories.QueryAlarmStatisticsFromCode(country, alarmCode, page) if err != nil { return helper.ServiceError("查询告警码统计", err), nil } return helper.JSONResult(data), nil } func handleFwhQueryMqttLogList(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { sn, err := req.RequireString("sn") if err != nil { return helper.ParamError("sn"), nil } cmdType, err := req.RequireString("cmd_type") if err != nil { return helper.ParamError("cmd_type"), nil } startTimeStr, err := req.RequireString("start_time") if err != nil { return helper.ParamError("start_time"), nil } endTimeStr, err := req.RequireString("end_time") if err != nil { return helper.ParamError("end_time"), nil } startTime, err := time.Parse(time.DateTime, startTimeStr) if err != nil { return helper.ParamInvalidError("start_time", fmt.Sprintf("需要 yyyy-MM-dd HH:mm:ss 格式: %v", err)), nil } endTime, err := time.Parse(time.DateTime, endTimeStr) if err != nil { return helper.ParamInvalidError("end_time", fmt.Sprintf("需要 yyyy-MM-dd HH:mm:ss 格式: %v", err)), nil } data, err := repositories.QueryMqttLogListOnTimeRange(sn, domain.MqttCmdType(cmdType), startTime, endTime) if err != nil { return helper.ServiceError("查询MQTT日志", err), nil } if len(data) == 0 { return helper.EmptyResult("查询结果为空"), nil } return helper.JSONResult(data), nil } func handleFwhQueryShutdownList(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { dateStr, err := req.RequireString("date") if err != nil { return helper.ParamError("date"), nil } country := int(req.GetFloat("country", 0)) // 验证日期格式 if _, err := time.Parse("2006-01-02", dateStr); err != nil { return helper.ParamInvalidError("date", fmt.Sprintf("需要 yyyy-MM-dd 格式: %v", err)), nil } data, err := repositories.QuerySiteShutdownList(dateStr, country) if err != nil { return helper.ServiceError("查询停机列表", err), nil } if len(data) == 0 { return helper.EmptyResult("查询结果为空"), nil } return helper.JSONResult(data), nil } func handleFwhQueryEmsLogRecord(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { sn, err := req.RequireString("sn") if err != nil { return helper.ParamError("sn"), nil } // 使用空日期和0类型查询所有记录 data, err := repositories.QueryEmsLogCallRecord(sn, "", 0) if err != nil { // 如果是"没有召唤日志"的错误,返回空结果 return helper.EmptyResult(fmt.Sprintf("未找到EMS日志记录: %v", err)), nil } return helper.JSONResult(data), nil } func handleFwhQueryFaultRecordList(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { sn, err := req.RequireString("sn") if err != nil { return helper.ParamError("sn"), nil } startTimeStr, err := req.RequireString("start_time") if err != nil { return helper.ParamError("start_time"), nil } endTimeStr, err := req.RequireString("end_time") if err != nil { return helper.ParamError("end_time"), nil } data, err := repositories.QueryFaultRecordList(sn, startTimeStr, endTimeStr) if err != nil { return helper.ServiceError("查询故障录波列表", err), nil } if len(data) == 0 { return helper.EmptyResult("查询结果为空"), nil } return helper.JSONResult(data), nil } func handleFwhQueryFaultRecordCallableList(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { sn, err := req.RequireString("sn") if err != nil { return helper.ParamError("sn"), nil } devType := int(req.GetFloat("dev_type", 1)) data, err := repositories.QueryFaultRecordCallableList(devType, sn) if err != nil { return helper.ServiceError("查询可召唤故障录波列表", err), nil } if len(data) == 0 { return helper.EmptyResult("无可召唤的故障录波数据"), nil } return helper.JSONResult(data), nil } func handleFwhQueryFaultRecordCallRecordList(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { data, err := repositories.QueryFaultRecordCallRecordList() if err != nil { return helper.ServiceError("查询故障录波召唤记录", err), nil } if len(data) == 0 { return helper.EmptyResult("查询结果为空"), nil } return helper.JSONResult(data), nil } func handleFwhQueryFaultRecordSubList(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { faultIdStr, err := req.RequireString("fault_id") if err != nil { return helper.ParamError("fault_id"), nil } faultId, err := strconv.ParseInt(faultIdStr, 10, 64) if err != nil { return helper.ParamInvalidError("fault_id", "必须是数字"), nil } data, err := repositories.QueryFaultRecordSubList(faultId) if err != nil { return helper.ServiceError("查询故障录波子记录", err), nil } if len(data) == 0 { return helper.EmptyResult("查询结果为空"), nil } return helper.JSONResult(data), nil } func handleFwhQuerySystemUpdateLog(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { sn, err := req.RequireString("sn") if err != nil { return helper.ParamError("sn"), nil } data, err := repositories.QuerySystemUpdateLog(sn) if err != nil { return helper.ServiceError("查询系统升级记录", err), nil } if len(data) == 0 { return helper.EmptyResult("查询结果为空"), nil } return helper.JSONResult(data), nil } func handleFwhQuerySystemUpdateLogDetail(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { orderIdStr, err := req.RequireString("order_id") if err != nil { return helper.ParamError("order_id"), nil } orderId, err := strconv.ParseInt(orderIdStr, 10, 64) if err != nil { return helper.ParamInvalidError("order_id", "必须是数字"), nil } data, err := repositories.QuerySystemUpdateLogDetail(orderId) if err != nil { return helper.ServiceError("查询升级详情", err), nil } if len(data) == 0 { return helper.EmptyResult("查询结果为空"), nil } return helper.JSONResult(data), nil } func handleFwhQueryAHubUpdateLog(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { sn, err := req.RequireString("sn") if err != nil { return helper.ParamError("sn"), nil } data, err := repositories.QueryAHubUpdateLog(sn) if err != nil { return helper.ServiceError("查询aHub升级记录", err), nil } if len(data) == 0 { return helper.EmptyResult("查询结果为空"), nil } return helper.JSONResult(data), nil } func handleFwhQueryTouTemplateList(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { search := req.GetString("search", "") page := uint(req.GetFloat("page", 1)) size := uint(req.GetFloat("size", 20)) data, err := repositories.QueryTouTemplateInfoList(search, size, page, nil, nil) if err != nil { return helper.ServiceError("查询TOU模板列表", err), nil } return helper.JSONResult(data), nil } func handleFwhQueryTouTemplateDetail(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) { idStr, err := req.RequireString("id") if err != nil { return helper.ParamError("id"), nil } id, err := strconv.ParseUint(idStr, 10, 64) if err != nil { return helper.ParamInvalidError("id", "必须是数字"), nil } data, err := repositories.QueryTouTemplateDetailInfo(uint(id)) if err != nil { return helper.ServiceError("查询TOU模板详情", err), nil } if data == nil { return helper.EmptyResult("模板不存在"), nil } return helper.JSONResult(data), nil }