datacaps.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/redis/go-redis/v9"
  6. "github.com/xuri/excelize/v2"
  7. "log"
  8. "strconv"
  9. "time"
  10. "ydMonitoring/config"
  11. "ydMonitoring/databases"
  12. "ydMonitoring/util"
  13. )
  14. /*
  15. *
  16. DataCaps
  17. * 得到所有设备的SN并且通过SN得到表名
  18. * z_device_data_sn
  19. * 查找该表内最新的一条数据信息并且查询该设备数据上传时间,并且通过该时间
  20. * 判断前5分钟内的数据是否缺失,如有缺失,直接推送短信告警,并记录在数据库里面(时间、客户名称、SN、数据缺失的时间、是否处理、处理人、处理时间)
  21. * 新增:获取每个t_id的前10条数据进行两两比较,最后一条数据还需与当前时间进行比较判断在设定时间内是否有数据缺失
  22. * 新增:每一个探头当天内只保存一次数据
  23. *
  24. */
  25. var RedisClient *redis.Client
  26. func init() {
  27. RedisClient = redis.NewClient(&redis.Options{
  28. Addr: config.Config.GetString("redis.host"),
  29. Password: config.Config.GetString("redis.password"), // no password set
  30. DB: 0, // use default DB
  31. })
  32. ping := RedisClient.Ping(context.Background())
  33. if ping.Err() != nil {
  34. log.Println("redis连接失败:", ping.Err())
  35. panic("redis连接失败")
  36. }
  37. }
  38. func DataCaps(devices []Device) {
  39. message := make([]string, 0)
  40. // 文件名
  41. var row = 2
  42. filename := fmt.Sprintf("%s.xlsx", time.Now().Format("2006-01-02"))
  43. file, err := excelize.OpenFile(filename)
  44. if err != nil {
  45. file = excelize.NewFile()
  46. // 创建工作区
  47. sheet := "sheet1"
  48. file.NewSheet(sheet)
  49. // 设置列标题
  50. file.SetCellValue(sheet, "A1", "设备SN")
  51. file.SetCellValue(sheet, "B1", "公司名称")
  52. file.SetCellValue(sheet, "C1", "设备名称")
  53. file.SetCellValue(sheet, "D1", "探头")
  54. file.SetCellValue(sheet, "E1", "数据缺失开始时间")
  55. } else {
  56. // 获取最后一行
  57. lastRow, err := getLastRow(file, "sheet1")
  58. if err != nil {
  59. log.Println("获取Excel文件失败:", err)
  60. return
  61. }
  62. row = lastRow + 1
  63. }
  64. sqllist := make([]string, 0)
  65. for _, v := range devices {
  66. //log.Println(v.Tsn)
  67. sql := fmt.Sprintf("select t_sn,t_id,t_pid,t_name from device_sensor where t_sn = %s", v.Tsn)
  68. sqllist = append(sqllist, sql)
  69. }
  70. deviceSensor := make([]DeviceSensor, 0)
  71. for _, sql := range sqllist {
  72. query, _ := databases.Db.Query(sql)
  73. var sn, t_id, t_pid, t_name string
  74. if query != nil {
  75. for query.Next() {
  76. query.Scan(&sn, &t_id, &t_pid, &t_name)
  77. deviceSensor = append(deviceSensor, DeviceSensor{sn, t_id, t_pid, t_name})
  78. }
  79. }
  80. }
  81. for _, sensor := range deviceSensor {
  82. var t_time string
  83. var t_save_t string
  84. var companyname string
  85. var id string
  86. b, _ := Ignore(sensor.Tsn)
  87. if b {
  88. log.Println("该设备已忽略:", sensor.Tsn)
  89. } else {
  90. sql := fmt.Sprintf("SELECT t_time FROM z_device_data_%s WHERE t_id = '%s' ORDER BY t_time DESC LIMIT 3", sensor.Tsn, sensor.TId)
  91. sqls := fmt.Sprintf("SELECT t_save_t FROM device_parameter WHERE t_sn='%s' ORDER BY update_time DESC LIMIT 1", sensor.Tsn)
  92. company := fmt.Sprintf("SELECT t_name,id FROM company WHERE id='%s'", sensor.TPid)
  93. databases.Db.QueryRow(sqls).Scan(&t_save_t)
  94. databases.Db.QueryRow(company).Scan(&companyname, &id)
  95. rows, err := databases.Db.Query(sql)
  96. if err != nil {
  97. log.Println("查询数据失败:", err)
  98. continue
  99. }
  100. defer rows.Close()
  101. var times []string
  102. for rows.Next() {
  103. var t string
  104. rows.Scan(&t)
  105. times = append(times, t)
  106. }
  107. if len(times) >= 2 {
  108. // 比较前3条数据
  109. timeFormat := "2006-01-02 15:04:05"
  110. for i := 0; i < len(times)-1; i++ {
  111. t1, err := time.Parse(timeFormat, times[i])
  112. if err != nil {
  113. log.Println("解析时间失败:", err)
  114. continue
  115. }
  116. t2, err := time.Parse(timeFormat, times[i+1])
  117. if err != nil {
  118. log.Println("解析时间失败:", err)
  119. continue
  120. }
  121. timeDiff := t1.Sub(t2).Seconds()
  122. float, _ := strconv.ParseFloat(t_save_t, 64) //获取系统设置时间
  123. // 获取今天的开始时间
  124. todayStart := time.Now().Truncate(24 * time.Hour)
  125. // 确保t1表示的时间为今天
  126. if t1.After(todayStart) || t1.Equal(todayStart) {
  127. DeviationValue := timeDiff - float
  128. if DeviationValue > 30 {
  129. //生成一个独立的key
  130. key := fmt.Sprintf("%s_%s_%s_%s", sensor.Tsn, companyname+"["+id+"]", sensor.TName, sensor.TId)
  131. //fmt.Println(key)
  132. nowday := time.Now()
  133. midnight := time.Date(nowday.Year(), nowday.Month(), nowday.Day()+1, 0, 0, 0, 0, nowday.Location())
  134. remainingTime := midnight.Sub(nowday)
  135. result, err := RedisClient.SetNX(context.Background(), key, 1, remainingTime).Result()
  136. if err != nil {
  137. log.Println("redis写入失败:", err)
  138. } else if result {
  139. wx := util.WxStruct{
  140. Character: sensor.Tsn,
  141. Thing13: companyname,
  142. Thing3: sensor.TName,
  143. Thing45: sensor.TId,
  144. Time2: times[i],
  145. }
  146. slice := config.Config.GetStringSlice("openID")
  147. for _, v := range slice {
  148. fmt.Println(v, wx)
  149. util.Send(v, wx)
  150. }
  151. message = append(message, fmt.Sprintf("Sn:%s==>%s==>设备:%s==>探头%s==>数据缺失上传时间:%s \n", sensor.Tsn, companyname+"["+id+"]", sensor.TName, sensor.TId, times[i]))
  152. // 将相关信息记录到Excel文件中
  153. if !dataExists(file, "sheet1", sensor.Tsn, companyname+"["+id+"]", sensor.TName, sensor.TId, times[i+1]) {
  154. file.SetCellValue("sheet1", fmt.Sprintf("A%d", row), sensor.Tsn)
  155. file.SetCellValue("sheet1", fmt.Sprintf("B%d", row), companyname+"["+id+"]")
  156. file.SetCellValue("sheet1", fmt.Sprintf("C%d", row), sensor.TName)
  157. file.SetCellValue("sheet1", fmt.Sprintf("D%d", row), sensor.TId)
  158. file.SetCellValue("sheet1", fmt.Sprintf("E%d", row), times[i+1]) // 数据缺失开始时间
  159. row++
  160. }
  161. }
  162. }
  163. }
  164. }
  165. // 最后一条数据与当前时间比较
  166. if len(times) > 0 {
  167. t_time = times[0]
  168. t1, err := time.Parse(timeFormat, t_time)
  169. if err != nil {
  170. log.Println("解析时间失败:", err)
  171. continue
  172. }
  173. now := time.Now().Format(timeFormat)
  174. nows, _ := time.Parse(timeFormat, now)
  175. timeDiff := nows.Sub(t1).Seconds()
  176. // 获取今天的开始时间
  177. todayStart := time.Now().Truncate(24 * time.Hour)
  178. // 确保t1表示的时间为今天
  179. if t1.After(todayStart) || t1.Equal(todayStart) {
  180. float, _ := strconv.ParseFloat(t_save_t, 64)
  181. DeviationValue := timeDiff - float
  182. if DeviationValue > 30 {
  183. key := fmt.Sprintf("%s_%s_%s_%s", sensor.Tsn, companyname+"["+id+"]", sensor.TName, sensor.TId)
  184. nowday := time.Now()
  185. midnight := time.Date(nowday.Year(), nowday.Month(), nowday.Day()+1, 0, 0, 0, 0, nowday.Location())
  186. remainingTime := midnight.Sub(nowday)
  187. result, err := RedisClient.SetNX(context.Background(), key, 1, remainingTime).Result()
  188. if err != nil {
  189. log.Println("redis写入失败:", err)
  190. } else if result {
  191. wx := util.WxStruct{
  192. Character: sensor.Tsn,
  193. Thing13: companyname,
  194. Thing3: sensor.TName,
  195. Thing45: sensor.TId,
  196. Time2: t_time,
  197. }
  198. slice := config.Config.GetStringSlice("openID")
  199. for _, v := range slice {
  200. fmt.Println(v, wx)
  201. util.Send(v, wx)
  202. }
  203. message = append(message, fmt.Sprintf("Sn:%s==>%s==>设备:%s==>探头%s==>数据缺失上传时间:%s \n", sensor.Tsn, companyname+"["+id+"]", sensor.TName, sensor.TId, t_time))
  204. // 将相关信息记录到Excel文件中
  205. if !dataExists(file, "sheet1", sensor.Tsn, companyname+"["+id+"]", sensor.TName, sensor.TId, t_time) {
  206. file.SetCellValue("sheet1", fmt.Sprintf("A%d", row), sensor.Tsn)
  207. file.SetCellValue("sheet1", fmt.Sprintf("B%d", row), companyname+"["+id+"]")
  208. file.SetCellValue("sheet1", fmt.Sprintf("C%d", row), sensor.TName)
  209. file.SetCellValue("sheet1", fmt.Sprintf("D%d", row), sensor.TId)
  210. file.SetCellValue("sheet1", fmt.Sprintf("E%d", row), t_time) // 数据缺失开始时间
  211. row++
  212. }
  213. }
  214. }
  215. }
  216. if err := file.SaveAs(filename); err != nil {
  217. log.Println("保存Excel文件失败:", err)
  218. }
  219. }
  220. }
  221. }
  222. }
  223. fmt.Println(message, len(message))
  224. }
  225. // 检查数据是否已存在
  226. func dataExists(file *excelize.File, sheet string, sn, company, name, id, time string) bool {
  227. rows, err := file.GetRows(sheet)
  228. if err != nil {
  229. log.Println("获取Excel文件行数据失败:", err)
  230. return false
  231. }
  232. for _, row := range rows[1:] { // 跳过表头
  233. if len(row) >= 5 && row[0] == sn && row[1] == company && row[2] == name && row[3] == id && row[4] == time {
  234. return true
  235. }
  236. }
  237. return false
  238. }
  239. // 获取最后一行的行号
  240. func getLastRow(file *excelize.File, sheet string) (int, error) {
  241. rows, err := file.GetRows(sheet)
  242. if err != nil {
  243. return 0, err
  244. }
  245. return len(rows), nil
  246. }
  247. func Ignore(sn string) (bool, error) {
  248. //sql := "SELECT t_sn FROM ignore WHERE t_sn = ?"
  249. sql := fmt.Sprintf("SELECT t_sn FROM `ignore` WHERE t_sn = '%s'", sn)
  250. var tsn string
  251. err := databases.Db.QueryRow(sql).Scan(&tsn)
  252. if err != nil {
  253. return false, err // 其他数据库错误
  254. }
  255. return tsn == sn, nil
  256. }