cow_neck_ring_error.go 10 KB

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