cow_neck_ring_error.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. package crontab
  2. import (
  3. "errors"
  4. "fmt"
  5. "kpt-pasture/model"
  6. "kpt-pasture/util"
  7. "time"
  8. "gorm.io/gorm"
  9. pasturePb "gitee.com/xuyiping_admin/go_proto/proto/go/backend/cow"
  10. "gitee.com/xuyiping_admin/pkg/logger/zaplog"
  11. "go.uber.org/zap"
  12. )
  13. // CowNeckRingErrorEnter 异常脖环监控 create_jbq_tj
  14. func (e *Entry) CowNeckRingErrorEnter() (err error) {
  15. pastureList := e.FindPastureList()
  16. if pastureList == nil || len(pastureList) == 0 {
  17. return nil
  18. }
  19. for _, pasture := range pastureList {
  20. e.CowNeckRingError(pasture.Id)
  21. e.NeckRingLastDate(pasture.Id)
  22. zaplog.Error("CowNeckRingErrorEnter-Success", zap.Any("pasture", pasture))
  23. }
  24. return nil
  25. }
  26. func (e *Entry) CowNeckRingError(pastureId int64) {
  27. yesterday := time.Now().Local().AddDate(0, 0, -1).Format(model.LayoutDate2)
  28. habitMinId, originalMinId := 0, 0
  29. if err := e.DB.Model(new(model.NeckActiveHabit)).
  30. Select("IFNULL(MIN(id),0) as id").
  31. Where("pasture_id = ?", pastureId).
  32. Where("heat_date = ?", yesterday).
  33. Scan(&habitMinId).Error; err != nil {
  34. zaplog.Error("CowNeckRingError-Error", zap.Any("pastureId", pastureId), zap.Any("err", err))
  35. return
  36. }
  37. if err := e.DB.Model(new(model.NeckRingOriginal)).
  38. Select("IFNULL(MIN(id),0) as id").
  39. Where("pasture_id = ?", pastureId).
  40. Where("active_date = ?", yesterday).
  41. Scan(&originalMinId).Error; err != nil {
  42. zaplog.Error("CowNeckRingError-Error", zap.Any("pastureId", pastureId), zap.Any("err", err))
  43. return
  44. }
  45. minIsBindDate := util.TimeParseLocalUnix(yesterday)
  46. neckRingList := make([]*model.NeckRing, 0)
  47. if err := e.DB.Model(new(model.NeckRing)).
  48. Where("pasture_id = ?", pastureId).
  49. Where("is_bind = ?", pasturePb.IsShow_Ok).
  50. Where("wear_at <= ?", minIsBindDate).
  51. Find(&neckRingList).Error; err != nil {
  52. zaplog.Error("NeckRingErrorOfNoSignal", zap.Any("err", err), zap.Any("pastureId", pastureId))
  53. }
  54. updateNeckRingMap := make(map[int64]*model.NeckRingStats)
  55. errorMap := e.NeckRingErrorMap()
  56. for _, neckRing := range neckRingList {
  57. var info bool
  58. // 佩戴后无信号
  59. c1 := e.NeckRingErrorOfNoSignal(pastureId, neckRing, int64(habitMinId), yesterday)
  60. if c1 > 0 {
  61. updateNeckRingMap[neckRing.Id] = &model.NeckRingStats{
  62. Status: pasturePb.IsShow_No,
  63. ErrorKind: c1,
  64. ErrorReason: errorMap[c1],
  65. Describe: "",
  66. }
  67. }
  68. // '疑似脱落', '电量低','接收少'
  69. c2 := e.NeckRingErrorOfSuspectedFallOffAndLowBattery(pastureId, neckRing, int64(habitMinId), yesterday)
  70. if c2 > 0 {
  71. updateNeckRingMap[neckRing.Id] = &model.NeckRingStats{
  72. Status: pasturePb.IsShow_No,
  73. ErrorKind: c2,
  74. ErrorReason: errorMap[c2],
  75. Describe: "",
  76. }
  77. }
  78. // 接收少
  79. c3 := e.NeckRingErrorOfReceivingLess(pastureId, neckRing, int64(habitMinId), int64(originalMinId), yesterday)
  80. if c3 > 0 {
  81. updateNeckRingMap[neckRing.Id] = &model.NeckRingStats{
  82. Status: pasturePb.IsShow_No,
  83. ErrorKind: c3,
  84. ErrorReason: errorMap[c3],
  85. Describe: "",
  86. }
  87. }
  88. // 数据延迟
  89. c4 := e.NeckRingErrorOfDataLatency(pastureId, neckRing, int64(habitMinId), yesterday)
  90. if c4 > 0 {
  91. updateNeckRingMap[neckRing.Id] = &model.NeckRingStats{
  92. Status: pasturePb.IsShow_No,
  93. ErrorKind: c4,
  94. ErrorReason: errorMap[c4],
  95. Describe: "",
  96. }
  97. }
  98. if c1 > 0 || c2 > 0 || c3 > 0 || c4 > 0 {
  99. info = true
  100. }
  101. if !info {
  102. updateNeckRingMap[neckRing.Id] = &model.NeckRingStats{
  103. Status: pasturePb.IsShow_Ok,
  104. ErrorKind: 0,
  105. ErrorReason: "",
  106. Describe: "",
  107. }
  108. }
  109. }
  110. zaplog.Info("CowNeckRingError", zap.Any("updateNeckRingMap", updateNeckRingMap))
  111. if len(updateNeckRingMap) > 0 {
  112. for id, v := range updateNeckRingMap {
  113. if err := e.DB.Model(new(model.NeckRing)).
  114. Where("id = ?", id).
  115. Updates(map[string]interface{}{
  116. "status": v.Status,
  117. "error_kind": v.ErrorKind,
  118. "error_reason": v.ErrorReason,
  119. "describe": v.Describe,
  120. }).Error; err != nil {
  121. zaplog.Error("CowNeckRingError", zap.Any("err", err), zap.Any("id", id), zap.Any("v", v))
  122. }
  123. }
  124. }
  125. }
  126. // NeckRingErrorOfNoSignal 佩戴后无信号
  127. func (e *Entry) NeckRingErrorOfNoSignal(pastureId int64, neckRing *model.NeckRing, minId int64, dateTime string) pasturePb.NeckRingNumberError_Kind {
  128. var count int64
  129. if err := e.DB.Model(new(model.NeckActiveHabit)).
  130. Where("id >= ?", minId).
  131. Where("neck_ring_number = ?", neckRing.NeckRingNumber).
  132. Where("pasture_id = ?", pastureId).
  133. Where("heat_date >= ?", dateTime).
  134. Count(&count).Error; err != nil {
  135. zaplog.Error("NeckRingErrorOfNoSignal", zap.Any("err", err), zap.Any("pastureId", pastureId))
  136. }
  137. if count <= 0 {
  138. return pasturePb.NeckRingNumberError_No_Signal
  139. }
  140. return pasturePb.NeckRingNumberError_Invalid
  141. }
  142. // NeckRingErrorOfSuspectedFallOffAndLowBattery '疑似脱落', '电量低','接收少'
  143. func (e *Entry) NeckRingErrorOfSuspectedFallOffAndLowBattery(pastureId int64, neckRing *model.NeckRing, minId int64, dateTime string) pasturePb.NeckRingNumberError_Kind {
  144. nowTime := time.Now().Local()
  145. neckRingHabitList := make([]*model.NeckActiveHabit, 0)
  146. if err := e.DB.Model(new(model.NeckActiveHabit)).
  147. Where("id >= ?", minId).
  148. Where("neck_ring_number = ?", neckRing.NeckRingNumber).
  149. Where("pasture_id = ?", pastureId).
  150. Where("heat_date >= ?", dateTime).
  151. Find(&neckRingHabitList).Error; err != nil {
  152. zaplog.Error("suspectedFallOffAndLowBattery", zap.Any("err", err), zap.Any("pastureId", pastureId))
  153. return pasturePb.NeckRingNumberError_Invalid
  154. }
  155. nba, nb1, nbHh, nbh, voltage := 0, 0, 0, 0, int32(0)
  156. for _, v := range neckRingHabitList {
  157. nba++
  158. if v.High <= 50 && v.Rumina <= 5 {
  159. nb1 += 1
  160. }
  161. at := util.DateTimeParseLocalUnix(v.ActiveTime)
  162. nowTimeUnix := nowTime.Unix()
  163. hoursDiff := (nowTimeUnix - at) / 3600
  164. sumRuminaIntake := v.SumRumina + v.SumIntake
  165. if hoursDiff <= 8 && (v.High > 0 || sumRuminaIntake > 20) {
  166. nbHh++
  167. }
  168. if v.High > 100 || v.Rumina > 5 {
  169. nbh++
  170. }
  171. voltage += v.Voltage
  172. }
  173. svgVoltage := int32(float32(voltage) / float32(nba))
  174. errorKind := pasturePb.NeckRingNumberError_Invalid
  175. switch {
  176. case svgVoltage <= 275:
  177. errorKind = pasturePb.NeckRingNumberError_Low_Battery
  178. case nb1 >= 4:
  179. errorKind = pasturePb.NeckRingNumberError_Suspected_Fall_Off
  180. default:
  181. errorKind = pasturePb.NeckRingNumberError_Receiving_Less
  182. }
  183. if (nb1 >= 4 && nbHh <= 1) || svgVoltage <= 275 || nba <= (5+nowTime.Hour()/4-1) {
  184. return errorKind
  185. }
  186. return pasturePb.NeckRingNumberError_Invalid
  187. }
  188. // NeckRingErrorOfReceivingLess '接收少'
  189. func (e *Entry) NeckRingErrorOfReceivingLess(pastureId int64, neckRing *model.NeckRing, habitMinId, originalMinId int64, dateTime string) pasturePb.NeckRingNumberError_Kind {
  190. var count int64
  191. if err := e.DB.Model(new(model.NeckRing)).
  192. Where("pasture_id = ?", pastureId).
  193. Where("neck_ring_number = ?", neckRing.NeckRingNumber).
  194. Where("status = ?", pasturePb.IsShow_No).
  195. Count(&count).Error; err != nil {
  196. zaplog.Error("NeckRingErrorOfReceivingLess", zap.Any("err", err), zap.Any("pastureId", pastureId))
  197. return pasturePb.NeckRingNumberError_Invalid
  198. }
  199. // 已存在就不再处理
  200. if count > 0 {
  201. return pasturePb.NeckRingNumberError_Invalid
  202. }
  203. if err := e.DB.Model(new(model.NeckActiveHabit)).
  204. Where("id >= ?", habitMinId).
  205. Where("neck_ring_number = ?", neckRing.NeckRingNumber).
  206. Where("pasture_id = ?", pastureId).
  207. Where("heat_date >= ?", dateTime).
  208. Count(&count).Error; err != nil {
  209. zaplog.Error("NeckRingErrorOfReceivingLess", zap.Any("err", err), zap.Any("pastureId", pastureId))
  210. }
  211. // 已存在就不再处理
  212. if count > 0 {
  213. return pasturePb.NeckRingNumberError_Invalid
  214. }
  215. // 查询原始活动数据统计信息
  216. var originalStats struct {
  217. Count int64
  218. AvgVoltage float64
  219. }
  220. if err := e.DB.Model(new(model.NeckRingOriginal)).
  221. Select("COUNT(*) as count, ROUND(AVG(voltage)) as avg_voltage").
  222. Where("id >= ?", originalMinId).
  223. Where("neck_ring_number = ?", neckRing.NeckRingNumber).
  224. Where("pasture_id = ?", pastureId).
  225. Where("heat_date >= ?", dateTime).
  226. First(&originalStats).Error; err != nil {
  227. zaplog.Error("NeckRingOriginal", zap.Any("err", err), zap.Any("pasture_id", pastureId))
  228. return pasturePb.NeckRingNumberError_Invalid
  229. }
  230. // 创建错误记录
  231. errorKind := pasturePb.NeckRingNumberError_Receiving_Less
  232. if originalStats.AvgVoltage <= 285 {
  233. errorKind = pasturePb.NeckRingNumberError_Low_Battery
  234. }
  235. // 限制最大显示数量为99
  236. displayCount := originalStats.Count
  237. if displayCount > 99 {
  238. displayCount = 99
  239. }
  240. if displayCount > 0 {
  241. return errorKind
  242. }
  243. return pasturePb.NeckRingNumberError_Invalid
  244. }
  245. // NeckRingErrorOfDataLatency 数据延迟
  246. func (e *Entry) NeckRingErrorOfDataLatency(pastureId int64, neckRing *model.NeckRing, habitMinId int64, dateTime string) pasturePb.NeckRingNumberError_Kind {
  247. res := make([]*model.NeckRingErrorModel, 0)
  248. if err := e.DB.Model(new(model.NeckActiveHabit)).
  249. Select(`cow_id,ear_number, SUM(IF(TIMESTAMPDIFF(HOUR, UNIX_TIMESTAMP(active_time), created_at)>9, 1, 0)) AS nb, COUNT(1) AS nba, ROUND(AVG(voltage), 0) AS voltage`).
  250. Where("id >= ?", habitMinId).
  251. Where("cow_id = ?", neckRing.CowId).
  252. Where("filter_high > ?", 200).
  253. Where("heat_date >= ?", dateTime).
  254. Having("nb/nba >= ?", 0.7).
  255. Find(&res).Error; err != nil {
  256. zaplog.Error("NeckRingErrorOfDataLatency", zap.Any("err", err), zap.Any("pastureId", pastureId))
  257. }
  258. if len(res) > 0 {
  259. return pasturePb.NeckRingNumberError_Data_Latency
  260. }
  261. return pasturePb.NeckRingNumberError_Invalid
  262. }
  263. // NeckRingLastDate 获取牧场脖环最后数据时间
  264. func (e *Entry) NeckRingLastDate(pastureId int64) {
  265. lastOriginalData := &model.NeckRingOriginal{}
  266. if err := e.DB.Model(new(model.NeckRingOriginal)).
  267. Where("pasture_id = ?", pastureId).
  268. Order("id DESC").
  269. First(&lastOriginalData).Error; err != nil {
  270. zaplog.Error("NeckRingLastDate", zap.Any("err", err), zap.Any("pastureId", pastureId))
  271. }
  272. if lastOriginalData.CreatedAt <= 0 {
  273. return
  274. }
  275. nowTime := time.Now().Local()
  276. subMinutes := nowTime.Sub(time.Unix(lastOriginalData.CreatedAt, 0)).Minutes()
  277. if subMinutes < model.DefaultDataLatencyMinutes {
  278. return
  279. }
  280. hours := int(subMinutes) / 60
  281. minutes := int(subMinutes) % 60
  282. content := fmt.Sprintf("距离目前已经%d小时%d分钟未接收到脖环数据,核实是否有电,如有电请及时联系服务工程师", hours, minutes)
  283. historyData := &model.DataNotice{}
  284. if err := e.DB.Model(new(model.DataNotice)).
  285. Where("pasture_id = ?", pastureId).
  286. Where("notice_kind = ?", pasturePb.NoticeType_Neck_Ring_Data_Latency).
  287. Where("start_date = ?", nowTime.Format(model.LayoutDate2)).
  288. First(&historyData).Error; err != nil {
  289. if !errors.Is(err, gorm.ErrRecordNotFound) {
  290. return
  291. }
  292. }
  293. if historyData.Id > 0 {
  294. historyData.UpdateNotice(content)
  295. if err := e.DB.Model(new(model.DataNotice)).
  296. Select("content", "known_users").
  297. Where("id = ?", historyData.Id).
  298. Updates(historyData).Error; err != nil {
  299. zaplog.Error("NeckRingLastDate", zap.Any("err", err), zap.Any("pastureId", pastureId))
  300. }
  301. } else {
  302. newDataNotice := model.NewDataNotice(pastureId, model.DataLatencyTitle, content, pasturePb.NoticeType_Neck_Ring_Data_Latency)
  303. if err := e.DB.Model(new(model.DataNotice)).
  304. Create(newDataNotice).Error; err != nil {
  305. zaplog.Error("NeckRingLastDate", zap.Any("err", err), zap.Any("pastureId", pastureId))
  306. }
  307. }
  308. }