package service import ( "database/sql" "fmt" "math" "strconv" "strings" "time" "ydMonitoring/config" "ydMonitoring/databases" "ydMonitoring/util" ) var ( thresholdTemperature, thresholdHumidity float64 // DateFormat 格式化时间字符串 DateFormat = "2006-01-02 15:04:05" //EquipmentMonitoringTime uint64 errRangeTime int ) func init() { thresholdTemperature = config.Config.GetFloat64("monitoring.temperature") thresholdHumidity = config.Config.GetFloat64("monitoring.humidity") errRangeTime = config.Config.GetInt("monitoring.errRangeTime") //EquipmentMonitoringTime = config.Config.GetUint64("monitoring.equipmentMonitoringTime") } // EquipmentMonitoring // 监控设备总函数 func EquipmentMonitoring() { db := databases.Db var ( //sqlStatement string err error rows *sql.Rows ) //设备YD监控 sqlStatement := "SELECT t_sn,t_dev_name FROM device WHERE (t__site = '' OR t__site IS NULL) AND t__state = 1 AND t_monitor = 1" fmt.Printf("YD设备查询SQL:%s\n", sqlStatement) rows, err = db.Query(sqlStatement) if err != nil { fmt.Println("数据查询失败:", err.Error()) } handlerData(rows) } // handlerData // 处理数据库查询响应数据 func handlerData(rows *sql.Rows) { db := databases.Db //设备配置表,获取备份时间 sql := "SELECT t_sn,t_save_time FROM device_parameter where ( t__state = 1 ) OR ( t__state = 2 and t__send_state = 1 ) order by ID asc" tSnRows, err := db.Query(sql) fmt.Printf("查询设备表设备备份时间SQL:%s\n", sql) if err != nil { fmt.Println("数据查询失败:", err.Error()) } var tSnThresholdTimeMap = make(map[string]int) for tSnRows.Next() { var tSn string var saveTime int tSnRows.Scan(&tSn, &saveTime) tSnThresholdTimeMap[tSn] = saveTime } fmt.Printf("查询到%d条记录\n", len(tSnThresholdTimeMap)) //获取所有tsn,并将其处理判断是否异常 for rows.Next() { var tSn, tDevName string rows.Scan(&tSn, &tDevName) // z_devicedata_kf861551053476933 tableName := fmt.Sprintf("z_device_data_%s", tSn) if tableName == "z_device_data_202335objgv2pz1" { fmt.Println() } //需要查出所有设备的t_id,对t_id对应的记录进行对比 selectTId := fmt.Sprintf("SELECT t_id FROM %s GROUP BY t_id", tableName) fmt.Printf("查询%s表中t_id进行分类执行SQL:\n", tSn) tIdRows, err := db.Query(selectTId) if err != nil { fmt.Printf(err.Error()) if strings.Contains(err.Error(), "Error 1146 (42S02): Table") { continue } } var tIds = make([]string, 0) for tIdRows.Next() { var tId string tIdRows.Scan(&tId) fmt.Println(tId) tIds = append(tIds, tId) } fmt.Printf("执行SQL后查询到%d条数据\n", len(tIds)) //判断是否有时间间隔,对于表tsn来说 thresholdTime, ok := tSnThresholdTimeMap[tSn] if !ok { util.SendWarning(tSn, -1, tDevName, "", fmt.Sprintf("[设备名称:%s|t_sn:%s]\t不存在配置时间", tDevName, tSn)) continue } for _, tId := range tIds { //如果t_id为空则跳出当前循环 if tId == "" { continue } t, _ := strconv.ParseInt(tId, 10, 64) id := int(t) sql := fmt.Sprintf("SELECT t_t,t_rh,create_time FROM %s where create_time >= DATE_SUB(NOW(),INTERVAL 1 DAY) AND t_id = %s ORDER BY create_time DESC LIMIT 10", tableName, tId) fmt.Printf("查询设备最近一天得前十条记录,执行SQL:%s\n", sql) tSnRows, err = db.Query(sql) if err != nil { util.SendWarning(tSn, -1, tDevName, "", fmt.Sprintf("[设备名称:%s|t_sn:%s]\t不存在配置时间", tDevName, tSn)) } tTs := make([]float64, 0) tRhs := make([]float64, 0) createTimes := make([]string, 0) //获取sn上传信息 for tSnRows.Next() { var ( tT, tRh float64 createTime string ) tSnRows.Scan(&tT, &tRh, &createTime) tTs = append(tTs, tT) tRhs = append(tRhs, tRh) createTimes = append(createTimes, createTime) } fmt.Printf("查询到%d条记录\n", len(tTs)) //如果不存在上传记录则跳出本次循环 if len(createTimes) == 0 || len(tTs) == 0 || len(tRhs) == 0 { fmt.Printf("%s设备执行SQL后不存在记录,设备已停用\n", tableName) util.SendWarning(tSn, -1, tDevName, "", fmt.Sprintf("【设备名称:%s|t_sn:%s|t_id:%s】\t缺少上传记录,该设备下没有数据记录,时间间隔%d", tDevName, tSn, tId, thresholdTime)) continue } //处理时间 //情况1:查询出来的最近时间节点对于现在的时间,是否在其中还存在一个记录时间段 currentTime := time.Now() firstTime, _ := time.Parse(DateFormat, createTimes[0]) if int((currentTime.Unix()-firstTime.Unix())/1000) > thresholdTime { fmt.Printf("当前时间:%s 最近记录时间:%s,时间间隔:%d", currentTime.Format(DateFormat), createTimes[0], thresholdTime) util.SendWarning(tSn, -1, tDevName, "", fmt.Sprintf("【设备名称:%s|t_sn:%s|t_id:%s】\t缺少上传记录,对于当前时间%s,最近记录时间%s,时间间隔%d", tDevName, tSn, tId, currentTime.Format(DateFormat), createTimes[0], thresholdTime)) continue } // 处理数据 for i := 0; i < len(tTs); i++ { //情况2:设备记录时间段不在阈值内,存在上传时间误差 if i == len(createTimes)-1 { break } previous, _ := time.Parse(DateFormat, createTimes[i]) next, _ := time.Parse(DateFormat, createTimes[i+1]) previous = previous.Add(time.Minute * time.Duration(-(thresholdTime / 60))) //判断时分是否一致,若不一致则存在误差 if previous.Day() != next.Day() || previous.Hour() != next.Hour() || previous.Minute() != next.Minute() { //误差再1分钟内可接受 if int(math.Abs((float64(previous.Unix()-next.Unix()))/1000)) > errRangeTime { fmt.Printf("当前%s,前条%s\n", next.Format(DateFormat), previous.Format(DateFormat)) util.SendWarning(tSn, id, tDevName, "", fmt.Sprintf("【设备名称:%s|t_sn:%s|t_id:%s】\t数据上传与配置时间不符合,时间为:[%s],[%s],时间阀值为:%d秒", tDevName, tSn, tId, createTimes[i+1], createTimes[i], thresholdTime)) continue } } //处理温度 previousTemperature := tTs[i] nextTemperature := tTs[i+1] if math.Abs(previousTemperature-nextTemperature) > thresholdTemperature { util.SendWarning(tSn, id, tDevName, "", fmt.Sprintf("【设备名称:%s|t_sn:%s|t_id:%s】\t温度变化超出阈值警告,当前温度:%.2f 上一次温度:%.2f 阈值温度:%.2f,温差为:%.2f\t出现时间为:%s", tDevName, tSn, tId, nextTemperature, previousTemperature, thresholdTemperature, math.Abs(previousTemperature-nextTemperature), createTimes[i])) continue } //处理湿度 previousHumidity := tRhs[i] nextHumidity := tRhs[i+1] if math.Abs(previousHumidity-nextHumidity) > thresholdHumidity { util.SendWarning(tSn, id, tDevName, "", fmt.Sprintf("【设备名称:%s|t_sn:%s|t_id:%s】\t湿度变化超出阈值警告,当前湿度:%.2f,前一次湿度:%.2f,温度阀值为:%.2f,湿度差:%.2f\t出现时间:%s", tDevName, tSn, tId, nextHumidity, previousHumidity, thresholdHumidity, math.Abs(previousTemperature-nextHumidity), createTimes[i])) continue } } } } }