package crontab import ( "kpt-pasture/model" "kpt-pasture/util" "time" pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow" "gitee.com/xuyiping_admin/pkg/logger/zaplog" "go.uber.org/zap" ) func (e *Entry) CowNeckRingErrorEnter() (err error) { pastureList := e.FindPastureList() if pastureList == nil || len(pastureList) == 0 { return nil } for _, pasture := range pastureList { e.DB.Model(new(model.NeckRingError)).Delete(new(model.NeckRingError)).Where("pasture_id = ?", pasture.Id) e.CowNeckRingError(pasture.Id) zaplog.Error("CowNeckRingErrorEnter-Success", zap.Any("pasture", pasture)) } return nil } func (e *Entry) CowNeckRingError(pastureId int64) { yesterday := time.Now().Local().AddDate(0, 0, -1).Format(model.LayoutDate2) habitMinId, originalMinId := 0, 0 if err := e.DB.Model(new(model.NeckActiveHabit)). Select("MIN(id) as id"). Where("pasture_id = ?", pastureId). Where("heat_date = ?", yesterday). Scan(&habitMinId).Error; err != nil { zaplog.Error("CowNeckRingError-Error", zap.Any("pastureId", pastureId), zap.Any("err", err)) return } if err := e.DB.Model(new(model.NeckRingOriginal)). Select("MIN(id) as id"). Where("pasture_id = ?", pastureId). Where("heat_date = ?", yesterday). Scan(&originalMinId).Error; err != nil { zaplog.Error("CowNeckRingError-Error", zap.Any("pastureId", pastureId), zap.Any("err", err)) return } minIsBindDate := util.TimeParseLocalUnix(yesterday) neckRingList := make([]*model.NeckRing, 0) if err := e.DB.Model(new(model.NeckRingError)). Where("pasture_id = ?", pastureId). Where("is_bind = ?", pasturePb.IsShow_Ok). Where("wear_at <= ?", minIsBindDate). Find(&neckRingList).Error; err != nil { zaplog.Error("NeckRingErrorOfNoSignal", zap.Any("err", err), zap.Any("pastureId", pastureId)) } updateNeckRingMap := make(map[int64]*model.NeckRingStats) errorMap := e.NeckRingErrorMap() for _, neckRing := range neckRingList { c1 := e.NeckRingErrorOfNoSignal(pastureId, neckRing, int64(habitMinId), yesterday) if c1 > 0 { updateNeckRingMap[neckRing.Id] = &model.NeckRingStats{ ErrorKind: c1, ErrorReason: errorMap[c1], Describe: "", } } c2 := e.NeckRingErrorOfSuspectedFallOffAndLowBattery(pastureId, neckRing, int64(habitMinId), yesterday) if c2 > 0 { updateNeckRingMap[neckRing.Id] = &model.NeckRingStats{ ErrorKind: c2, ErrorReason: errorMap[c2], Describe: "", } } c3 := e.NeckRingErrorOfReceivingLess(pastureId, neckRing, int64(habitMinId), int64(originalMinId), yesterday) if c3 > 0 { updateNeckRingMap[neckRing.Id] = &model.NeckRingStats{ ErrorKind: c3, ErrorReason: errorMap[c3], Describe: "", } } c4 := e.NeckRingErrorOfDataLatency(pastureId, neckRing, int64(habitMinId), yesterday) if c4 > 0 { updateNeckRingMap[neckRing.Id] = &model.NeckRingStats{ ErrorKind: c4, ErrorReason: errorMap[c4], Describe: "", } } } if len(updateNeckRingMap) > 0 { for id, v := range updateNeckRingMap { if err := e.DB.Model(new(model.NeckRing)). Where("id = ?", id). Updates(map[string]interface{}{ "status": pasturePb.IsShow_No, "error_kind": v.ErrorKind, "error_reason": v.ErrorReason, "describe": v.Describe, }).Error; err != nil { zaplog.Error("CowNeckRingError", zap.Any("err", err), zap.Any("id", id), zap.Any("v", v)) } } } } // NeckRingErrorOfNoSignal 佩戴后无信号 func (e *Entry) NeckRingErrorOfNoSignal(pastureId int64, neckRing *model.NeckRing, minId int64, dateTime string) pasturePb.NeckRingNumberError_Kind { var count int64 if err := e.DB.Model(new(model.NeckActiveHabit)). Where("id >= ?", minId). Where("neck_ring_number = ?", neckRing.NeckRingNumber). Where("pasture_id = ?", pastureId). Where("heat_date >= ?", dateTime). Count(&count).Error; err != nil { zaplog.Error("NeckRingErrorOfNoSignal", zap.Any("err", err), zap.Any("pastureId", pastureId)) } if count <= 0 { return pasturePb.NeckRingNumberError_No_Signal } return pasturePb.NeckRingNumberError_Invalid } // NeckRingErrorOfSuspectedFallOffAndLowBattery 插入异常脖环 '疑似脱落', '电量低','接收少' func (e *Entry) NeckRingErrorOfSuspectedFallOffAndLowBattery(pastureId int64, neckRing *model.NeckRing, minId int64, dateTime string) pasturePb.NeckRingNumberError_Kind { nowTime := time.Now().Local() neckRingHabitList := make([]*model.NeckActiveHabit, 0) if err := e.DB.Model(new(model.NeckActiveHabit)). Select(``). Where("id >= ?", minId). Where("neck_ring_number = ?", neckRing.NeckRingNumber). Where("pasture_id = ?", pastureId). Where("heat_date >= ?", dateTime). Find(&neckRingHabitList).Error; err != nil { zaplog.Error("suspectedFallOffAndLowBattery", zap.Any("err", err), zap.Any("pastureId", pastureId)) return pasturePb.NeckRingNumberError_Invalid } nba, nb1, nbHh, nbh, voltage := 0, 0, 0, 0, int32(0) for _, v := range neckRingHabitList { nba++ if v.High <= 50 && v.Rumina <= 5 { nb1 += 1 } at := util.DateTimeParseLocalUnix(v.ActiveTime) nowTimeUnix := nowTime.Unix() hoursDiff := (nowTimeUnix - at) / 3600 sumRuminaIntake := v.SumRumina + v.SumIntake if hoursDiff <= 8 && (v.High > 0 || sumRuminaIntake > 20) { nbHh++ } if v.High > 100 || v.Rumina > 5 { nbh++ } voltage += v.Voltage } svgVoltage := int32(float32(voltage) / float32(nba)) errorKind := pasturePb.NeckRingNumberError_Invalid switch { case svgVoltage <= 275: errorKind = pasturePb.NeckRingNumberError_Low_Battery case nb1 >= 4: errorKind = pasturePb.NeckRingNumberError_Suspected_Fall_Off default: errorKind = pasturePb.NeckRingNumberError_Receiving_Less } if (nb1 >= 4 && nbHh <= 1) || svgVoltage <= 275 || nba <= (5+nowTime.Hour()/4-1) { return errorKind } return pasturePb.NeckRingNumberError_Invalid } // NeckRingErrorOfReceivingLess '接收少' func (e *Entry) NeckRingErrorOfReceivingLess(pastureId int64, neckRing *model.NeckRing, habitMinId, originalMinId int64, dateTime string) pasturePb.NeckRingNumberError_Kind { var count int64 if err := e.DB.Model(new(model.NeckRing)). Where("pasture_id = ?", pastureId). Where("neck_ring_number = ?", neckRing.NeckRingNumber). Where("status = ?", pasturePb.IsShow_No). Count(&count).Error; err != nil { zaplog.Error("NeckRingErrorOfReceivingLess", zap.Any("err", err), zap.Any("pastureId", pastureId)) return pasturePb.NeckRingNumberError_Invalid } // 已存在就不再处理 if count > 0 { return pasturePb.NeckRingNumberError_Invalid } if err := e.DB.Model(new(model.NeckActiveHabit)). Where("id >= ?", habitMinId). Where("neck_ring_number = ?", neckRing.NeckRingNumber). Where("pasture_id = ?", pastureId). Where("heat_date >= ?", dateTime). Count(&count).Error; err != nil { zaplog.Error("NeckRingErrorOfReceivingLess", zap.Any("err", err), zap.Any("pastureId", pastureId)) } // 已存在就不再处理 if count > 0 { return pasturePb.NeckRingNumberError_Invalid } // 查询原始活动数据统计信息 var originalStats struct { Count int64 AvgVoltage float64 } if err := e.DB.Model(new(model.NeckRingOriginal)). Select("COUNT(*) as count, ROUND(AVG(voltage)) as avg_voltage"). Where("id >= ?", originalMinId). Where("neck_ring_number = ?", neckRing.NeckRingNumber). Where("pasture_id = ?", pastureId). Where("heat_date >= ?", dateTime). First(&originalStats).Error; err != nil { zaplog.Error("NeckRingOriginal", zap.Any("err", err), zap.Any("pasture_id", pastureId)) return pasturePb.NeckRingNumberError_Invalid } // 创建错误记录 errorKind := pasturePb.NeckRingNumberError_Receiving_Less if originalStats.AvgVoltage <= 285 { errorKind = pasturePb.NeckRingNumberError_Low_Battery } // 限制最大显示数量为99 displayCount := originalStats.Count if displayCount > 99 { displayCount = 99 } if displayCount > 0 { return errorKind } return pasturePb.NeckRingNumberError_Invalid } // NeckRingErrorOfDataLatency 数据延迟 func (e *Entry) NeckRingErrorOfDataLatency(pastureId int64, neckRing *model.NeckRing, habitMinId int64, dateTime string) pasturePb.NeckRingNumberError_Kind { var count int64 if err := e.DB.Model(new(model.NeckActiveHabit)). Select(`h.cow_id, h.ear_number, SUM(IF(TIMESTAMPDIFF(HOUR, UNIX_TIMESTAMP(h.active_time), h.created_at)>9, 1, 0)) AS nb, COUNT(1) AS nba, ROUND(AVG(h.voltage), 0) AS voltage`). Where("id >= ?", habitMinId). Where("cow_id = ?", neckRing.CowId). Where("filter_high > ?", 200). Where("heat_date >= ?", dateTime). Having("nb/nba >= ?", 0.7). Count(&count).Error; err != nil { zaplog.Error("NeckRingErrorOfDataLatency", zap.Any("err", err), zap.Any("pastureId", pastureId)) } if count > 0 { return pasturePb.NeckRingNumberError_Data_Latency } return pasturePb.NeckRingNumberError_Invalid }