package fwh_pro import ( "encoding/json" "errors" "fmt" "fwh-toolbox-server/domain" "net/url" "strconv" "time" "go.uber.org/zap" ) type EventAlarmType int const ( Event EventAlarmType = iota // 0 Alarm // 1 ) type EventAlarmListResponse struct { Code int `json:"code"` Message string `json:"message"` Result []domain.EventAlarmItem `json:"result"` Success bool `json:"success"` Total uint `json:"total"` } // 查询事件事件日志 func queryEventAndAlarmLog(sn string, params url.Values) ([]byte, error) { token := getLoginToken() userId, _ := getUserId(token) // 构造 query 参数 params.Add("userId", strconv.Itoa(userId)) params.Add("searchName", sn) params.Add("timeType", strconv.Itoa(1)) // 0-通讯时间;1-设备时间 params.Add("pageSize", strconv.FormatUint(REQ_PAGE_SIZE, 10)) params.Add("pageNum", strconv.Itoa(1)) params.Add("land", "ZH_CN") return FwhHttpGet("https://energy.franklinwh.com/hes-gateway/manage/iotDeviceRunLogs", params) } // 查询所有事件告警 // startTime&endTime 格式 YYYY-MM-DD HH:mm:SS func queryAllEventAlarm(sn, startTime, endTime string) ([]byte, error) { // 构造 query 参数 params := url.Values{} params.Add("startTime", startTime) params.Add("endTime", endTime) return queryEventAndAlarmLog(sn, params) } // 查询事件日志 // startTime&endTime 格式 YYYY-MM-DD HH:mm:SS func queryEventLog(sn, startTime, endTime string) ([]byte, error) { // 构造 query 参数 params := url.Values{} params.Add("logType", strconv.Itoa(0)) params.Add("startTime", startTime) params.Add("endTime", endTime) return queryEventAndAlarmLog(sn, params) } // 查询告警日志 // startTime&endTime 格式 YYYY-MM-DD HH:mm:SS // alarmCode - 支持多个code,用‘,’隔开,“”代表查询所有 func queryAlarmLog(sn, startTime, endTime, alarmCode string) ([]byte, error) { // 构造 query 参数 params := url.Values{} params.Add("logType", strconv.Itoa(1)) params.Add("alarmCode", alarmCode) params.Add("startTime", startTime) params.Add("endTime", endTime) return queryEventAndAlarmLog(sn, params) } // 查询实时告警 func queryRealtimeAlarm(sn string) ([]byte, error) { // 构造 query 参数 params := url.Values{} params.Add("logType", strconv.Itoa(2)) return queryEventAndAlarmLog(sn, params) } func queryEventOrAlarmListOnePage(sn string, startTime, endTime time.Time, t EventAlarmType) ([]domain.EventAlarmItem, error) { // 三次请求尝试 for i := 0; i < 3; i++ { eventLogRes, err := queryEventOrAlarmListOnePageExec(sn, startTime, endTime, t) if err != nil { zap.L().Warn("queryEventOrAlarmListOnePageExec failed and retry", zap.String("err", err.Error())) continue } if eventLogRes.Code == 401 { // TODO 尝试重新登录 return nil, errors.New("certification expired") } if eventLogRes.Code != 200 { // return nil, fmt.Errorf("查询失败 code: %d, message: %s", eventLogRes.Code, eventLogRes.Message) zap.L().Warn("queryEventOrAlarmListOnePage 查询失败 retry", zap.Int("code", eventLogRes.Code), zap.String("msg", eventLogRes.Message)) time.Sleep(time.Second * 5) continue } return eventLogRes.Result, nil } return nil, errors.New("retry failed") } func queryEventOrAlarmListOnePageExec(sn string, startTime, endTime time.Time, t EventAlarmType) (*EventAlarmListResponse, error) { startTimeStr := startTime.Format(time.DateTime) endTimeStr := endTime.Format(time.DateTime) // TEST fmt.Printf("startTime = %s\n", startTimeStr) fmt.Printf("endTime = %s\n", endTimeStr) var resByte []byte var err error switch t { case Event: resByte, err = queryEventLog(sn, startTimeStr, endTimeStr) case Alarm: resByte, err = queryAlarmLog(sn, startTimeStr, endTimeStr, "") } if err != nil { return nil, err } var eventLogRes EventAlarmListResponse // 反序列化(unmarshal) jsonErr := json.Unmarshal(resByte, &eventLogRes) if jsonErr != nil { return nil, jsonErr } return &eventLogRes, nil } // 从FWH获取事件或告警log数据 func QueryEventOrAlarmListOnTimeRange(sn string, startTime, endTime time.Time, t EventAlarmType) ([]domain.EventAlarmItem, error) { // 保证 startTime <= endTime if startTime.After(endTime) { return nil, errors.New("startTime > endTime") } // 按天拆分时间段 var periods []struct{ Start, End time.Time } currTime := startTime for currTime.Before(endTime) { // 当天结束时间 dayEnd := time.Date(currTime.Year(), currTime.Month(), currTime.Day(), 23, 59, 59, 0, currTime.Location()) // 如果当天结束大于 endTime,使用 endTime if dayEnd.After(endTime) { dayEnd = endTime } periods = append(periods, struct{ Start, End time.Time }{Start: currTime, End: dayEnd}) // 下一天开始 currTime = dayEnd.Add(time.Second).Truncate(24 * time.Hour) currTime = time.Date(currTime.Year(), currTime.Month(), currTime.Day(), 0, 0, 0, 0, currTime.Location()) } // 按天查询 var eventLogList []domain.EventAlarmItem for _, period := range periods { var eventLogRes []domain.EventAlarmItem = nil periodEndTime := period.End // 检查数据是否超过1000(单次查询上限) for { var err error eventLogRes, err = queryEventOrAlarmListOnePage(sn, period.Start, periodEndTime, t) if err != nil { return nil, err } eventLogList = append(eventLogList, eventLogRes...) // 判断是否未查完 if len(eventLogRes) < int(REQ_PAGE_SIZE) { // 请求完成,退出 break } // 跳转时间段,再次请求 // 提取最后一条数据的设备时间 periodEndTime, err = time.Parse(time.DateTime, eventLogRes[len(eventLogRes)-1].LogTime) if err != nil { return nil, err } } } return eventLogList, nil } // 查询快照信息 // logTime 格式 YYYY-MM-DD func queryAlarmSnapshotInfo(sn, logTime string, page int) ([]byte, error) { // 构造 query 参数 params := url.Values{} params.Add("logTime", logTime) params.Add("linkId", sn) params.Add("pageSize", strconv.FormatUint(REQ_PAGE_SIZE, 10)) params.Add("pageNum", strconv.Itoa(page)) params.Add("land", "ZH_CN") return FwhHttpGet("https://energy.franklinwh.com/hes-gateway/manage/selectAlarmSnapshotList", params) } func QueryAlarmSnapshotInfo(sn, logTime string) ([]domain.AlarmSnapshotInfo, error) { var page int = 1 var infoList []domain.AlarmSnapshotInfo for { // 查询告警快照数据 resByte, err := queryAlarmSnapshotInfo(sn, logTime, page) if err != nil { return nil, fmt.Errorf("[QueryAlarmSnapshotInfo] %s", err.Error()) } var alarmSnapshotRes domain.FwhPageResponse[domain.AlarmSnapshotInfo] // 反序列化(unmarshal) jsonErr := json.Unmarshal(resByte, &alarmSnapshotRes) if jsonErr != nil { return nil, fmt.Errorf("[QueryAlarmSnapshotInfo] %s", jsonErr) } if alarmSnapshotRes.Code != 200 { return nil, fmt.Errorf("[QueryAlarmSnapshotInfo] 查询失败 code: %d, message: %s", alarmSnapshotRes.Code, alarmSnapshotRes.Message) } if alarmSnapshotRes.Total > 10000 { return nil, fmt.Errorf("[QueryAlarmSnapshotInfo] 数据超过10000条") } infoList = append(infoList, alarmSnapshotRes.Result...) if alarmSnapshotRes.Total <= uint64(page*int(REQ_PAGE_SIZE)) { break } page++ } return infoList, nil }