Browse Source

habit: week data

Yi 2 months ago
parent
commit
2ce6611024

+ 1 - 1
.drone.yml

@@ -30,7 +30,7 @@ steps:
         from_secret: aliyuncs_password
       repo: registry.cn-hangzhou.aliyuncs.com/kpt-event/kpt-pasture
       registry: registry.cn-hangzhou.aliyuncs.com
-      tags: [ http-test,mqtt-test ]
+      tags: [ http-test,mqtt-test,cron-test]
 
 trigger:
   branch:

+ 0 - 15
cmd/neckring.go

@@ -1,15 +0,0 @@
-package cmd
-
-import (
-	"fmt"
-
-	"github.com/spf13/cobra"
-)
-
-var NeckRingCmd = &cobra.Command{
-	Use:   "neckRing",
-	Short: "merge neck ring data",
-	Run: func(cmd *cobra.Command, args []string) {
-		fmt.Println("neckRing called")
-	},
-}

+ 0 - 1
cmd/root.go

@@ -24,5 +24,4 @@ func init() {
 	RootCmd.AddCommand(CrontabCmd)
 	RootCmd.AddCommand(ConsumerCmd)
 	RootCmd.AddCommand(MqttCmd)
-	RootCmd.AddCommand(NeckRingCmd)
 }

+ 3 - 1
config/app.develop.yaml

@@ -43,7 +43,9 @@ cron:
   update_same_time: "0 20 1 * * ?"      # 每天凌晨1点20分执行
   system_basic_crontab: "0 25 1 * * ?"  # 每天凌晨1点25分执行
   cow_pregnant: "0 00 15 * * ?"         # 每天15点执行
-  neck_ring_estrus: "0 0 */1 * * ?"     # 每1个小时执行一次
+  neck_ring_estrus: "0 45 * * * ?"      # 更新脖环发情数据
+  neck_ring_merge: "*/5 * * * * ?"      # 合并脖环原始2小时数据(5分钟)
+  neck_ring_calculate: "*/10 * * * * ?"  # 计算脖环数据
 
 mqtt:
   broker: "kptyun.com:1983"

+ 2 - 0
config/app.go

@@ -59,6 +59,8 @@ type CronSetting struct {
 	CowPregnant        string `yaml:"cow_pregnant"`         //  月度牛只怀孕清单
 	UpdateActiveHabit  string `yaml:"update_active_habit"`  //  脖环2小时数据重新整合
 	NeckRingEstrus     string `yaml:"neck_ring_estrus"`     //  脖环牛只发情
+	NeckRingMerge      string `yaml:"neck_ring_merge"`      //  脖环原始数据合并
+	NeckRingCalculate  string `yaml:"neck_ring_calculate"`  //  脖环数据计算
 }
 
 type JwtTokenKeyConfig struct {

+ 3 - 2
config/app.test.yaml

@@ -31,8 +31,9 @@ cron:
   update_same_time: "0 20 1 * * ?"
   system_basic_crontab: "0 25 1 * * ?"
   cow_pregnant: "0 00 15 * * ?"
-  update_active_habit: "0 */2 * * * ?"  # 每2分钟执行一次
-  neck_ring_estrus: "0 */5 * * * ?"     # 每5分钟执行一次
+  neck_ring_estrus: "0 45 * * * ?"      # 更新脖环发情数据
+  neck_ring_merge: "*/5 * * * * ?"      # 合并脖环原始2小时数据(5分钟)
+  neck_ring_calculate: "*/10 * * * * ?"  # 计算脖环数据
 
 mqtt:
   broker: "kptyun.com:1983"

+ 14 - 2
dep/di_crontab.go

@@ -80,9 +80,21 @@ func EntryCrontab(dependency CrontabDependency) *cron.Crontab {
 		panic(err)
 	}*/
 
-	err = newCrontab.Bind("PastureUpdateCowEstrus", cs.NeckRingEstrus, dependency.CrontabHub.PastureUpdateCowEstrus)
+	err = newCrontab.Bind("UpdateCowEstrus", cs.NeckRingEstrus, dependency.CrontabHub.UpdateCowEstrus)
 	if err != nil {
-		zaplog.Error("EntryCrontab", zap.Any("PastureUpdateCowEstrus", err))
+		zaplog.Error("EntryCrontab", zap.Any("UpdateCowEstrus", err))
+		panic(err)
+	}
+
+	err = newCrontab.Bind("UpdateActiveHabit", cs.NeckRingCalculate, dependency.CrontabHub.NeckRingCalculate)
+	if err != nil {
+		zaplog.Error("EntryCrontab", zap.Any("UpdateActiveHabit", err))
+		panic(err)
+	}
+
+	err = newCrontab.Bind("NeckRingOriginalMergeData", cs.NeckRingMerge, dependency.CrontabHub.NeckRingOriginalMergeData)
+	if err != nil {
+		zaplog.Error("EntryCrontab", zap.Any("NeckRingOriginalMergeData", err))
 		panic(err)
 	}
 

+ 50 - 50
model/neck_active_habit.go

@@ -16,56 +16,56 @@ const (
 )
 
 type NeckActiveHabit struct {
-	Id                      int64                 `json:"id"`
-	PastureId               int64                 `json:"pastureId"`
-	NeckRingNumber          string                `json:"neckRingNumber"`
-	CowId                   int64                 `json:"cowId"`
-	Lact                    int32                 `json:"lact"`
-	CalvingAge              int32                 `json:"calvingAge"`
-	ActiveTime              string                `json:"activeTime"`
-	Frameid                 int32                 `json:"frameid"`
-	HeatDate                string                `json:"heatDate"`
-	Rumina                  int32                 `json:"rumina"`
-	Intake                  int32                 `json:"intake"`
-	Inactive                int32                 `json:"inactive"`
-	Gasp                    int32                 `json:"gasp"`
-	Other                   int32                 `json:"other"`
-	High                    int32                 `json:"high"`
-	Active                  int32                 `json:"active"`
-	FilterHigh              int32                 `json:"filterHigh"`
-	FilterRumina            int32                 `json:"filterRumina"`
-	FilterChew              int32                 `json:"filterChew"`
-	WeekHigh                int32                 `json:"weekHigh"`
-	WeekHighHabit           int32                 `json:"weekHighHabit"`
-	WeekRuminaHabit         int32                 `json:"weekRuminaHabit"`
-	WeekIntakeHabit         int32                 `json:"weekIntakeHabit"`
-	WeekChewHabit           int32                 `json:"weekChewHabit"`
-	WeekInactiveHabit       int32                 `json:"weekInactiveHabit"`
-	WeekOtherHabit          int32                 `json:"weekOtherHabit"`
-	ChangeHigh              int32                 `json:"changeHigh"`
-	ChangeRumina            int32                 `json:"changeRumina"`
-	ChangeChew              int32                 `json:"changeChew"`
-	ChangeAdjust            int32                 `json:"changeAdjust"`
-	ChangeFilter            int32                 `json:"changeFilter"`
-	RuminaFilter            int32                 `json:"ruminaFilter"`
-	ChewFilter              int32                 `json:"chewFilter"`
-	FilterCorrect           int32                 `json:"filterCorrect"`
-	SumRumina               int32                 `json:"sumRumina"`
-	SumIntake               int32                 `json:"sumIntake"`
-	SumInactive             int32                 `json:"sumInactive"`
-	SumAct                  int32                 `json:"sumAct"`
-	SumMinHigh              int32                 `json:"sumMinHigh"`
-	SumMaxHigh              int32                 `json:"sumMaxHigh"`
-	SumMinChew              int32                 `json:"SumMinChew"`
-	SumRuminaBeforeThreeDay int32                 `json:"sumRuminaBeforeThreeDay"`
-	SumIntakeBeforeThreeDay int32                 `json:"sumIntakeBeforeThreeDay"`
-	Score                   int32                 `json:"score"`
-	IsMaxTime               pasturePb.IsShow_Kind `json:"isMaxTime"`
-	IsShow                  pasturePb.IsShow_Kind `json:"isShow"`
-	RecordCount             int32                 `json:"recordCount"`
-	FirmwareVersion         int32                 `json:"firmwareVersion"`
-	CreatedAt               int64                 `json:"createdAt"`
-	UpdatedAt               int64                 `json:"updatedAt"`
+	Id                   int64                 `json:"id"`
+	PastureId            int64                 `json:"pastureId"`
+	NeckRingNumber       string                `json:"neckRingNumber"`
+	CowId                int64                 `json:"cowId"`
+	Lact                 int32                 `json:"lact"`
+	CalvingAge           int32                 `json:"calvingAge"`
+	ActiveTime           string                `json:"activeTime"`
+	Frameid              int32                 `json:"frameid"`
+	HeatDate             string                `json:"heatDate"`
+	Rumina               int32                 `json:"rumina"`
+	Intake               int32                 `json:"intake"`
+	Inactive             int32                 `json:"inactive"`
+	Gasp                 int32                 `json:"gasp"`
+	Other                int32                 `json:"other"`
+	High                 int32                 `json:"high"`
+	Active               int32                 `json:"active"`
+	FilterHigh           int32                 `json:"filterHigh"`
+	FilterRumina         int32                 `json:"filterRumina"`
+	FilterChew           int32                 `json:"filterChew"`
+	WeekHigh             int32                 `json:"weekHigh"`
+	WeekHighHabit        int32                 `json:"weekHighHabit"`
+	WeekRuminaHabit      int32                 `json:"weekRuminaHabit"`
+	WeekIntakeHabit      int32                 `json:"weekIntakeHabit"`
+	WeekChewHabit        int32                 `json:"weekChewHabit"`
+	WeekInactiveHabit    int32                 `json:"weekInactiveHabit"`
+	WeekOtherHabit       int32                 `json:"weekOtherHabit"`
+	ChangeHigh           int32                 `json:"changeHigh"`
+	ChangeRumina         int32                 `json:"changeRumina"`
+	ChangeChew           int32                 `json:"changeChew"`
+	ChangeAdjust         int32                 `json:"changeAdjust"`
+	ChangeFilter         int32                 `json:"changeFilter"`
+	RuminaFilter         int32                 `json:"ruminaFilter"`
+	ChewFilter           int32                 `json:"chewFilter"`
+	FilterCorrect        int32                 `json:"filterCorrect"`
+	SumRumina            int32                 `json:"sumRumina"`
+	SumIntake            int32                 `json:"sumIntake"`
+	SumInactive          int32                 `json:"sumInactive"`
+	SumActive            int32                 `json:"sumActive"`
+	SumMinHigh           int32                 `json:"sumMinHigh"`
+	SumMaxHigh           int32                 `json:"sumMaxHigh"`
+	SumMinChew           int32                 `json:"SumMinChew"`
+	BeforeThreeSumRumina int32                 `json:"beforeThreeSumRumina"`
+	BeforeThreeSumIntake int32                 `json:"beforeThreeSumIntake"`
+	Score                int32                 `json:"score"`
+	IsMaxTime            pasturePb.IsShow_Kind `json:"isMaxTime"`
+	IsShow               pasturePb.IsShow_Kind `json:"isShow"`
+	RecordCount          int32                 `json:"recordCount"`
+	FirmwareVersion      int32                 `json:"firmwareVersion"`
+	CreatedAt            int64                 `json:"createdAt"`
+	UpdatedAt            int64                 `json:"updatedAt"`
 }
 
 func (n *NeckActiveHabit) TableName() string {

+ 1 - 1
model/neck_ring_original.go

@@ -121,7 +121,7 @@ func (n *NeckRingOriginalMerge) IsMageData(data *NeckRingOriginal, xframeId int3
 	n.XframeId = xframeId
 	n.PastureId = data.PastureId
 	n.FirmwareVersion = data.FirmwareVersion
-	n.IsShow = pasturePb.IsShow_Ok
+	n.IsShow = pasturePb.IsShow_No
 }
 
 func (n *NeckRingOriginalMerge) SumAvg() {

+ 10 - 11
model/system_configure.go

@@ -3,17 +3,16 @@ package model
 import pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 
 const (
-	ActiveLowest      = "active_lowest"
-	RuminaLowest      = "rumina_lowest"
-	WeeklyActive      = "weekly_active"
-	XRuminaDisc       = "x_rumina_disc"
-	XChangeDiscount   = "x_change_discount"
-	ActiveLow         = "active_low"
-	ActiveMiddle      = "active_middle"
-	ActiveHigh        = "active_high"
-	MaxEstrus         = "max_estrus"
-	MaxHabit          = "max_habit"
-	UpdateOriginalMax = "original_merge_data"
+	High            = "high"
+	Rumina          = "rumina"
+	WeeklyActive    = "weekly_active"
+	XRuminaDisc     = "x_rumina_disc"
+	XChangeDiscount = "x_change_discount"
+	ActiveLow       = "active_low"
+	ActiveMiddle    = "active_middle"
+	ActiveHigh      = "active_high"
+	MaxEstrus       = "max_estrus"
+	MaxHabit        = "max_habit"
 )
 
 type SystemConfigure struct {

+ 4 - 1
module/crontab/interface.go

@@ -32,5 +32,8 @@ type Crontab interface {
 	UpdateSameTime() error
 	SystemBasicCrontab() error
 
-	PastureUpdateCowEstrus() error // 获取牛只发情数据 5分钟执行一下
+	// UpdateCowEstrus 脖环数据
+	UpdateCowEstrus() error           // 获取牛只发情数据 2小时执行一下
+	NeckRingOriginalMergeData() error // 合并脖环数据
+	NeckRingCalculate() error         // 更新脖环数据
 }

+ 86 - 32
module/crontab/model.go

@@ -1,40 +1,42 @@
 package crontab
 
-type XToday struct {
-	XBegDate       string
-	XEndDate       string
-	LastMaxHabitId int64
-	CurrMaxHabitId int64
-	XMin2Id        int64
-	XMin7Id        int64
-	ActiveLowest   int64
-	RuminaLowest   int64
-	ActiveLow      int64
-	ActiveMiddle   int64
-	ActiveHigh     int64
-}
-
+/*
+	type XToday struct {
+		XBegDate       string
+		XEndDate       string
+		LastMaxHabitId int64
+		CurrMaxHabitId int64
+		XMin2Id        int64
+		XMin7Id        int64
+		ActiveLowest   int64
+		RuminaLowest   int64
+		ActiveLow      int64
+		ActiveMiddle   int64
+		ActiveHigh     int64
+	}
+*/
 type WeekHabit struct {
-	NeckRingNumber   string
-	AvgHighHabit     int32
-	AvgRuminaHabit   int32
-	AvgChewHabit     int32
-	AvgInactiveHabit int32
-	AvgIntakeHabit   int32
-	AvgOtherHabit    int32
-}
-
-type SumHabit struct {
-	NeckRingNumber string
-	SumRumina      int32
-	SumIntake      int32
-	SumInactive    int32
-	SumActive      int32
-	SumMaxHigh     int32
-	SumMinHigh     int32
-	SumMinChew     int32
+	NeckRingNumber    string
+	WeekHighHabit     int32
+	WeekRuminaHabit   int32
+	WeekChewHabit     int32
+	WeekInactiveHabit int32
+	WeekIntakeHabit   int32
+	WeekOtherHabit    int32
 }
 
+/*
+	type SumHabit struct {
+		NeckRingNumber string
+		SumRumina      int32
+		SumIntake      int32
+		SumInactive    int32
+		SumActive      int32
+		SumMaxHigh     int32
+		SumMinHigh     int32
+		SumMinChew     int32
+	}
+*/
 type ActivityVolume struct {
 	NeckRingNumber string
 	AvgFilter      int32
@@ -67,3 +69,55 @@ type EstrusIsPeakData struct {
 	EstrusStartDate string
 	ActiveDate      string
 }
+
+type XToday struct {
+	LastMaxHabitId  int64
+	CurrMaxHabitId  int64
+	High            int32
+	Rumina          int32
+	ActiveLow       int32
+	ActiveMiddle    int32
+	ActiveHigh      int32
+	XRuminaDisc     int32
+	XChangeDiscount int32
+	WeeklyActive    int32
+}
+
+type FirstFilterData struct {
+	NeckRingNumber string
+	FilterHigh     int32
+	FilterRumina   int32
+	FilterChew     int32
+}
+
+type SumHabit struct {
+	NeckRingNumber string
+	SumRumina      int32
+	SumIntake      int32
+	SumInactive    int32
+	SumActive      int32
+	SumMaxHigh     int32
+	SumMinHigh     int32
+	SumMinChew     int32
+}
+
+type ChangeFilterData struct {
+	Id             int64
+	NeckRingNumber string
+	ChangeHigh     int32
+	ChangeFilter   int32
+	RuminaFilter   int32
+	ChangeRumina   int32
+	ChewFilter     int32
+	ChangeChew     int32
+	XlcDisCount    float64
+	HeatDate       string
+	FrameId        int32
+}
+
+type SecondFilterData struct {
+	NeckRingNumber string
+	ChangeFilter   float64
+	RuminaFilter   float64
+	ChewFilter     float64
+}

+ 7 - 7
module/crontab/neck_ring_estrus.go

@@ -22,7 +22,7 @@ const (
 	NormalChangJust = 10
 )
 
-func (e *Entry) PastureUpdateCowEstrus() (err error) {
+func (e *Entry) UpdateCowEstrus() (err error) {
 	pastureList := e.FindPastureList()
 	if pastureList == nil || len(pastureList) == 0 {
 		return nil
@@ -38,13 +38,13 @@ func (e *Entry) PastureUpdateCowEstrus() (err error) {
 }
 
 func (e *Entry) EntryCowEstrus(pastureId int64) (err error) {
-	activeLowValue := e.GetSystemConfigure(pastureId, model.ActiveLow).Value
-	activeMiddleValue := e.GetSystemConfigure(pastureId, model.ActiveMiddle).Value
-	activeHighValue := e.GetSystemConfigure(pastureId, model.ActiveHigh).Value
+	activeLow, _ := e.GetSystemConfigure(pastureId, model.ActiveLow)
+	activeMiddle, _ := e.GetSystemConfigure(pastureId, model.ActiveMiddle)
+	activeHigh, _ := e.GetSystemConfigure(pastureId, model.ActiveHigh)
 	xToday := &XToday{
-		ActiveLow:    activeLowValue,
-		ActiveMiddle: activeMiddleValue,
-		ActiveHigh:   activeHighValue,
+		ActiveLow:    int32(activeLow.Value),
+		ActiveMiddle: int32(activeMiddle.Value),
+		ActiveHigh:   int32(activeHigh.Value),
 	}
 	if err = e.CowEstrusWarning(pastureId, xToday); err != nil {
 		zaplog.Error("EntryCowEstrus", zap.Any("CowEstrusWarning", err), zap.Any("xToday", xToday))

+ 0 - 158
module/crontab/neck_ring_estrus_test.go

@@ -1,158 +0,0 @@
-package crontab
-
-import (
-	"database/sql"
-	"fmt"
-	"math"
-
-	"gorm.io/driver/mysql"
-	"gorm.io/gorm"
-)
-
-type HActiveHabit struct {
-	ID            uint
-	IntPastureID  uint
-	IntCowID      uint
-	VarCowCode    string
-	IntCurFetal   uint
-	DIM           uint
-	Createtime    sql.NullString
-	Changeadjust  uint
-	Changefilter  uint
-	Filtercorrect float64
-	Ruminafilter  int
-	Filterhigh    uint
-	Heatdate      sql.NullString
-}
-
-func main() {
-	dsn := "username:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
-	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
-	if err != nil {
-		panic("failed to connect database")
-	}
-
-	// 假设这些变量是从外部传入的
-	xbegactid, xendactid := uint(1), uint(100)
-	xPastuId := uint(123)
-	xthatdate := "2023-10-01"
-	xactlevellow := float64(10)
-	xadjust21 := float64(2)
-	maxruminaadjust := int(10)
-	rumtoheat := float64(0.5) // 假设值
-
-	var habits []HActiveHabit
-	db.Where("id BETWEEN ? AND ? AND int_pasture_id = ? AND heatdate = ?", xbegactid, xendactid, xPastuId, xthatdate).
-		Find(&habits)
-
-	var results []struct {
-		IntPastureID uint
-		IntCowID     uint
-		VarCowCode   string
-		IntCurFetal  uint
-		DIM          uint
-		Createtime   string
-		CFT          float64
-		High         uint
-	}
-
-	cowMap := make(map[uint][]HActiveHabit)
-	for _, habit := range habits {
-		cowMap[habit.IntCowID] = append(cowMap[habit.IntCowID], habit)
-	}
-
-	for cowID, habits := range cowMap {
-		var createtime string
-		var cft float64
-		var high uint
-		if len(habits) > 0 {
-			sortedHabits := sortHabitsByChangefilterDesc(habits)
-			createtime = sortedHabits[0].Createtime.String
-
-			maxCft := float64(-math.MaxFloat64)
-			for _, habit := range sortedHabits {
-				adjustedValue := calculateAdjustedValue(habit, maxruminaadjust, rumtoheat)
-				if adjustedValue > maxCft {
-					maxCft = adjustedValue
-					high = habit.Filterhigh
-				}
-			}
-			cft = round(maxCft)
-		}
-
-		if cft >= (xactlevellow - xadjust21) {
-			anyDimValid := false
-			for _, habit := range habits {
-				if habit.DIM >= 20 || habit.IntCurFetal == 0 {
-					anyDimValid = true
-					break
-				}
-			}
-			if anyDimValid {
-				results = append(results, struct {
-					IntPastureID uint
-					IntCowID     uint
-					VarCowCode   string
-					IntCurFetal  uint
-					DIM          uint
-					Createtime   string
-					CFT          float64
-					High         uint
-				}{
-					IntPastureID: habits[0].IntPastureID,
-					IntCowID:     cowID,
-					VarCowCode:   habits[0].VarCowCode,
-					IntCurFetal:  habits[0].IntCurFetal,
-					DIM:          habits[0].DIM,
-					Createtime:   createtime,
-					CFT:          cft,
-					High:         high,
-				})
-			}
-		}
-	}
-
-	for _, result := range results {
-		fmt.Printf("IntPastureID: %d, IntCowID: %d, VarCowCode: %s, IntCurFetal: %d, DIM: %d, Createtime: %s, CFT: %.2f, High: %d\n",
-			result.IntPastureID, result.IntCowID, result.VarCowCode, result.IntCurFetal, result.DIM, result.Createtime, result.CFT, result.High)
-	}
-}
-
-func sortHabitsByChangefilterDesc(habits []HActiveHabit) []HActiveHabit {
-	sorted := make([]HActiveHabit, len(habits))
-	copy(sorted, habits)
-	for i := range sorted {
-		for j := i + 1; j < len(sorted); j++ {
-			if sorted[i].Changefilter < sorted[j].Changefilter {
-				sorted[i], sorted[j] = sorted[j], sorted[i]
-			}
-		}
-	}
-	return sorted
-}
-
-func calculateAdjustedValue(habit HActiveHabit, maxruminaadjust int, rumtoheat float64) float64 {
-	baseValue := float64(0)
-	if habit.Changeadjust >= 10 {
-		baseValue = float64(habit.Changefilter-habit.Changeadjust+3) * habit.Filtercorrect / 100
-	} else {
-		baseValue = float64(habit.Changefilter) * habit.Filtercorrect / 100
-	}
-
-	ruminaAdjustment := float64(0)
-	if habit.Ruminafilter > maxruminaadjust {
-		ruminaAdjustment = 5
-	} else if habit.Ruminafilter > 0 {
-		ruminaAdjustment = float64(habit.Ruminafilter) * 0.25
-	} else if habit.Ruminafilter < -maxruminaadjust {
-		ruminaAdjustment = float64(-maxruminaadjust) * rumtoheat
-	} else {
-		ruminaAdjustment = float64(habit.Ruminafilter) * rumtoheat
-	}
-
-	return baseValue - ruminaAdjustment
-}
-
-func round(value float64) float64 {
-	return math.Round(value*100) / 100
-}

+ 336 - 173
module/mqtt/neck_ring_habit.go → module/crontab/neck_ring_handle.go

@@ -1,20 +1,16 @@
-package mqtt
+package crontab
 
 import (
 	"fmt"
 	"kpt-pasture/model"
-	"kpt-pasture/module/crontab"
+	"kpt-pasture/util"
 	"math"
 	"time"
 
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
-
-	"gorm.io/gorm"
-
 	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
-	"go.uber.org/zap"
-
 	"gitee.com/xuyiping_admin/pkg/xerr"
+	"go.uber.org/zap"
 )
 
 const (
@@ -26,22 +22,156 @@ const (
 	DefaultScore    = 100
 )
 
-func (e *Entry) PastureUpdateActiveHabit() {
+var (
+	defaultLimit = int32(1000)
+	isDelete     bool
+)
+
+// NeckRingOriginalMergeData 把脖环数据合并成2个小时的
+func (e *Entry) NeckRingOriginalMergeData() error {
+	var err error
+	limit := e.Cfg.NeckRingLimit
+	if limit <= 0 {
+		limit = defaultLimit
+	}
+	newTime := time.Now()
+	createdAt := newTime.Add(-1 * time.Hour)
+
+	neckRingList := make([]*model.NeckRingOriginal, 0)
+	if err = e.DB.Model(new(model.NeckRingOriginal)).
+		Where("is_show <= ?", pasturePb.IsShow_No).
+		Where("created_at <= ?", createdAt.Unix()).
+		Order("neck_ring_number,active_date,frameid").
+		Limit(int(limit)).Find(&neckRingList).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+	if len(neckRingList) <= 0 {
+		return nil
+	}
+
+	defer func() {
+		if newTime.Day()%15 == 0 && !isDelete {
+			// 原始数据删除15天前的
+			e.DB.Model(new(model.NeckRingOriginal)).
+				Where("created_at < ?", newTime.AddDate(0, 0, -15).Unix()).
+				Delete(new(model.NeckRingOriginal))
+			// 活动数据删除6个月前的数据
+			e.DB.Model(new(model.NeckActiveHabit)).
+				Where("created_at < ?", newTime.AddDate(0, -6, 0).Unix()).
+				Delete(new(model.NeckActiveHabit))
+			isDelete = true
+		}
+	}()
+	// 计算合并
+	neckActiveHabitList := e.recalculate(neckRingList)
+	if len(neckActiveHabitList) <= 0 {
+		return nil
+	}
+
+	zaplog.Info("NeckRingOriginalMergeData start", zap.Any("neckRingListLen", len(neckRingList)))
+
+	for _, neckActiveHabit := range neckActiveHabitList {
+		//更新脖环牛只相关信息 新数据直接插入
+		historyNeckActiveHabit, ct := e.IsExistNeckActiveHabit(neckActiveHabit.NeckRingNumber, neckActiveHabit.HeatDate, neckActiveHabit.Frameid)
+		if ct <= 0 {
+			if err = e.DB.Create(neckActiveHabit).Error; err != nil {
+				zaplog.Info("NeckRingOriginalMergeData-1", zap.Any("err", err), zap.Any("neckActiveHabit", neckActiveHabit))
+			}
+			newNeckRingProcess := model.NewNeckRingProcess(neckActiveHabit)
+			if err = e.DB.Create(newNeckRingProcess).Error; err != nil {
+				zaplog.Info("NeckRingOriginalMergeData-2", zap.Any("err", err), zap.Any("neckActiveHabit", neckActiveHabit))
+			}
+			if err = e.UpdateNeckRingOriginalIsShow(neckActiveHabit); err != nil {
+				zaplog.Error("NeckRingOriginalMergeData-3", zap.Any("err", err), zap.Any("neckActiveHabit", neckActiveHabit))
+			}
+			continue
+		}
+
+		if historyNeckActiveHabit == nil || historyNeckActiveHabit.Id <= 0 {
+			zaplog.Error("NeckRingOriginalMergeData-4", zap.Any("historyNeckActiveHabit", historyNeckActiveHabit), zap.Any("ct", ct), zap.Any("neckActiveHabit", neckActiveHabit))
+			continue
+		}
+
+		// 重新计算
+		newNeckActiveHabit := e.againRecalculate(historyNeckActiveHabit)
+		if newNeckActiveHabit != nil {
+			if err = e.DB.Model(new(model.NeckActiveHabit)).
+				Select("rumina", "intake", "inactive", "gasp", "other", "high", "active").
+				Where("id = ?", historyNeckActiveHabit.Id).
+				Updates(newNeckActiveHabit).Error; err != nil {
+				zaplog.Error("NeckRingOriginalMergeData-5", zap.Any("historyNeckActiveHabit", historyNeckActiveHabit), zap.Any("ct", ct), zap.Any("newNeckActiveHabit", newNeckActiveHabit))
+			}
+		}
+	}
+
+	return nil
+}
+
+func (e *Entry) NeckRingCalculate() error {
 	pastureList := e.FindPastureList()
 	if pastureList == nil || len(pastureList) == 0 {
-		return
+		return nil
 	}
 
 	for _, pasture := range pastureList {
 		if err := e.EntryUpdateActiveHabit(pasture.Id); err != nil {
-			zaplog.Error("PastureUpdateActiveHabit", zap.Any("PastureUpdateActiveHabit", err), zap.Any("pasture", pasture))
+			zaplog.Error("PastureUpdateActiveHabit", zap.Any("err", err), zap.Any("pasture", pasture))
 		}
 		zaplog.Info(fmt.Sprintf("PastureUpdateActiveHabit Success %d", pasture.Id))
 	}
+	return nil
+}
+
+// recalculate 合并计算
+func (e *Entry) recalculate(neckRingList []*model.NeckRingOriginal) []*model.NeckActiveHabit {
+	originalMapData := make(map[string]*model.NeckRingOriginalMerge)
+	// 合并成2个小时的
+	for _, v := range neckRingList {
+		xframeId := util.XFrameId(v.Frameid)
+		mapKey := fmt.Sprintf("%s%s%s%s%d", v.NeckRingNumber, model.JoinKey, v.ActiveDate, model.JoinKey, xframeId) // 0001/2023-12-04/0 0001/2023-12-03/4
+		if originalMapData[mapKey] == nil {
+			originalMapData[mapKey] = new(model.NeckRingOriginalMerge)
+		}
+		originalMapData[mapKey].IsMageData(v, xframeId)
+	}
+
+	currTime := time.Now()
+	// 算平均值
+	for k, v := range originalMapData {
+		// 过滤掉合并后不满6条数据
+		if v.RecordCount != 6 {
+			currMaxXframeId := util.FrameIdMapReverse[int32(currTime.Hour())]
+			activeDateString := fmt.Sprintf("%s %02d:00:00", v.ActiveDate, v.XframeId*2+1)
+			activeDate, _ := time.Parse(model.LayoutTime, activeDateString)
+			if currMaxXframeId-v.XframeId <= 1 && currTime.Add(-1*time.Hour).Unix() < activeDate.Unix() {
+				delete(originalMapData, k)
+			}
+		}
+		v.SumAvg()
+	}
+	return model.NeckRingOriginalMap(originalMapData).ForMatData()
+}
+
+func (e *Entry) againRecalculate(data *model.NeckActiveHabit) *model.NeckActiveHabit {
+	originalList := make([]*model.NeckRingOriginal, 0)
+	frameIds := util.FrameIds(data.Frameid)
+	if err := e.DB.Model(new(model.NeckRingOriginal)).
+		Where("neck_ring_number = ?", data.NeckRingNumber).
+		Where("active_date = ?", data.HeatDate).
+		Where("frameid IN (?)", frameIds).
+		Find(&originalList).Error; err != nil {
+		return nil
+	}
+
+	newDataList := e.recalculate(originalList)
+	if len(newDataList) != 1 {
+		return nil
+	}
+	return newDataList[0]
 }
 
 func (e *Entry) EntryUpdateActiveHabit(pastureId int64) (err error) {
-	lastMaxHabitData, err := e.GetSystemConfigure2(pastureId, model.MaxHabit)
+	lastMaxHabitData, err := e.GetSystemConfigure(pastureId, model.MaxHabit)
 	if err != nil {
 		return xerr.WithStack(err)
 	}
@@ -51,7 +181,7 @@ func (e *Entry) EntryUpdateActiveHabit(pastureId int64) (err error) {
 	if err = e.DB.Model(new(model.NeckActiveHabit)).
 		Where("id > ?", lastMaxHabitId).
 		Where("pasture_id = ?", pastureId).
-		Where(e.DB.Where("record_count = ?", model.AvgHours).Or("is_show = ?", pasturePb.IsShow_Ok)).
+		Where("is_show = ?", pasturePb.IsShow_No).
 		Order("id desc").First(currMaxHabit).Error; err != nil {
 		return xerr.WithStack(err)
 	}
@@ -70,29 +200,36 @@ func (e *Entry) EntryUpdateActiveHabit(pastureId int64) (err error) {
 	}()
 	// 获取这段执行数据内最大日期和最小日期
 	xToday := &XToday{}
-	activeLowest, err := e.GetSystemConfigure2(pastureId, model.ActiveLowest)
+	activeLowest, err := e.GetSystemConfigure(pastureId, model.High)
 	if err != nil {
 		return xerr.WithStack(err)
 	}
-	ruminaLowest, err := e.GetSystemConfigure2(pastureId, model.RuminaLowest)
+	ruminaLowest, err := e.GetSystemConfigure(pastureId, model.Rumina)
 	if err != nil {
 		return xerr.WithStack(err)
 	}
-	xRuminaDisc, err := e.GetSystemConfigure2(pastureId, model.XRuminaDisc)
+	xRuminaDisc, err := e.GetSystemConfigure(pastureId, model.XRuminaDisc)
 	if err != nil {
 		return err
 	}
-	xChangeDiscount, err := e.GetSystemConfigure2(pastureId, model.XChangeDiscount)
+	xChangeDiscount, err := e.GetSystemConfigure(pastureId, model.XChangeDiscount)
 	if err != nil {
 		return err
 	}
 
-	xToday.ActiveLowest = int32(activeLowest.Value)
-	xToday.RuminaLowest = int32(ruminaLowest.Value)
+	weeklyActive, err := e.GetSystemConfigure(pastureId, model.WeeklyActive)
+	if err != nil {
+		return xerr.WithStack(err)
+	}
+
+	xToday.High = int32(activeLowest.Value)
+	xToday.Rumina = int32(ruminaLowest.Value)
 	xToday.XRuminaDisc = int32(xRuminaDisc.Value)
 	xToday.XChangeDiscount = int32(xChangeDiscount.Value)
-	xToday.LastMaxHabitId = lastMaxHabitId  // 上次执行的id
-	xToday.CurrMaxHabitId = currMaxHabit.Id // 本次执行的id
+	xToday.CurrMaxHabitId = currMaxHabit.Id
+	xToday.LastMaxHabitId = lastMaxHabitId
+	xToday.WeeklyActive = int32(weeklyActive.Value)
+
 	// 更新活动滤波
 	if err = e.FirstFilterUpdate(pastureId, xToday); err != nil {
 		zaplog.Error("EntryUpdateActiveHabit", zap.Any("FirstFilterUpdate", err), zap.Any("xToday", xToday))
@@ -112,8 +249,9 @@ func (e *Entry) EntryUpdateActiveHabit(pastureId int64) (err error) {
 	}
 
 	if err = e.DB.Model(new(model.NeckActiveHabit)).
+		Where("id BETWEEN ? AND  ?", xToday.LastMaxHabitId, xToday.CurrMaxHabitId).
 		Where("pasture_id = ?", pastureId).
-		Where("id BETWEEN ? AND ?", xToday.LastMaxHabitId, xToday.CurrMaxHabitId).
+		Where("is_show = ?", pasturePb.IsShow_No).
 		Where("change_filter = ?", model.InitChangeFilter).
 		Updates(map[string]interface{}{
 			"change_filter": model.DefaultChangeFilter,
@@ -124,12 +262,14 @@ func (e *Entry) EntryUpdateActiveHabit(pastureId int64) (err error) {
 	}
 
 	if err = e.DB.Model(new(model.NeckActiveHabit)).
+		Where("id BETWEEN ? AND  ?", xToday.LastMaxHabitId, xToday.CurrMaxHabitId).
 		Where("pasture_id = ?", pastureId).
-		Where("id BETWEEN ? AND ?", xToday.LastMaxHabitId, xToday.CurrMaxHabitId).
+		Where("is_show = ?", pasturePb.IsShow_No).
 		Where("change_filter < ?", 0).
 		Where("filter_correct < ?", model.DefaultFilterCorrect).
 		Updates(map[string]interface{}{
 			"filter_correct": model.DefaultFilterCorrect,
+			"is_show":        pasturePb.IsShow_Ok,
 		}).Error; err != nil {
 		zaplog.Error("EntryUpdateActiveHabit", zap.Any("filter_correct", err), zap.Any("xToday", xToday))
 	}
@@ -141,20 +281,44 @@ func (e *Entry) EntryUpdateActiveHabit(pastureId int64) (err error) {
 	return nil
 }
 
+// CurrentMaxXFrameId 当前最大frameid
+func (e *Entry) CurrentMaxXFrameId(neckRingNumber, activeDate string) (frameid int32) {
+	type Fm struct {
+		Frameid int32
+	}
+	maxFx := &Fm{}
+	if err := e.DB.Model(new(model.NeckRingOriginal)).
+		Select("frameid").
+		Where("neck_ring_number = ?", neckRingNumber).
+		Where("active_date = ?", activeDate).
+		Order("frameid DESC").First(maxFx).Error; err != nil {
+		zaplog.Error("CurrentMaxXFrameId", zap.Any("err", err))
+		return 0
+	}
+	return maxFx.Frameid
+}
+
 // FirstFilterUpdate 首次更新活动滤波
 func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) error {
 	newNeckActiveHabitList := make([]*model.NeckActiveHabit, 0)
 	if err := e.DB.Model(new(model.NeckActiveHabit)).
-		Where("id BETWEEN ? AND ?", xToDay.LastMaxHabitId, xToDay.CurrMaxHabitId).
+		Where("id <= ?", xToDay.CurrMaxHabitId).
 		Where("pasture_id = ?", pastureId).
+		Where("is_show = ?", pasturePb.IsShow_No).
 		Where("change_filter = ?", model.InitChangeFilter).
-		Where(e.DB.Where("high >= ?", xToDay.ActiveLowest).Or("rumina >= ?", xToDay.RuminaLowest)). // 活动量过低牛只不参与计算
+		Where(e.DB.Where("high >= ?", xToDay.High).Or("rumina >= ?", xToDay.Rumina)). // 活动量过低牛只不参与计算
 		Order("neck_ring_number,heat_date,frameid").
 		Limit(int(defaultLimit)).Find(&newNeckActiveHabitList).Error; err != nil {
 		return xerr.WithStack(err)
 	}
 	// 活动量滤波
 	for _, v := range newNeckActiveHabitList {
+		// 过滤牛只未绑定的脖环的数据
+		cowInfo := e.GetCowInfoByNeckRingNumber(v.PastureId, v.NeckRingNumber)
+		if cowInfo == nil || cowInfo.Id <= 0 {
+			continue
+		}
+
 		firstFilterData := &FirstFilterData{}
 		frameId := v.Frameid
 		heatDate := v.HeatDate
@@ -169,7 +333,12 @@ func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) error {
 			Where("heat_date = ?", heatDate).
 			Where("frameid = ?", frameId).
 			First(&firstFilterData).Error; err != nil {
-			zaplog.Error("EntryUpdateActiveHabit", zap.Any("FirstFilterUpdate", err))
+			zaplog.Error("FirstFilterUpdate",
+				zap.Any("err", err),
+				zap.Any("NeckRingNumber", v.NeckRingNumber),
+				zap.Any("heatDate", heatDate),
+				zap.Any("frameId", frameId),
+			)
 		}
 
 		if v.FilterHigh > 0 {
@@ -200,14 +369,18 @@ func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) error {
 				firstFilterData.FilterChew = v.Rumina + v.Intake
 			}
 		}
+
 		// 更新过滤值
 		if err := e.DB.Model(new(model.NeckActiveHabit)).
-			Select("filter_high", "filter_rumina", "filter_chew").
+			Select("filter_high", "filter_rumina", "filter_chew", "cow_id", "lact", "calving_age").
 			Where("id = ?", v.Id).
 			Updates(map[string]interface{}{
 				"filter_high":   firstFilterData.FilterHigh,
 				"filter_rumina": firstFilterData.FilterRumina,
 				"filter_chew":   firstFilterData.FilterChew,
+				"cow_id":        cowInfo.Id,
+				"lact":          cowInfo.Lact,
+				"calving_age":   cowInfo.CalvingAge,
 			}).Error; err != nil {
 			return xerr.WithStack(err)
 		}
@@ -218,137 +391,125 @@ func (e *Entry) FirstFilterUpdate(pastureId int64, xToDay *XToday) error {
 
 // WeeklyActiveAvgUpdate 更新周平均值
 func (e *Entry) WeeklyActiveAvgUpdate(pastureId int64, xToday *XToday) (err error) {
-	weeklyActive, err := e.GetSystemConfigure2(pastureId, model.WeeklyActive)
-	if err != nil {
+	neckActiveHabitList := make([]*model.NeckActiveHabit, 0)
+	if err = e.DB.Model(new(model.NeckActiveHabit)).
+		Where("id <= ?", xToday.CurrMaxHabitId).
+		Where("pasture_id = ?", pastureId).
+		Where("change_filter = ?", model.InitChangeFilter).
+		Where("is_show = ?", pasturePb.IsShow_No).
+		Where(e.DB.Where("high > ?", xToday.High).Or("rumina >= ?", xToday.Rumina)).
+		Order("neck_ring_number,heat_date,frameid").
+		Limit(int(defaultLimit)).Find(&neckActiveHabitList).Error; err != nil {
 		return xerr.WithStack(err)
 	}
 
-	if err = e.DB.Transaction(func(tx *gorm.DB) error {
-		neckActiveHabitList := make([]*model.NeckActiveHabit, 0)
-		if err = tx.Model(new(model.NeckActiveHabit)).
-			Where("id BETWEEN ? AND ?", xToday.LastMaxHabitId, xToday.CurrMaxHabitId).
-			Where("pasture_id = ?", pastureId).
-			Where("change_filter = ?", model.InitChangeFilter).
-			Where(e.DB.Where("high > ?", xToday.ActiveLowest).Or("rumina > ?", xToday.RuminaLowest)).
-			Order("neck_ring_number,frameid").
-			Limit(int(defaultLimit)).Find(&neckActiveHabitList).Error; err != nil {
-			return xerr.WithStack(err)
-		}
-
-		zaplog.Info("WeeklyActiveAvgUpdate-0", zap.Any("neckActiveHabitList", neckActiveHabitList))
-		for _, v := range neckActiveHabitList {
-			beginDayDate, _ := time.Parse(model.LayoutDate2, v.HeatDate)
-			before7DayDate := beginDayDate.AddDate(0, 0, -7).Format(model.LayoutDate2)
-			before1DayDate := beginDayDate.AddDate(0, 0, -1).Format(model.LayoutDate2)
-
-			weekHabitData := &crontab.WeekHabit{}
-			if err = tx.Model(new(model.NeckActiveHabit)).
-				Select("neck_ring_number").
-				Select("IF(COUNT(1)>=3, ROUND((SUM(filter_high) -MIN(filter_high) -MAX(filter_high))/ABS(COUNT(1) -2),0), -1) as avg_high_habit").
-				Select("IF(COUNT(1)>=3, ROUND((SUM(filter_rumina) -MIN(filter_rumina) -MAX(filter_rumina))/ABS(COUNT(1) -2),0), -1) as avg_rumina_habit").
-				Select("IF(COUNT(1)>=3, ROUND((SUM(filter_chew) -MIN(filter_chew) -MAX(filter_chew))/ABS(COUNT(1) -2),0), -1) as avg_chew_habit").
-				Select("ROUND(AVG(intake),0) as avg_intake_habit").
-				Select("ROUND(AVG(inactive),0) as avg_inactive_habit").
-				Where("heat_date BETWEEN ? AND ?", before7DayDate, before1DayDate).
-				Where("pasture_id = ?", pastureId).
-				Where("neck_ring_number = ? AND frameid = ?", v.NeckRingNumber, v.Frameid).
-				Where(e.DB.Where("high > ?", xToday.ActiveLowest).Or("rumina > ?", xToday.RuminaLowest)).
-				Group("neck_ring_number").First(weekHabitData).Error; err != nil {
-				zaplog.Error("WeeklyActiveAvgUpdate-1", zap.Any("error", err), zap.Any("xToday", xToday))
-			}
-
-			// 累计24小时数值
-			sumHabitData := &SumHabit{}
-			if err = tx.Model(new(model.NeckActiveHabit)).
-				Select("neck_ring_number").
-				Select("IF(COUNT(1)>6, ROUND(AVG( h2.filter_rumina)*12,0), 0) as sum_rumina").
-				Select("IF(COUNT(1)>6, ROUND(AVG( h2.intake)*12,0), 0) as sum_intake").
-				Select("IF(COUNT(1)>6, ROUND(AVG( h2.inactive)*12,0), 0) as sum_inactive").
-				Select("IF(COUNT(1)>6, ROUND(AVG( h2.active)*12,0), 0) as sum_active").
-				Select("MAX(h2.change_filter) as sum_max_high").
-				Select("MIN(IF(change_filter > ?, change_filter, ?)) as sum_min_high", model.DefaultChangeFilter, model.InitChangeFilter).
-				Select("MIN( CASE WHEN filter_chew > ? THEN filter_chew WHEN filter_rumina >= ? THEN filter_rumina ELSE 0 END) as sum_min_chew", model.DefaultChangeFilter, model.DefaultRuminaFilter).
-				Where("pasture_id = ?", pastureId).
-				Where("heat_date BETWEEN ? AND ?", before1DayDate, beginDayDate).
-				Where("active_time BETWEEN ? AND ?", beginDayDate.Add(-23*time.Hour).Format(model.LayoutTime), beginDayDate.Format(model.LayoutTime)).
-				Where(e.DB.Where("high > ?", xToday.ActiveLowest).Or("rumina >= ?", xToday.RuminaLowest)).
-				Where("neck_ring_number = ? AND frameid = ?", v.NeckRingNumber, v.Frameid).
-				Group("neck_ring_number").
-				First(sumHabitData).Error; err != nil {
-				zaplog.Error("WeeklyActiveAvgUpdate-2", zap.Any("error", err), zap.Any("xToday", xToday))
-			}
+	for _, v := range neckActiveHabitList {
+		beginDayDate, _ := time.Parse(model.LayoutDate2, v.HeatDate)
+		before7DayDate := beginDayDate.AddDate(0, 0, -7).Format(model.LayoutDate2)
+		before1DayDate := beginDayDate.AddDate(0, 0, -1).Format(model.LayoutDate2)
 
-			// 变化百分比
-			if v.WeekHighHabit > 0 {
-				if v.FilterHigh-v.WeekHighHabit > 0 {
-					v.ChangeHigh = (v.FilterHigh - v.WeekHighHabit) / int32(float64(v.WeekHigh)*0.6+float64(v.WeekHighHabit)*0.2+float64(weeklyActive.Value)*0.2)
-				} else {
-					v.ChangeHigh = v.FilterHigh - v.WeekHighHabit/v.WeekHighHabit*100
-				}
+		activeTime := fmt.Sprintf("%s %02d:00:00", v.HeatDate, v.Frameid*2+1)
+		activeStartTimeParse, _ := time.Parse(model.LayoutTime, activeTime)
+		activeStartTime := activeStartTimeParse.Add(-23 * time.Hour).Format(model.LayoutTime)
 
-				v.ChangeRumina = v.RuminaFilter - v.WeekRuminaHabit/v.WeekHighHabit*100
-				v.ChangeChew = v.FilterChew - v.WeekChewHabit/v.WeekHighHabit*100
-				if err = e.DB.Model(new(model.NeckActiveHabit)).
-					Select("change_high", "change_rumina", "change_chew").
-					Where("id = ?", v.Id).
-					Updates(v).Error; err != nil {
-					return xerr.WithStack(err)
-				}
-			}
+		weekHabitData := &WeekHabit{}
+		if err = e.DB.Model(new(model.NeckActiveHabit)).
+			Select(
+				"neck_ring_number",
+				"IF(COUNT(1)>=3, ROUND((SUM(filter_high) -MIN(filter_high) -MAX(filter_high))/ABS(COUNT(1) -2),0), -1) as week_high_habit",
+				"IF(COUNT(1)>=3, ROUND((SUM(filter_rumina) -MIN(filter_rumina) -MAX(filter_rumina))/ABS(COUNT(1) -2),0), -1) as week_rumina_habit",
+				"IF(COUNT(1)>=3, ROUND((SUM(filter_chew) -MIN(filter_chew) -MAX(filter_chew))/ABS(COUNT(1) -2),0), -1) as week_chew_habit",
+				"ROUND(AVG(intake),0) as week_intake_habit",
+				"ROUND(AVG(inactive),0) as week_inactive_habit",
+			).Where("pasture_id = ?", pastureId).
+			Where("heat_date BETWEEN ? AND ?", before7DayDate, before1DayDate).
+			Where("neck_ring_number = ? ", v.NeckRingNumber).
+			Where("frameid = ?", v.Frameid).
+			Where(e.DB.Where("high > ?", xToday.High).Or("rumina >= ?", xToday.Rumina)).
+			Group("neck_ring_number").First(weekHabitData).Error; err != nil {
+			zaplog.Error("WeeklyActiveAvgUpdate-1", zap.Any("error", err), zap.Any("xToday", xToday))
+		}
+		// 累计24小时数值
+		sumHabitData := &SumHabit{}
+		if err = e.DB.Model(new(model.NeckActiveHabit)).
+			Select(
+				"neck_ring_number",
+				"IF(COUNT(1)>6, ROUND(AVG(filter_rumina)*12,0), 0) as sum_rumina",
+				"IF(COUNT(1)>6, ROUND(AVG(intake)*12,0), 0) as sum_intake",
+				"IF(COUNT(1)>6, ROUND(AVG(inactive)*12,0), 0) as sum_inactive",
+				"IF(COUNT(1)>6, ROUND(AVG(active)*12,0), 0) as sum_active",
+				"MAX(change_filter) as sum_max_high",
+				fmt.Sprintf("MIN(IF(change_filter > %d, change_filter, %d)) as sum_min_high", model.DefaultChangeFilter, model.InitChangeFilter),
+				fmt.Sprintf("MIN( CASE WHEN filter_chew > %d THEN filter_chew WHEN filter_rumina >= %d THEN filter_rumina ELSE 0 END) as sum_min_chew", model.DefaultChangeFilter, model.DefaultRuminaFilter),
+			).
+			Where("pasture_id = ?", pastureId).
+			Where("heat_date BETWEEN ? AND ?", before1DayDate, beginDayDate).
+			Where("active_time BETWEEN ? AND ?", activeStartTime, activeTime).
+			Where(e.DB.Where("high > ?", xToday.High).Or("rumina >= ?", xToday.Rumina)).
+			Where("neck_ring_number = ? AND frameid = ?", v.NeckRingNumber, v.Frameid).
+			Group("neck_ring_number").First(sumHabitData).Error; err != nil {
+			zaplog.Error("WeeklyActiveAvgUpdate-2", zap.Any("error", err), zap.Any("xToday", xToday))
+		}
 
-			// 三天前的反刍和采食
-			before3DaysNeckActiveHabit := &model.NeckActiveHabit{}
-			before3DayDate := beginDayDate.AddDate(0, 0, -3).Format(model.LayoutDate2)
-			if err = e.DB.Model(new(model.NeckActiveHabit)).
-				Select("sum_rumina", "sum_intake").
-				Where("pasture_id = ?", pastureId).
-				Where("neck_ring_number = ?", v.NeckRingNumber).
-				Where("heat_date = ?", before3DayDate).
-				Where("frameid = ? ", v.Frameid).
-				First(before3DaysNeckActiveHabit).Error; err != nil {
-				zaplog.Error("WeeklyActiveAvgUpdate-3", zap.Any("error", err), zap.Any("xToday", xToday))
-			}
+		highDiff := v.FilterHigh - weekHabitData.WeekHighHabit
+		denominator := float64(v.WeekHigh)*0.6 + float64(weekHabitData.WeekHighHabit)*0.2 + float64(xToday.WeeklyActive)*0.2
+		if highDiff > 0 {
+			v.ChangeHigh = int32(math.Round((float64(highDiff) / denominator) * 100))
+		} else {
+			v.ChangeHigh = int32(math.Round(float64(highDiff) / denominator * 100))
+		}
 
-			if err = tx.Model(new(model.NeckActiveHabit)).
-				Select("avg_high_habit", "avg_rumina_habit", "avg_chew_habit", "avg_intake_habit", "avg_inactive_habit").
-				Select("sum_rumina", "sum_intake", "sum_inactive", "sum_active", "sum_max_high", "sum_min_high", "sum_min_chew").
-				Select("change_high", "change_rumina", "change_chew", "sum_rumina_before_three_day", "sum_intake_before_three_day").
-				Where("id = ?", v.Id).
-				Updates(map[string]interface{}{
-					"week_high_habit":             weekHabitData.AvgHighHabit,
-					"week_rumina_habit":           weekHabitData.AvgRuminaHabit,
-					"week_chew_habit":             weekHabitData.AvgChewHabit,
-					"week_intake_habit":           weekHabitData.AvgIntakeHabit,
-					"week_inactive_habit":         weekHabitData.AvgIntakeHabit,
-					"sum_rumina":                  sumHabitData.SumRumina,
-					"sum_intake":                  sumHabitData.SumIntake,
-					"sum_inactive":                sumHabitData.SumInactive,
-					"sum_active":                  sumHabitData.SumActive,
-					"sum_max_high":                sumHabitData.SumMaxHigh,
-					"sum_min_high":                sumHabitData.SumMinHigh,
-					"sum_min_chew":                sumHabitData.SumMinChew,
-					"change_high":                 v.ChangeHigh,
-					"change_rumina":               v.ChangeRumina,
-					"change_chew":                 v.ChangeChew,
-					"sum_rumina_before_three_day": before3DaysNeckActiveHabit.SumRumina,
-					"sum_intake_before_three_day": before3DaysNeckActiveHabit.SumIntake,
-				}).Error; err != nil {
-				zaplog.Error("WeeklyActiveAvgUpdate-6", zap.Any("error", err), zap.Any("xToday", xToday))
-			}
+		if weekHabitData.WeekRuminaHabit != 0 {
+			v.ChangeRumina = int32(math.Round(float64(v.FilterRumina-weekHabitData.WeekRuminaHabit) / float64(weekHabitData.WeekRuminaHabit) * 100))
+		} else {
+			v.ChangeRumina = 0
+		}
+		if weekHabitData.WeekChewHabit != 0 {
+			v.ChangeChew = int32(math.Round(float64(v.FilterChew-weekHabitData.WeekChewHabit) / float64(weekHabitData.WeekChewHabit) * 100))
+		} else {
+			v.ChangeChew = 0
+		}
+		// 三天前的反刍和采食
+		before3DaysNeckActiveHabit := &model.NeckActiveHabit{}
+		before3DayDate := beginDayDate.AddDate(0, 0, -3).Format(model.LayoutDate2)
+		if err = e.DB.Model(new(model.NeckActiveHabit)).
+			Select("sum_rumina", "sum_intake").
+			Where("pasture_id = ?", pastureId).
+			Where("neck_ring_number = ?", v.NeckRingNumber).
+			Where("heat_date = ?", before3DayDate).
+			Where("frameid = ? ", v.Frameid).
+			First(before3DaysNeckActiveHabit).Error; err != nil {
+			zaplog.Error("WeeklyActiveAvgUpdate-3", zap.Any("error", err), zap.Any("xToday", xToday))
+		}
 
-			zaplog.Info("WeeklyActiveAvgUpdate-7",
-				zap.Any("v", v),
-				zap.Any("xToday", xToday),
-				zap.Any("before3DaysNeckActiveHabit", before3DaysNeckActiveHabit),
-				zap.Any("sumHabitData", sumHabitData),
-				zap.Any("weekHabitData", weekHabitData),
-			)
+		if err = e.DB.Model(new(model.NeckActiveHabit)).
+			Select(
+				"week_high_habit", "week_rumina_habit", "week_chew_habit", "week_intake_habit", "week_inactive_habit",
+				"sum_rumina", "sum_intake", "sum_inactive", "sum_active", "sum_max_high", "sum_min_high", "sum_min_chew",
+				"change_high", "change_rumina", "change_chew", "before_three_sum_rumina", "before_three_sum_intake",
+			).Where("id = ?", v.Id).
+			Updates(map[string]interface{}{
+				"week_high_habit":         weekHabitData.WeekHighHabit,
+				"week_rumina_habit":       weekHabitData.WeekRuminaHabit,
+				"week_chew_habit":         weekHabitData.WeekChewHabit,
+				"week_intake_habit":       weekHabitData.WeekIntakeHabit,
+				"week_inactive_habit":     weekHabitData.WeekIntakeHabit,
+				"sum_rumina":              sumHabitData.SumRumina,
+				"sum_intake":              sumHabitData.SumIntake,
+				"sum_inactive":            sumHabitData.SumInactive,
+				"sum_active":              sumHabitData.SumActive,
+				"sum_max_high":            sumHabitData.SumMaxHigh,
+				"sum_min_high":            sumHabitData.SumMinHigh,
+				"sum_min_chew":            sumHabitData.SumMinChew,
+				"change_high":             v.ChangeHigh,
+				"change_rumina":           v.ChangeRumina,
+				"change_chew":             v.ChangeChew,
+				"before_three_sum_rumina": before3DaysNeckActiveHabit.SumRumina,
+				"before_three_sum_intake": before3DaysNeckActiveHabit.SumIntake,
+			}).Error; err != nil {
+			zaplog.Error("WeeklyActiveAvgUpdate-6", zap.Any("error", err), zap.Any("xToday", xToday))
 		}
-		return nil
-	}); err != nil {
-		return xerr.WithStack(err)
 	}
-	zaplog.Info("WeeklyActiveAvgUpdate-Success", zap.Any("xToday", xToday))
 	return nil
 }
 
@@ -356,9 +517,9 @@ func (e *Entry) WeeklyActiveAvgUpdate(pastureId int64, xToday *XToday) (err erro
 func (e *Entry) SecondUpdateChangeFilter(pastureId int64, xToday *XToday) (err error) {
 	newChangeFilterList := make([]*ChangeFilterData, 0)
 	if err = e.DB.Model(new(model.NeckActiveHabit)).
-		Select("id,neck_ring_number,change_high,change_filter,rumina_filter,change_rumina,chew_filter,change_chew,heat_date,frameid").
-		Select("IF(lact = 0, 0.8, 1) as xlc_dis_count").
-		Where("id BETWEEN ? AND ?", xToday.XMin2Id, xToday.CurrMaxHabitId).
+		Select("id", "neck_ring_number", "change_high", "change_filter", "rumina_filter", "change_rumina",
+			"chew_filter", "change_chew", "heat_date", "frameid", "IF(lact = 0, 0.8, 1) as xlc_dis_count").
+		Where("heat_date >= ?", time.Now().AddDate(0, 0, -2).Format(model.LayoutDate2)).
 		Where("pasture_id = ?", pastureId).
 		Where("change_filter = ?", model.InitChangeFilter).
 		Where("change_high > ?", MinChangeHigh).
@@ -430,8 +591,6 @@ func (e *Entry) SecondUpdateChangeFilter(pastureId int64, xToday *XToday) (err e
 		if err = e.DB.Model(new(model.NeckActiveHabit)).
 			Select("change_filter", "rumina_filter", "chew_filter").
 			Where("id = ?", v.Id).
-			Where("neck_ring_number = ?", v.NeckRingNumber).
-			Where("change_filter = ?", model.InitChangeFilter).
 			Updates(map[string]interface{}{
 				"change_filter": secondFilterData.ChangeFilter,
 				"rumina_filter": secondFilterData.RuminaFilter,
@@ -439,12 +598,8 @@ func (e *Entry) SecondUpdateChangeFilter(pastureId int64, xToday *XToday) (err e
 			}).Error; err != nil {
 			zaplog.Error("SecondUpdateChangeFilter-1", zap.Any("error", err), zap.Any("xToday", xToday))
 		}
-		zaplog.Info("SecondUpdateChangeFilter",
-			zap.Any("secondFilterData", secondFilterData),
-			zap.Any("xToday", xToday),
-			zap.Any("v", v),
-		)
 	}
+	zaplog.Info("SecondUpdateChangeFilter-Success")
 	return nil
 }
 
@@ -454,16 +609,13 @@ func (e *Entry) FilterCorrectAndScoreUpdate(pastureId int64, xToday *XToday) err
 	before7DayDate := beginDayDate.AddDate(0, 0, -7).Format(model.LayoutDate2)
 	before1DayDate := beginDayDate.AddDate(0, 0, -1).Format(model.LayoutDate2)
 
-	activityVolumeList := make([]*crontab.ActivityVolume, 0)
-	activityVolumeMap := make(map[string]*crontab.ActivityVolume)
+	activityVolumeList := make([]*ActivityVolume, 0)
+	activityVolumeMap := make(map[string]*ActivityVolume)
 	if err := e.DB.Model(new(model.NeckActiveHabit)).
-		Select("neck_ring_number").
-		Select("AVG(IF(change_filter>=60, 60, change_filter)) as avg_filter").
-		Select("ROUND(STD(IF(change_filter>=60, 60, change_filter))) as std_filter").
-		Select("COUNT(1) as nb").
+		Select("neck_ring_number", "AVG(IF(change_filter>=60, 60, change_filter)) as avg_filter", "ROUND(STD(IF(change_filter>=60, 60, change_filter))) as std_filter", "COUNT(1) as nb").
 		Where("heat_date BETWEEN ? AND ?", before7DayDate, before1DayDate).
 		Where("pasture_id = ?", pastureId).
-		Where(e.DB.Where("high > ?", xToday.ActiveLowest).Or("rumina >= ?", xToday.RuminaLowest)).
+		Where(e.DB.Where("high > ?", xToday.High).Or("rumina >= ?", xToday.Rumina)).
 		Where("active_time <= ?", beginDayDate.Add(-12*time.Hour).Format(model.LayoutTime)).
 		Where("change_filter > ?", MinChangeFilter).
 		Having("nb > ?", DefaultNb).
@@ -480,9 +632,10 @@ func (e *Entry) FilterCorrectAndScoreUpdate(pastureId int64, xToday *XToday) err
 
 	neckActiveHabitList := make([]*model.NeckActiveHabit, 0)
 	if err := e.DB.Model(new(model.NeckActiveHabit)).
-		Where("id BETWEEN ? AND ?", xToday.XMin2Id, xToday.CurrMaxHabitId).
+		Where("id <= ?", xToday.CurrMaxHabitId).
+		Where("heat_date >= ?", before1DayDate).
 		Where("pasture_id = ?", pastureId).
-		Where(e.DB.Where("high > ?", xToday.ActiveLowest).Or("rumina > ?", xToday.RuminaLowest)).
+		Where(e.DB.Where("high > ?", xToday.High).Or("rumina > ?", xToday.Rumina)).
 		Find(&neckActiveHabitList).Error; err != nil {
 		zaplog.Error("ActivityVolumeChanges-1", zap.Any("error", err), zap.Any("xToday", xToday))
 		return xerr.WithStack(err)
@@ -500,15 +653,10 @@ func (e *Entry) FilterCorrectAndScoreUpdate(pastureId int64, xToday *XToday) err
 				continue
 			}
 		}
-		// 健康评分
-		if v.Score != 0 {
-			continue
-		}
 
 		cowScore := calculateScore(v)
 		if err := e.DB.Model(new(model.NeckActiveHabit)).
 			Where("id = ?", v.Id).
-			Where("neck_ring_number = ?", v.NeckRingNumber).
 			Update("score", cowScore).Error; err != nil {
 			zaplog.Error("ActivityVolumeChanges-2", zap.Any("error", err), zap.Any("xToday", xToday))
 			continue
@@ -522,6 +670,11 @@ func (e *Entry) FilterCorrectAndScoreUpdate(pastureId int64, xToday *XToday) err
 func (e *Entry) UpdateChangeAdJust(pastureId int64, xToday *XToday) error {
 	res := make([]*model.NeckRingBarChange, 0)
 	oneDayAgo := time.Now().AddDate(0, 0, -1).Format(model.LayoutDate2)
+	//SELECT h.neck_ring_number,h.heat_date, h.frameid, c.pen_id, c.pen_name, COUNT(*) as nb, ROUND(AVG(h.change_high)) as change_high,
+	//ROUND(AVG(h.change_filter)) as change_filter F
+	//ROM neck_active_habit as h JOIN cow as c ON h.neck_ring_number = c.neck_ring_number
+	//WHERE h.pasture_id = 1 AND h.heat_date >= '2025-01-16' AND h.cow_id >= 0
+	//GROUP BY h.heat_date, h.frameid, c.pen_id ORDER BY h.heat_date, h.frameid, c.pen_name
 	if err := e.DB.Table(fmt.Sprintf("%s as h", new(model.NeckActiveHabit).TableName())).
 		Select("h.neck_ring_number,h.heat_date, h.frameid, c.pen_id, c.pen_name, COUNT(*) as nb, ROUND(AVG(h.change_high)) as change_high, ROUND(AVG(h.change_filter)) as change_filter").
 		Joins("JOIN cow as c ON h.neck_ring_number = c.neck_ring_number").
@@ -538,7 +691,6 @@ func (e *Entry) UpdateChangeAdJust(pastureId int64, xToday *XToday) error {
 		if err := e.DB.Model(new(model.NeckActiveHabit)).
 			Where("id > ?", xToday.LastMaxHabitId).
 			Where("heat_date = ?", v.HeatDate).
-			Where("heat_date >= ?", oneDayAgo).
 			Where("frameid = ?", v.FrameId).
 			Where("neck_ring_number = ?", v.NeckRingNumber).
 			Update("change_adjust", v.ChangeHigh).Error; err != nil {
@@ -548,7 +700,18 @@ func (e *Entry) UpdateChangeAdJust(pastureId int64, xToday *XToday) error {
 	return nil
 }
 
-// 辅助函数来计算过滤值
+func (e *Entry) UpdateNeckRingOriginalIsShow(neckRingList *model.NeckActiveHabit) error {
+	if err := e.DB.Model(new(model.NeckRingOriginal)).
+		Where("neck_ring_number = ?", neckRingList.NeckRingNumber).
+		Where("active_date = ?", neckRingList.HeatDate).
+		Where("frameid IN (?)", util.FrameIds(neckRingList.Frameid)).
+		Update("is_show", pasturePb.IsShow_Ok).Error; err != nil {
+		return xerr.WithStack(err)
+	}
+	return nil
+}
+
+// computeIfPositiveElse 辅助函数来计算过滤值
 func computeIfPositiveElse(newValue, prevFilterValue float64, weightPrev, weightNew float64) float64 {
 	return math.Ceil((prevFilterValue * weightPrev) + (weightNew * newValue))
 }

+ 0 - 2
module/crontab/other.go

@@ -26,8 +26,6 @@ func (e *Entry) IsExistCrontabLog(name string) bool {
 	return false
 }
 
-var isDelete bool
-
 func (e *Entry) CreateCrontabLog(name string) {
 	// 日志保留15天以内的
 	nowDay := time.Now()

+ 85 - 12
module/crontab/sql.go

@@ -1,8 +1,11 @@
 package crontab
 
 import (
+	"errors"
 	"kpt-pasture/model"
 
+	"gorm.io/gorm"
+
 	"go.uber.org/zap"
 
 	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
@@ -45,18 +48,6 @@ func (e *Entry) GetPenMapList() (map[int32]*model.Pen, error) {
 	return penMap, nil
 }
 
-func (e *Entry) GetSystemConfigure(pastureId int64, name string) *model.SystemConfigure {
-	res := &model.SystemConfigure{}
-	if err := e.DB.Model(new(model.SystemConfigure)).
-		Where("name = ?", name).
-		Where("pasture_id = ?", pastureId).
-		Where("is_show = ?", pasturePb.IsShow_Ok).
-		First(res).Error; err != nil {
-		return nil
-	}
-	return res
-}
-
 // GetBeforeThreeDaysCowEstrus 获取值得时间之前三天内最大发情记录
 func (e *Entry) GetBeforeThreeDaysCowEstrus(cowId int64, activeTime string) *model.EventEstrus {
 	eventEstrus := &model.EventEstrus{}
@@ -110,3 +101,85 @@ func (e *Entry) IsExistEventEstrus(pastureId, cowId int64) *model.EventEstrus {
 	}
 	return res
 }
+
+func (e *Entry) IsExistNeckActiveHabit(neckRingNumber, heatDate string, frameId int32) (*model.NeckActiveHabit, int64) {
+	count := int64(0)
+	neckRingProcess := &model.NeckRingProcess{}
+	if err := e.DB.Model(new(model.NeckRingProcess)).
+		Where("neck_ring_number = ?", neckRingNumber).
+		Where("active_date = ?", heatDate).
+		Where("frameid = ?", frameId).
+		Count(&count).
+		First(neckRingProcess).Error; err != nil {
+		return nil, 0
+	}
+
+	res := &model.NeckActiveHabit{}
+	if neckRingProcess != nil {
+		if neckRingProcess.HabitId > 0 {
+			if err := e.DB.Model(new(model.NeckActiveHabit)).
+				Where("id = ?", neckRingProcess.HabitId).
+				First(res).Error; err != nil {
+				return nil, 0
+			}
+		} else {
+			if err := e.DB.Model(new(model.NeckActiveHabit)).
+				Where("heat_date = ?", heatDate).
+				Where("neck_ring_number = ?", neckRingNumber).
+				Where("frameid = ?", frameId).
+				First(res).Error; err != nil {
+				return nil, 0
+			}
+
+			if err := e.DB.Model(new(model.NeckRingProcess)).
+				Where("id = ?", neckRingProcess.Id).
+				Where("frameid = ?", frameId).
+				Update("habit_id", res.Id).Error; err != nil {
+				return nil, 0
+			}
+		}
+	}
+	return res, count
+}
+
+func (e *Entry) GetSystemConfigure(pastureId int64, name string) (*model.SystemConfigure, error) {
+	res := &model.SystemConfigure{}
+	if err := e.DB.Model(new(model.SystemConfigure)).
+		Where("name = ?", name).
+		Where("pasture_id = ?", pastureId).
+		Where("is_show = ?", pasturePb.IsShow_Ok).
+		First(res).Error; err != nil {
+		return nil, xerr.WithStack(err)
+	}
+	return res, nil
+}
+
+func (e *Entry) GetCowInfoByNeckRingNumber(pastureId int64, neckRingNumber string) *model.Cow {
+	res := &model.Cow{}
+	if err := e.DB.Model(new(model.Cow)).
+		Where("pasture_id = ?", pastureId).
+		Where("neck_ring_number = ?", neckRingNumber).
+		Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
+		First(res).Error; err != nil {
+		return nil
+	}
+	return res
+}
+
+// GetMinIdByHeatDate 获取最小的id
+func (e *Entry) GetMinIdByHeatDate(heatDate string, defaultId int64) (int64, error) {
+	xMinId := struct {
+		Id int64
+	}{}
+	if err := e.DB.Model(new(model.NeckActiveHabit)).
+		Select("MIN(id) as id").
+		Where("heat_date = ?", heatDate).
+		First(&xMinId).Error; err != nil {
+		if errors.Is(err, gorm.ErrRecordNotFound) {
+			xMinId.Id = defaultId
+		} else {
+			return 0, xerr.WithStack(err)
+		}
+	}
+	return xMinId.Id, nil
+}

+ 0 - 2
module/mqtt/interface.go

@@ -22,6 +22,4 @@ type Entry struct {
 
 type DataHandle interface {
 	NeckRingHandle(msg []byte)
-	NeckRingOriginalMergeData()
-	PastureUpdateActiveHabit() // 更新脖环数据 2分钟执行一下
 }

+ 0 - 73
module/mqtt/model.go

@@ -1,73 +0,0 @@
-package mqtt
-
-type XToday struct {
-	XBegDate        string
-	XEndDate        string
-	LastMaxHabitId  int64
-	CurrMaxHabitId  int64
-	XMin2Id         int64
-	XMin7Id         int64
-	ActiveLowest    int32
-	RuminaLowest    int32
-	ActiveLow       int32
-	ActiveMiddle    int32
-	ActiveHigh      int32
-	XRuminaDisc     int32
-	XChangeDiscount int32
-}
-
-type AvgHabit struct {
-	NeckRingNumber   string
-	AvgHighHabit     int32
-	AvgRuminaHabit   int32
-	AvgChewHabit     int32
-	AvgInactiveHabit int32
-	AvgIntakeHabit   int32
-	AvgOtherHabit    int32
-}
-
-type SumHabit struct {
-	NeckRingNumber string
-	SumRumina      int32
-	SumIntake      int32
-	SumInactive    int32
-	SumActive      int32
-	SumMaxHigh     int32
-	SumMinHigh     int32
-	SumMinChew     int32
-}
-
-type ChangeFilterData struct {
-	Id             int64
-	NeckRingNumber string
-	ChangeHigh     int32
-	ChangeFilter   int32
-	RuminaFilter   int32
-	ChangeRumina   int32
-	ChewFilter     int32
-	ChangeChew     int32
-	XlcDisCount    float64
-	HeatDate       string
-	FrameId        int32
-}
-
-type ActivityVolume struct {
-	NeckRingNumber string
-	AvgFilter      int32
-	StdFilter      int32
-	Nb             int32
-}
-
-type FirstFilterData struct {
-	NeckRingNumber string
-	FilterHigh     int32
-	FilterRumina   int32
-	FilterChew     int32
-}
-
-type SecondFilterData struct {
-	NeckRingNumber string
-	ChangeFilter   float64
-	RuminaFilter   float64
-	ChewFilter     float64
-}

+ 1 - 189
module/mqtt/merge_handle.go → module/mqtt/mqtt_handle.go

@@ -2,14 +2,10 @@ package mqtt
 
 import (
 	"encoding/json"
-	"fmt"
 	"kpt-pasture/model"
 	"kpt-pasture/util"
 	"strconv"
 	"strings"
-	"time"
-
-	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 
 	"github.com/jinzhu/copier"
 
@@ -25,14 +21,10 @@ type DataInsertNeckRingLog struct {
 }
 
 var (
-	batchSize    = 10
-	batchList    = make([]*model.NeckRingOriginal, 0, batchSize)
-	defaultLimit = int32(1000)
-	DSMLog       = &DataInsertNeckRingLog{
+	DSMLog = &DataInsertNeckRingLog{
 		NeckRingOriginalData: make([]*model.NeckRingOriginal, 0),
 		NeckRingErrorData:    make([]*model.NeckRingError, 0),
 	}
-	isDelete             bool
 	pastureMqttMap       = make(map[string]int64)
 	isFindPastureMqttMap bool
 )
@@ -51,112 +43,6 @@ func (e *Entry) NeckRingHandle(data []byte) {
 	return
 }
 
-// NeckRingOriginalMergeData 把脖环数据合并成2个小时的
-func (e *Entry) NeckRingOriginalMergeData() {
-	var err error
-	limit := e.Cfg.NeckRingLimit
-	if limit <= 0 {
-		limit = defaultLimit
-	}
-	mergeDataMaxId := e.GetSystemConfigure(model.UpdateOriginalMax).Value
-
-	newTime := time.Now()
-	createdAt := newTime.Add(-1 * time.Hour)
-
-	neckRingList := make([]*model.NeckRingOriginal, 0)
-	if err = e.DB.Model(new(model.NeckRingOriginal)).
-		Where("is_show <= ?", pasturePb.IsShow_No).
-		Where("created_at <= ?", createdAt.Unix()).
-		Order("neck_ring_number,active_date,frameid").
-		Limit(int(limit)).Find(&neckRingList).Error; err != nil {
-		return
-	}
-	if len(neckRingList) <= 0 {
-		return
-	}
-
-	if neckRingList[len(neckRingList)-1].Id <= mergeDataMaxId {
-		return
-	}
-
-	defer func() {
-		newMergeDataMaxId := neckRingList[len(neckRingList)-1].Id
-		if newMergeDataMaxId > 0 && newMergeDataMaxId > mergeDataMaxId {
-			e.DB.Model(new(model.SystemConfigure)).
-				Where("name = ?", model.UpdateOriginalMax).
-				Update("value", newMergeDataMaxId)
-			e.DB.Model(new(model.NeckRingOriginal)).
-				Where("id BETWEEN ? AND ?", mergeDataMaxId, newMergeDataMaxId).
-				Update("is_show", pasturePb.IsShow_Ok)
-		}
-
-		if newTime.Day()%15 == 0 && !isDelete {
-			// 原始数据删除15天前的
-			e.DB.Model(new(model.NeckRingOriginal)).
-				Where("created_at < ?", newTime.AddDate(0, 0, -15).Unix()).
-				Delete(new(model.NeckRingOriginal))
-			// 活动数据删除6个月前的数据
-			e.DB.Model(new(model.NeckActiveHabit)).
-				Where("created_at < ?", newTime.AddDate(0, -6, 0).Unix()).
-				Delete(new(model.NeckActiveHabit))
-			isDelete = true
-		}
-	}()
-	// 计算合并
-	neckActiveHabitList := e.recalculate(neckRingList)
-	if len(neckActiveHabitList) <= 0 {
-		return
-	}
-
-	if err = e.DB.Transaction(func(tx *gorm.DB) error {
-		for _, neckActiveHabit := range neckActiveHabitList {
-			//更新脖环牛只相关信息 新数据直接插入
-			historyNeckActiveHabit, ct := e.IsExistNeckActiveHabit(neckActiveHabit.NeckRingNumber, neckActiveHabit.HeatDate, neckActiveHabit.Frameid)
-			if ct <= 0 {
-				// 过滤牛只未绑定的脖环的数据
-				cowInfo := e.GetCowInfoByNeckRingNumber(neckActiveHabit.PastureId, neckActiveHabit.NeckRingNumber)
-				if cowInfo == nil || cowInfo.Id <= 0 {
-					continue
-				}
-				neckActiveHabit.CowId = cowInfo.Id
-				neckActiveHabit.Lact = cowInfo.Lact
-				neckActiveHabit.CalvingAge = int32(cowInfo.CalvingAge)
-				if err = tx.Create(neckActiveHabit).Error; err != nil {
-					return xerr.WithStack(err)
-				}
-				newNeckRingProcess := model.NewNeckRingProcess(neckActiveHabit)
-				if err = tx.Create(newNeckRingProcess).Error; err != nil {
-					return xerr.WithStack(err)
-				}
-				if err = e.UpdateNeckRingOriginalIsShow(neckActiveHabit); err != nil {
-					zaplog.Error("UpdateNeckRingOriginalIsShow", zap.Any("err", err), zap.Any("neckActiveHabit", neckActiveHabit))
-				}
-				continue
-			}
-
-			if historyNeckActiveHabit == nil || historyNeckActiveHabit.Id <= 0 {
-				zaplog.Error("NeckRingOriginalMergeData", zap.Any("historyNeckActiveHabit", historyNeckActiveHabit), zap.Any("ct", ct), zap.Any("neckActiveHabit", neckActiveHabit))
-				continue
-			}
-
-			// 重新计算
-			newNeckActiveHabit := e.againRecalculate(historyNeckActiveHabit)
-			if newNeckActiveHabit != nil {
-				if err = tx.Model(new(model.NeckActiveHabit)).
-					Select("rumina", "intake", "inactive", "gasp", "other", "high", "active").
-					Where("id = ?", historyNeckActiveHabit.Id).
-					Updates(newNeckActiveHabit).Error; err != nil {
-					return xerr.WithStack(err)
-				}
-			}
-		}
-		return nil
-	}); err != nil {
-		zaplog.Error("NeckRingOriginalMergeData", zap.Any("transaction", err))
-		return
-	}
-}
-
 func (e *Entry) FindPastureMqttMap() map[string]int64 {
 	if isFindPastureMqttMap {
 		return pastureMqttMap
@@ -266,80 +152,6 @@ func (e *Entry) MsgDataFormat2(msg []byte) *DataInsertNeckRingLog {
 	}
 }
 
-// recalculate 合并计算
-func (e *Entry) recalculate(neckRingList []*model.NeckRingOriginal) []*model.NeckActiveHabit {
-	originalMapData := make(map[string]*model.NeckRingOriginalMerge)
-	// 合并成2个小时的
-	for _, v := range neckRingList {
-		xframeId := util.XFrameId(v.Frameid)
-		mapKey := fmt.Sprintf("%s%s%s%s%d", v.NeckRingNumber, model.JoinKey, v.ActiveDate, model.JoinKey, xframeId) // 0001/2023-12-04/0 0001/2023-12-03/4
-		if originalMapData[mapKey] == nil {
-			originalMapData[mapKey] = new(model.NeckRingOriginalMerge)
-		}
-		originalMapData[mapKey].IsMageData(v, xframeId)
-	}
-
-	// 算平均值
-	for k, v := range originalMapData {
-		// 过滤掉合并后不满6条数据
-		if v.RecordCount != 6 {
-			maxFrameId := e.CurrentMaxXFrameId(v.NeckRingNumber, v.ActiveDate)
-			currXframeId := util.XFrameId(maxFrameId)
-			if currXframeId-v.XframeId <= 1 {
-				delete(originalMapData, k)
-			}
-		}
-		v.SumAvg()
-	}
-	return model.NeckRingOriginalMap(originalMapData).ForMatData()
-}
-
-func (e *Entry) againRecalculate(data *model.NeckActiveHabit) *model.NeckActiveHabit {
-	originalList := make([]*model.NeckRingOriginal, 0)
-	frameIds := util.FrameIds(data.Frameid)
-	if err := e.DB.Model(new(model.NeckRingOriginal)).
-		Where("neck_ring_number = ?", data.NeckRingNumber).
-		Where("active_date = ?", data.HeatDate).
-		Where("frameid IN (?)", frameIds).
-		Find(&originalList).Error; err != nil {
-		return nil
-	}
-
-	newDataList := e.recalculate(originalList)
-	if len(newDataList) != 1 {
-		return nil
-	}
-	return newDataList[0]
-}
-
-// CurrentMaxXFrameId 当前最大frameid
-func (e *Entry) CurrentMaxXFrameId(neckRingNumber, activeDate string) (frameid int32) {
-	type Fm struct {
-		Frameid int32
-	}
-	maxFx := &Fm{}
-	if err := e.DB.Model(new(model.NeckRingOriginal)).
-		Select("frameid").
-		Where("neck_ring_number = ?", neckRingNumber).
-		Where("active_date = ?", activeDate).
-		Order("frameid DESC").First(maxFx).Error; err != nil {
-		zaplog.Error("CurrentMaxXFrameId", zap.Any("err", err))
-		return 0
-	}
-	return maxFx.Frameid
-}
-
-func (e *Entry) UpdateNeckRingOriginalIsShow(neckRingList *model.NeckActiveHabit) error {
-	if err := e.DB.Model(new(model.NeckRingOriginal)).
-		Where("neck_ring_number = ?", neckRingList.NeckRingNumber).
-		Where("active_date = ?", neckRingList.HeatDate).
-		Where("frameid IN (?)", util.FrameIds(neckRingList.Frameid)).
-		Update("is_show", pasturePb.IsShow_Ok).Error; err != nil {
-		return xerr.WithStack(err)
-	}
-	return nil
-}
-
 func (e *Entry) MsgDataFormat(msg []byte) []*model.NeckRingOriginal {
 	msgData := make(map[string]interface{})
 	pairs := strings.Split(util.MsgFormat(string(msg)), " ")

+ 0 - 103
module/mqtt/neck_ring_habit_test.go

@@ -1,103 +0,0 @@
-package mqtt
-
-import (
-	"encoding/json"
-	"fmt"
-	"kpt-pasture/model"
-	"testing"
-)
-
-func TestFirstFilterUpdate(t *testing.T) {
-	newNeckActiveHabitList := []*model.NeckActiveHabit{
-		{
-			Id:             1,
-			NeckRingNumber: "123",
-			High:           731,
-			Rumina:         20,
-			Intake:         0,
-			Inactive:       65,
-			Gasp:           1,
-			Other:          0,
-			Active:         27,
-			FilterHigh:     0,
-			FilterRumina:   0,
-			FilterChew:     0,
-		},
-		{
-			Id:             2,
-			NeckRingNumber: "123",
-			High:           318,
-			Rumina:         55,
-			Intake:         2,
-			Inactive:       99,
-			Gasp:           1,
-			Other:          0,
-			Active:         18,
-			FilterHigh:     0,
-			FilterRumina:   0,
-			FilterChew:     0,
-		},
-		{
-			Id:             2,
-			NeckRingNumber: "123",
-			High:           254,
-			Rumina:         68,
-			Intake:         0,
-			Inactive:       114,
-			Gasp:           22,
-			Other:          0,
-			Active:         6,
-			FilterHigh:     0,
-			FilterRumina:   0,
-			FilterChew:     0,
-		},
-	}
-
-	test(newNeckActiveHabitList)
-}
-
-func test(newNeckActiveHabitList []*model.NeckActiveHabit) {
-
-	var (
-		neckRingNumber string
-		filterHigh     float64
-		filterRumina   float64
-		filterChew     float64
-	)
-	// 活动量滤波
-	for _, v := range newNeckActiveHabitList {
-		if v.FilterHigh > 0 {
-			filterHigh = float64(v.FilterHigh)
-		} else {
-			if v.NeckRingNumber == neckRingNumber {
-				filterHigh = computeIfPositiveElse(float64(v.High), filterHigh, 0.23, 0.77)
-			} else {
-				filterHigh = float64(v.High)
-			}
-		}
-
-		if v.FilterRumina > 0 {
-			filterRumina = float64(v.FilterRumina)
-		} else {
-			if v.NeckRingNumber == neckRingNumber {
-				filterRumina = computeIfPositiveElse(float64(v.Rumina), filterRumina, 0.33, 0.67)
-			} else {
-				filterRumina = float64(v.Rumina)
-			}
-		}
-		if v.FilterChew > 0 {
-			filterChew = float64(v.FilterChew)
-		} else {
-			if v.NeckRingNumber == neckRingNumber {
-				filterChew = computeIfPositiveElse(float64(v.Rumina+v.Intake), filterChew, 0.33, 0.67)
-			} else {
-				filterChew = float64(v.Rumina + v.Intake)
-			}
-		}
-
-		// 	Select("filter_high", "filter_rumina", "filter_chew")
-		b, _ := json.Marshal(v)
-		fmt.Println("======v=====", string(b))
-	}
-
-}

+ 0 - 111
module/mqtt/sql.go

@@ -1,15 +1,8 @@
 package mqtt
 
 import (
-	"errors"
 	"kpt-pasture/model"
 
-	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
-	"go.uber.org/zap"
-
-	"gitee.com/xuyiping_admin/pkg/xerr"
-	"gorm.io/gorm"
-
 	pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
 )
 
@@ -26,107 +19,3 @@ func (e *Entry) NeckRingIsBind(number string) bool {
 	}
 	return false
 }
-
-func (e *Entry) GetCowInfoByNeckRingNumber(pastureId int64, neckRingNumber string) *model.Cow {
-	res := &model.Cow{}
-	if err := e.DB.Model(new(model.Cow)).
-		Where("pasture_id = ?", pastureId).
-		Where("neck_ring_number = ?", neckRingNumber).
-		Where("admission_status = ?", pasturePb.AdmissionStatus_Admission).
-		First(res).Error; err != nil {
-		return nil
-	}
-	return res
-}
-
-func (e *Entry) GetSystemConfigure(name string) *model.SystemConfigure {
-	res := &model.SystemConfigure{}
-	if err := e.DB.Model(new(model.SystemConfigure)).
-		Where("name = ?", name).
-		Where("is_show = ?", pasturePb.IsShow_Ok).
-		First(res).Error; err != nil {
-		return nil
-	}
-	return res
-}
-
-func (e *Entry) IsExistNeckActiveHabit(neckRingNumber, heatDate string, frameId int32) (*model.NeckActiveHabit, int64) {
-	count := int64(0)
-	neckRingProcess := &model.NeckRingProcess{}
-	if err := e.DB.Model(new(model.NeckRingProcess)).
-		Where("neck_ring_number = ?", neckRingNumber).
-		Where("active_date = ?", heatDate).
-		Where("frameid = ?", frameId).
-		Count(&count).
-		First(neckRingProcess).Error; err != nil {
-		return nil, 0
-	}
-
-	res := &model.NeckActiveHabit{}
-	if neckRingProcess != nil {
-		if neckRingProcess.HabitId > 0 {
-			if err := e.DB.Model(new(model.NeckActiveHabit)).
-				Where("id = ?", neckRingProcess.HabitId).
-				First(res).Error; err != nil {
-				return nil, 0
-			}
-		} else {
-			if err := e.DB.Model(new(model.NeckActiveHabit)).
-				Where("heat_date = ?", heatDate).
-				Where("neck_ring_number = ?", neckRingNumber).
-				Where("frameid = ?", frameId).
-				First(res).Error; err != nil {
-				return nil, 0
-			}
-
-			if err := e.DB.Model(new(model.NeckRingProcess)).
-				Where("id = ?", neckRingProcess.Id).
-				Where("frameid = ?", frameId).
-				Update("habit_id", res.Id).Error; err != nil {
-				return nil, 0
-			}
-		}
-	}
-	return res, count
-}
-
-// GetMinIdByHeatDate 获取最小的id
-func (e *Entry) GetMinIdByHeatDate(heatDate string, defaultId int64) (int64, error) {
-	xMinId := struct {
-		Id int64
-	}{}
-	if err := e.DB.Model(new(model.NeckActiveHabit)).
-		Select("MIN(id) as id").
-		Where("heat_date = ?", heatDate).
-		First(&xMinId).Error; err != nil {
-		if errors.Is(err, gorm.ErrRecordNotFound) {
-			xMinId.Id = defaultId
-		} else {
-			return 0, xerr.WithStack(err)
-		}
-	}
-	return xMinId.Id, nil
-}
-
-func (e *Entry) FindPastureList() []*model.AppPastureList {
-	res := make([]*model.AppPastureList, 0)
-	if err := e.DB.Model(new(model.AppPastureList)).
-		Where("is_show = ?", pasturePb.IsShow_Ok).
-		Find(&res).Error; err != nil {
-		zaplog.Error("FindPastureList error", zap.Any("err", err))
-		return res
-	}
-	return res
-}
-
-func (e *Entry) GetSystemConfigure2(pastureId int64, name string) (*model.SystemConfigure, error) {
-	res := &model.SystemConfigure{}
-	if err := e.DB.Model(new(model.SystemConfigure)).
-		Where("name = ?", name).
-		Where("pasture_id = ?", pastureId).
-		Where("is_show = ?", pasturePb.IsShow_Ok).
-		First(res).Error; err != nil {
-		return nil, xerr.WithStack(err)
-	}
-	return res, nil
-}

+ 0 - 66
module/mqtt/work_cron_test.go

@@ -1,66 +0,0 @@
-package mqtt
-
-import (
-	"encoding/json"
-	"fmt"
-	"kpt-pasture/model"
-	"testing"
-)
-
-func TestEntry_SameTimePlan(t *testing.T) {
-	neckActiveHabit := make([]*model.NeckActiveHabit, 0)
-	neckActiveHabit = append(neckActiveHabit, &model.NeckActiveHabit{
-		Id:           14489593,
-		CowId:        71,
-		High:         1611,
-		Rumina:       32,
-		Intake:       67,
-		FilterHigh:   0,
-		FilterRumina: 0,
-		FilterChew:   0,
-	}, &model.NeckActiveHabit{
-		Id:           14490832,
-		CowId:        71,
-		High:         1295,
-		Rumina:       26,
-		Intake:       46,
-		FilterRumina: 0,
-		FilterHigh:   0,
-		FilterChew:   0,
-	})
-
-	var (
-		filterValues = make(map[int64]*model.NeckActiveHabit)
-	)
-	// 活动量滤波
-	for _, v := range neckActiveHabit {
-		prev, ok := filterValues[v.CowId]
-		if !ok {
-			if v.FilterHigh <= 0 {
-				v.FilterHigh = v.High
-			}
-			if v.FilterRumina <= 0 {
-				v.FilterRumina = v.Rumina
-			}
-			if v.FilterChew <= 0 {
-				v.FilterChew = v.Rumina + v.Intake
-			}
-			filterValues[v.CowId] = v
-			continue
-		}
-		if v.FilterHigh <= 0 {
-			v.FilterHigh = int32(computeIfPositiveElse(float64(v.High), float64(prev.FilterHigh), 0.23, 0.77))
-		}
-		if v.FilterRumina <= 0 {
-			v.FilterRumina = int32(computeIfPositiveElse(float64(v.Rumina), float64(prev.FilterRumina), 0.33, 0.67))
-		}
-		if v.FilterChew <= 0 {
-			v.FilterChew = int32(computeIfPositiveElse(float64(v.Rumina+v.Intake), float64(prev.FilterChew), 0.33, 0.67))
-		}
-		// 更新过滤值
-		filterValues[v.CowId] = v
-	}
-
-	b, _ := json.Marshal(neckActiveHabit)
-	fmt.Println(string(b))
-}

+ 0 - 8
service/mqtt/interface.go

@@ -113,8 +113,6 @@ func (s *IMqttClient) Run(enter handleMqtt.Entry) {
 	stop := make(chan os.Signal, 1)
 	signal.Notify(stop, os.Kill, os.Interrupt, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
 
-	ticker := time.NewTicker(time.Duration(s.Config.MergeDataTicker) * time.Minute)
-	habitTicker := time.NewTicker(time.Duration(s.Config.MergeDataTicker) * time.Minute)
 	// 创建上下文,用于优雅关闭
 	ctx, cancel := context.WithCancel(context.Background())
 	defer cancel()
@@ -126,13 +124,7 @@ func (s *IMqttClient) Run(enter handleMqtt.Entry) {
 			case <-stop:
 				cancel()
 				s.Close()
-				habitTicker.Stop()
-				ticker.Stop()
 				return
-			case <-ticker.C:
-				enter.NeckRingOriginalMergeData()
-			case <-habitTicker.C:
-				enter.PastureUpdateActiveHabit()
 			case <-ctx.Done():
 				return
 			}

+ 27 - 1
util/util.go

@@ -36,7 +36,33 @@ var (
 		101: 101, 102: 102, 103: 103, 104: 104, 105: 105, 106: 106, 108: 108, // 20-22
 		111: 111, 112: 112, 113: 113, 114: 114, 115: 115, 116: 116, 118: 118, // 22-24
 	}
-	SpecialHours = map[int]int{8: 2, 18: 4, 28: 6, 38: 8, 48: 10, 58: 12, 68: 14, 78: 16, 88: 18, 98: 20, 108: 22, 118: 0}
+	SpecialHours      = map[int]int{8: 2, 18: 4, 28: 6, 38: 8, 48: 10, 58: 12, 68: 14, 78: 16, 88: 18, 98: 20, 108: 22, 118: 0}
+	FrameIdMapReverse = map[int32]int32{
+		0:  8,
+		1:  8,
+		2:  18,
+		3:  18,
+		4:  28,
+		5:  28,
+		6:  38,
+		7:  38,
+		8:  48,
+		9:  48,
+		10: 58,
+		11: 58,
+		12: 68,
+		13: 68,
+		14: 78,
+		15: 78,
+		16: 88,
+		17: 88,
+		18: 98,
+		19: 98,
+		20: 108,
+		21: 108,
+		22: 118, // 04-06
+		23: 118,
+	}
 )
 
 // GenerateRandomNumberString 生成指定长度的数字串

+ 2 - 3
util/util_test.go

@@ -2,6 +2,7 @@ package util
 
 import (
 	"fmt"
+	"math"
 	"testing"
 	"time"
 
@@ -521,7 +522,5 @@ type XToday struct {
 }
 
 func Test_demo(t *testing.T) {
-	for i := 0; i < 23; i++ {
-		fmt.Println(CurrentMaxFrameId())
-	}
+	fmt.Println(math.Round(float64(44-0) / float64(0) * 100))
 }