Procházet zdrojové kódy

恢复在线监测重连

xu před 1 měsícem
rodič
revize
fed7381379
3 změnil soubory, kde provedl 185 přidání a 11 odebrání
  1. 1 0
      initialize/myData.go
  2. 174 0
      service/cron.go
  3. 10 11
      utils/myTool.go

+ 1 - 0
initialize/myData.go

@@ -198,6 +198,7 @@ func parseData(data *model.QueueData) {
 				if device.Sn == data.Id {
 					reg.Devices[i].State = 1
 					reg.Devices[i].OnlineTime = time.Now()
+					service.Cron{}.RelayOnOffTimeTaskSn(device.Sn)
 				}
 				for i2, _ := range device.DeviceLoops {
 					if toString[6:8] == "ff" || toString[6:8] == "0f" {

+ 174 - 0
service/cron.go

@@ -1,10 +1,12 @@
 package service
 
 import (
+	"fmt"
 	"server/logger"
 	"server/modbus"
 	"server/model"
 	"server/utils"
+	"sort"
 	"time"
 )
 
@@ -138,3 +140,175 @@ func (c Cron) RelayOnOffTimeTask() {
 		}
 	}
 }
+
+func (c Cron) RelayOnOffTimeTaskSn(sn string) {
+	_, dev, err := utils.GetDataByDeviceId(sn)
+	if err != nil {
+		logger.Get().Errorf("LoadData err = %s", err.Error())
+		return
+	}
+	relays := dev.DeviceLoops
+	rcTime, rlTime, err := utils.SunriseSunsetForChina(28.23, 113.05)
+	tmp := make(map[int]int)
+	for _, relay := range relays {
+		//日出日落时间
+		if relay.TimeCondition1OnTime == "日出" {
+			relay.TimeCondition1OnTime = rcTime
+		} else if relay.TimeCondition1OnTime == "日落" {
+			relay.TimeCondition1OnTime = rlTime
+		}
+		if relay.TimeCondition1OffTime == "日出" {
+			relay.TimeCondition1OffTime = rcTime
+		} else if relay.TimeCondition1OffTime == "日落" {
+			relay.TimeCondition1OffTime = rlTime
+		}
+		if relay.TimeCondition2OnTime == "日出" {
+			relay.TimeCondition2OnTime = rcTime
+		} else if relay.TimeCondition2OnTime == "日落" {
+			relay.TimeCondition2OnTime = rlTime
+		}
+		if relay.TimeCondition2OffTime == "日出" {
+			relay.TimeCondition2OffTime = rcTime
+		} else if relay.TimeCondition2OffTime == "日落" {
+			relay.TimeCondition2OffTime = rlTime
+		}
+
+		if relay.TimeCondition1OffTime == "关闭" && relay.TimeCondition1OnTime == "关闭" && relay.TimeCondition2OffTime == "关闭" && relay.TimeCondition2OnTime == "关闭" {
+			continue
+		}
+		state, _ := ss(relay.TimeCondition1OnTime, relay.TimeCondition1OffTime, relay.TimeCondition2OnTime, relay.TimeCondition2OffTime)
+		tmp[relay.ID] = state
+	}
+
+	for loop1, state := range tmp {
+
+		reg, dev, err := utils.GetDataByDeviceId(sn)
+		if err != nil {
+			logger.Get().Errorf("GetDataByDeviceId err = %s\n", err.Error())
+		}
+
+		data := modbus.DeviceLoopSwitch(loop1, state)
+		if model.ConnectionMap[sn] == nil {
+			logger.Get().Errorf("设备连接丢失")
+		}
+		err = utils.WriteDevice(data, model.ConnectionMap[sn])
+		time.Sleep(100 * time.Millisecond)
+		if err != nil {
+			logger.Get().Errorf("WriteDevice err = %s\n", err.Error())
+		}
+
+		for j, loop := range dev.DeviceLoops {
+			if loop.ID == loop1 {
+				dev.DeviceLoops[j].State = state
+			}
+		}
+
+		for i, device := range reg.Devices {
+			if device.Sn == dev.Sn {
+				reg.Devices[i] = dev
+			}
+		}
+
+		data1, err := utils.SaveRegionOnData(reg)
+		if err != nil {
+			logger.Get().Errorf("SaveRegionOnData err = %s\n", err.Error())
+		}
+		err = SaveData(data1)
+		if err != nil {
+			logger.Get().Errorf("SaveData err = %s\n", err.Error())
+		}
+	}
+}
+
+const (
+	Off = iota
+	On
+)
+
+type TimeControl struct {
+	start time.Time
+	end   time.Time
+	state int
+}
+
+func getDeviceState(schedules []TimeControl, currentTime time.Time) int {
+	for _, period := range schedules {
+		now := time.Date(0, time.January, 1, currentTime.Hour(), currentTime.Minute(), currentTime.Second(), currentTime.Nanosecond(), time.UTC)
+		if period.start.After(period.end) {
+			if now.After(period.start) || now.Before(period.end) {
+				return period.state
+			}
+		} else {
+			if now.After(period.start) && now.Before(period.end) {
+				return period.state
+			}
+		}
+	}
+	return Off
+}
+
+func stateTransition(str string) int {
+	if str == "on1" || str == "on2" {
+		return On
+	} else {
+		return Off
+	}
+}
+
+func ss(on1, off1, on2, off2 string) (int, error) {
+	deviceRecoveryTime := time.Now()
+
+	// 定义时间映射
+	deviceTime := map[string]string{
+		"on1":  on1,
+		"off1": off1,
+		"on2":  on2,
+		"off2": off2,
+	}
+
+	// 创建一个切片存储时间
+	var times []struct {
+		key   string
+		value time.Time
+	}
+
+	// 将时间字符串解析为 time.Time 对象,并存入切片
+	for key, value := range deviceTime {
+		if value == "关闭" {
+			continue
+		}
+
+		t, err := time.Parse("15:04", value)
+		if err != nil {
+			logger.Get().Error("时间转换失败!" + err.Error())
+			return 0, err
+		}
+		times = append(times, struct {
+			key   string
+			value time.Time
+		}{key, t})
+	}
+
+	// 对时间进行排序
+	sort.Slice(times, func(i, j int) bool {
+		return times[i].value.Before(times[j].value)
+	})
+
+	var timeControls []TimeControl
+
+	for i, _ := range times {
+		if len(times) == i+1 {
+			timeControls = append(timeControls, TimeControl{start: times[i].value, end: times[0].value.Add(24 * time.Hour), state: stateTransition(times[i].key)})
+			continue
+		}
+		timeControls = append(timeControls, TimeControl{start: times[i].value, end: times[i+1].value, state: stateTransition(times[i].key)})
+	}
+
+	for _, control := range timeControls {
+		fmt.Printf("%s : %s : %d\n", control.start, control.end, control.state)
+	}
+
+	// 在恢复时检查状态
+	state := getDeviceState(timeControls, deviceRecoveryTime)
+	return state, nil
+}

+ 10 - 11
utils/myTool.go

@@ -164,19 +164,19 @@ const (
 
 func WriteDevice(frame []byte, conn net.Conn) error {
 	for attempts := 0; attempts < maxRetries; attempts++ {
-		if err := conn.SetWriteDeadline(time.Now().Add(writeTimeout)); err != nil {
-			logger.Get().Errorf("Set write deadline failed: %v", err)
-			return err
-		}
-
 		_, err := conn.Write(frame)
 		if err == nil {
 			return nil
 		}
 
-		// 检查是否是对端强制关闭连接的错误
-		if ne, ok := err.(*net.OpError); ok && (strings.Contains(ne.Err.Error(), "forcibly closed") || strings.Contains(ne.Err.Error(), "broken pipe") || strings.Contains(ne.Err.Error(), "connection reset")) {
-			logger.Get().Warnf("Connection forcibly closed by peer, retrying (%d/%d)", attempts+1, maxRetries)
+		// 检查是否是对端强制关闭连接、管道破裂、连接重置或使用了已关闭的网络连接的错误
+		if ne, ok := err.(*net.OpError); ok &&
+			(strings.Contains(ne.Err.Error(), "forcibly closed") ||
+				strings.Contains(ne.Err.Error(), "broken pipe") ||
+				strings.Contains(ne.Err.Error(), "connection reset") ||
+				strings.Contains(strings.ToLower(ne.Err.Error()), "use of closed network connection")) {
+
+			logger.Get().Warnf("Connection issue detected, retrying (%d/%d): %v", attempts+1, maxRetries, err)
 
 			// 关闭旧连接
 			if err := conn.Close(); err != nil {
@@ -204,12 +204,11 @@ func WriteDevice(frame []byte, conn net.Conn) error {
 			continue // 重试写入
 		}
 
-		// 如果不是对端强制关闭连接的错误,则直接返回错误
+		// 如果不是上述情况,则直接返回错误
 		logger.Get().Errorf("Write failed: %v", err)
 		return fmt.Errorf("write failed after %d retries: %v", attempts+1, err)
 	}
-
-	return fmt.Errorf("failed to write after %d retries", maxRetries)
+	return fmt.Errorf("write failed after maximum number of retries")
 }
 
 // 解析远程地址,提取 IP 地址和网络接口名称