Procházet zdrojové kódy

修复疯狂重连bug

terry před 1 měsícem
rodič
revize
8037766c71
8 změnil soubory, kde provedl 278 přidání a 70 odebrání
  1. 26 26
      initialize/myData.go
  2. 1 1
      modbus/instruction.go
  3. 2 2
      modbus/operate.go
  4. 174 1
      service/cron.go
  5. 4 4
      service/device.go
  6. 32 32
      static/data.json
  7. 38 3
      utils/myTool.go
  8. 1 1
      work/MyJob.go

+ 26 - 26
initialize/myData.go

@@ -2,7 +2,6 @@ package initialize
 
 import (
 	"encoding/hex"
-	"log"
 	"net"
 	"os"
 	"runtime"
@@ -39,11 +38,10 @@ func GetHandler() *ModbusHandler {
 func InitInductanceTCP() {
 	lis, err := net.Listen("tcp", ":60001")
 	if err != nil {
-		logger.Get().Println(err)
+		logger.Get().Fatalln("Failed to listen on port 60001:", err)
 	} else {
-		logger.Get().Println(lis)
-		model.InductanceTCP = lis
 		logger.Get().Println("inductanceTCP启动成功")
+		model.InductanceTCP = lis
 	}
 	go StartInductanceTCP()
 }
@@ -55,31 +53,30 @@ func StartInductanceTCP() {
 		logger.Get().Println("进入InductanceTCP循环")
 		conn, err := model.InductanceTCP.Accept()
 		if err != nil {
-			log.Println(err)
+			logger.Get().Errorf("Accept error: %v", err)
+			// 根据实际情况决定是否继续循环
+			continue
 		}
 		remoteAddr := conn.RemoteAddr().String()
 		logger.Get().Printf("lis Accept conn = %s\n", remoteAddr)
 
-		model.Mutex.Lock()
-
 		deviceId, err := GetDeviceId(conn)
 		if err != nil {
-			log.Println("Error getting device ID:", err)
+			logger.Get().Errorf("Error getting device ID from %s: %v", remoteAddr, err)
 			conn.Close()
-			model.Mutex.Unlock()
 			continue
 		}
 
-		if _, exists := model.ConnectionMap[deviceId]; exists {
-			log.Printf("Connection from %s already exists, closing new connection\n", remoteAddr)
-			conn.Close()
-			model.Mutex.Unlock()
-			continue
+		model.Mutex.Lock()
+		if existingConn, exists := model.ConnectionMap[deviceId]; exists {
+			logger.Get().Printf("Connection from %s already exists for deviceId %d, closing new connection\n", remoteAddr, deviceId)
+			existingConn.Close()                  // 关闭旧连接
+			delete(model.ConnectionMap, deviceId) // 清理旧连接
 		}
-
 		model.ConnectionMap[deviceId] = conn
 		model.Mutex.Unlock()
-		//用新的协程处理新的连接
+
+		// 使用新的协程处理新的连接
 		go handler.ReadAndHandle(conn, deviceId)
 		go handler.Handler()
 	}
@@ -179,7 +176,6 @@ func parseData(data *model.QueueData) {
 		return
 	}
 	toString := hex.EncodeToString(data.Value)
-	logger.Get().Println(data.Id + "--------" + toString)
 	switch toString[0:2] {
 	case "fe":
 		switch toString[4:8] { // 开关灯
@@ -200,7 +196,10 @@ func parseData(data *model.QueueData) {
 		case "0101":
 			for i, device := range reg.Devices {
 				if device.Sn == data.Id {
-					reg.Devices[i].State = 1
+					if reg.Devices[i].State != 1 {
+						reg.Devices[i].State = 1
+						service.Cron{}.RelayOnOffTimeTaskSn(data.Id)
+					}
 					reg.Devices[i].OnlineTime = time.Now()
 					for i2, _ := range device.DeviceLoops {
 						if toString[6:8] == "ff" || toString[6:8] == "0f" {
@@ -218,9 +217,10 @@ func parseData(data *model.QueueData) {
 				return
 			}
 		}
-	case "11":
+	case "01":
 		switch toString[2:6] {
 		case "0336":
+			logger.Get().Println(data.Id + "----" + toString)
 			batteryVoltage, _ := strconv.ParseInt(toString[6:10], 16, 64)
 			batteryCurrent, _ := strconv.ParseInt(toString[10:14], 16, 64)
 			batteryPlateVoltage, _ := strconv.ParseInt(toString[38:42], 16, 64)
@@ -242,13 +242,13 @@ func parseData(data *model.QueueData) {
 				return
 			}
 			//电池
-			if float64(batteryVoltage)/100 < 5 {
-				data1 := modbus.DeviceSwitch(8, 1)
-				utils.WriteDevice(data1, model.ConnectionMap[data.Id])
-			} else {
-				data1 := modbus.DeviceSwitch(8, 0)
-				utils.WriteDevice(data1, model.ConnectionMap[data.Id])
-			}
+			//if float64(batteryVoltage)/100 < 5 {
+			//	data1 := modbus.DeviceSwitch(8, 1)
+			//	utils.WriteDevice(data1, model.ConnectionMap[data.Id])
+			//} else {
+			//	data1 := modbus.DeviceSwitch(8, 0)
+			//	utils.WriteDevice(data1, model.ConnectionMap[data.Id])
+			//}
 		}
 	}
 

+ 1 - 1
modbus/instruction.go

@@ -45,7 +45,7 @@ func DeviceSwitch(number int, state int) (data []byte) {
 }
 
 func SolarEnergyData() (data []byte) {
-	data = append(data, 0x11)
+	data = append(data, 0x01)
 	data = append(data, 0x03)
 	data = append(data, 0x00)
 	data = append(data, 0x04)

+ 2 - 2
modbus/operate.go

@@ -15,7 +15,7 @@ func GetSunPowerInfo() error {
 	for id, conn := range model.ConnectionMap {
 		_, dev, err := utils.GetDataByDeviceId(id)
 		if dev.IsSun && dev.State == 1 { //打开  并且在线
-			err = utils.WriteDevice(SolarEnergyData(), conn)
+			err = utils.WriteDevice(dev.Sn, SolarEnergyData(), conn)
 			if err != nil {
 				return err
 			}
@@ -28,7 +28,7 @@ func GetSunPowerInfo() error {
 func GetDeviceInfo() {
 	for id, conn := range model.ConnectionMap {
 		_, dev, _ := utils.GetDataByDeviceId(id)
-		utils.WriteDevice(ReadDeviceInfo(dev.LoopNumber), conn)
+		utils.WriteDevice(dev.Sn, ReadDeviceInfo(dev.LoopNumber), conn)
 	}
 }
 

+ 174 - 1
service/cron.go

@@ -5,6 +5,7 @@ import (
 	"server/modbus"
 	"server/model"
 	"server/utils"
+	"sort"
 	"time"
 )
 
@@ -109,7 +110,7 @@ func (c Cron) RelayOnOffTimeTask() {
 			if model.ConnectionMap[key] == nil {
 				logger.Get().Errorf("设备连接丢失")
 			}
-			err := utils.WriteDevice(data, model.ConnectionMap[key])
+			err := utils.WriteDevice(dev.Sn, data, model.ConnectionMap[key])
 			time.Sleep(100 * time.Millisecond)
 			if err != nil {
 				logger.Get().Errorf("WriteDevice err = %s\n", err.Error())
@@ -138,3 +139,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(dev.Sn, 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
+}

+ 4 - 4
service/device.go

@@ -33,7 +33,7 @@ func DeviceLoopSwitch(deviceLoop dao.DeviceLoop) error {
 		return fmt.Errorf("设备离线无法操作")
 	}
 
-	err := utils.WriteDevice(data, model.ConnectionMap[deviceLoop.DeviceId])
+	err := utils.WriteDevice(dev.Sn, data, model.ConnectionMap[deviceLoop.DeviceId])
 	if err != nil {
 		fmt.Printf("Write device error: %v\n", err)
 		return err
@@ -45,7 +45,7 @@ func DeviceSwitch(req model.DeviceRequest) error {
 	if model.ConnectionMap[req.Device.Sn] == nil {
 		return fmt.Errorf("设备连接丢失")
 	}
-	err := utils.WriteDevice(data, model.ConnectionMap[req.Device.Sn])
+	err := utils.WriteDevice(req.Device.Sn, data, model.ConnectionMap[req.Device.Sn])
 	if err != nil {
 		logger.Get().Errorf("Write device error: %v\n", err)
 		return err
@@ -62,7 +62,7 @@ func DeviceBatchSwitch(req model.DevicesRequest) error {
 		if model.ConnectionMap[device.Sn] == nil {
 			return fmt.Errorf("设备连接丢失")
 		}
-		err := utils.WriteDevice(data, model.ConnectionMap[device.Sn])
+		err := utils.WriteDevice(device.Sn, data, model.ConnectionMap[device.Sn])
 		if err != nil {
 			fmt.Printf("Write device error: %v\n", err)
 			return err
@@ -100,7 +100,7 @@ func GetSunDevices() (devices []dao.Device, err error) {
 }
 
 func UpdateRegisterAddress(deviceId string) error {
-	err := utils.WriteDevice(modbus.UpdateRegisterAddress(), model.ConnectionMap[deviceId])
+	err := utils.WriteDevice(deviceId, modbus.UpdateRegisterAddress(), model.ConnectionMap[deviceId])
 	if err != nil {
 		logger.Get().Errorf("UpdateRegisterAddress error: %v\n", err)
 		return err

+ 32 - 32
static/data.json

@@ -395,15 +395,15 @@
     "state": 1,
     "isSun": true,
     "loopNumber": 4,
-    "onlineTime": "2025-02-10T15:12:00.033184+08:00",
+    "onlineTime": "2025-02-12T16:44:19.9551468+08:00",
     "deviceLoops": [
      {
       "id": 1,
       "deviceId": "JM45L1V0q2TrA8tn",
       "name": "回路12",
       "state": 1,
-      "timeCondition1OnTime": "关闭",
-      "timeCondition1OffTime": "关闭",
+      "timeCondition1OnTime": "13:48",
+      "timeCondition1OffTime": "08:20",
       "timeCondition2OnTime": "关闭",
       "timeCondition2OffTime": "关闭"
      },
@@ -412,8 +412,8 @@
       "deviceId": "JM45L1V0q2TrA8tn",
       "name": "回路2",
       "state": 1,
-      "timeCondition1OnTime": "关闭",
-      "timeCondition1OffTime": "关闭",
+      "timeCondition1OnTime": "13:48",
+      "timeCondition1OffTime": "08:20",
       "timeCondition2OnTime": "关闭",
       "timeCondition2OffTime": "关闭"
      },
@@ -422,8 +422,8 @@
       "deviceId": "JM45L1V0q2TrA8tn",
       "name": "回路3",
       "state": 1,
-      "timeCondition1OnTime": "关闭",
-      "timeCondition1OffTime": "关闭",
+      "timeCondition1OnTime": "13:48",
+      "timeCondition1OffTime": "08:20",
       "timeCondition2OnTime": "关闭",
       "timeCondition2OffTime": "关闭"
      },
@@ -432,8 +432,8 @@
       "deviceId": "JM45L1V0q2TrA8tn",
       "name": "回路4",
       "state": 1,
-      "timeCondition1OnTime": "关闭",
-      "timeCondition1OffTime": "关闭",
+      "timeCondition1OnTime": "13:48",
+      "timeCondition1OffTime": "08:00",
       "timeCondition2OnTime": "关闭",
       "timeCondition2OffTime": "关闭"
      }
@@ -454,15 +454,15 @@
     "state": 1,
     "isSun": true,
     "loopNumber": 4,
-    "onlineTime": "2025-02-10T15:06:00.021725+08:00",
+    "onlineTime": "2025-02-12T16:44:20.0199864+08:00",
     "deviceLoops": [
      {
       "id": 1,
       "deviceId": "JM45uSabL2URuQaD",
       "name": "回路12",
       "state": 1,
-      "timeCondition1OnTime": "关闭",
-      "timeCondition1OffTime": "关闭",
+      "timeCondition1OnTime": "13:48",
+      "timeCondition1OffTime": "17:14",
       "timeCondition2OnTime": "关闭",
       "timeCondition2OffTime": "关闭"
      },
@@ -471,8 +471,8 @@
       "deviceId": "JM45uSabL2URuQaD",
       "name": "回路2",
       "state": 1,
-      "timeCondition1OnTime": "关闭",
-      "timeCondition1OffTime": "关闭",
+      "timeCondition1OnTime": "13:48",
+      "timeCondition1OffTime": "17:14",
       "timeCondition2OnTime": "关闭",
       "timeCondition2OffTime": "关闭"
      },
@@ -481,8 +481,8 @@
       "deviceId": "JM45uSabL2URuQaD",
       "name": "回路3",
       "state": 1,
-      "timeCondition1OnTime": "关闭",
-      "timeCondition1OffTime": "关闭",
+      "timeCondition1OnTime": "13:48",
+      "timeCondition1OffTime": "08:00",
       "timeCondition2OnTime": "关闭",
       "timeCondition2OffTime": "关闭"
      },
@@ -491,8 +491,8 @@
       "deviceId": "JM45uSabL2URuQaD",
       "name": "回路4",
       "state": 1,
-      "timeCondition1OnTime": "关闭",
-      "timeCondition1OffTime": "关闭",
+      "timeCondition1OnTime": "13:48",
+      "timeCondition1OffTime": "08:00",
       "timeCondition2OnTime": "关闭",
       "timeCondition2OffTime": "关闭"
      }
@@ -510,18 +510,18 @@
     "regionId": 1,
     "name": "维修车间",
     "genre": "八回路控制",
-    "state": 1,
+    "state": 0,
     "isSun": true,
     "loopNumber": 4,
-    "onlineTime": "2025-02-10T15:12:00.0103096+08:00",
+    "onlineTime": "2025-02-12T15:10:20.0285025+08:00",
     "deviceLoops": [
      {
       "id": 1,
       "deviceId": "JM45Xy7KQGyxDhS3",
       "name": "回路12",
-      "state": 0,
-      "timeCondition1OnTime": "关闭",
-      "timeCondition1OffTime": "关闭",
+      "state": 1,
+      "timeCondition1OnTime": "13:48",
+      "timeCondition1OffTime": "08:00",
       "timeCondition2OnTime": "关闭",
       "timeCondition2OffTime": "关闭"
      },
@@ -529,9 +529,9 @@
       "id": 2,
       "deviceId": "JM45Xy7KQGyxDhS3",
       "name": "回路2",
-      "state": 0,
-      "timeCondition1OnTime": "关闭",
-      "timeCondition1OffTime": "关闭",
+      "state": 1,
+      "timeCondition1OnTime": "13:48",
+      "timeCondition1OffTime": "08:00",
       "timeCondition2OnTime": "关闭",
       "timeCondition2OffTime": "关闭"
      },
@@ -539,9 +539,9 @@
       "id": 3,
       "deviceId": "JM45Xy7KQGyxDhS3",
       "name": "回路3",
-      "state": 0,
-      "timeCondition1OnTime": "关闭",
-      "timeCondition1OffTime": "关闭",
+      "state": 1,
+      "timeCondition1OnTime": "13:48",
+      "timeCondition1OffTime": "08:00",
       "timeCondition2OnTime": "关闭",
       "timeCondition2OffTime": "关闭"
      },
@@ -549,9 +549,9 @@
       "id": 4,
       "deviceId": "JM45Xy7KQGyxDhS3",
       "name": "回路4",
-      "state": 0,
-      "timeCondition1OnTime": "关闭",
-      "timeCondition1OffTime": "关闭",
+      "state": 1,
+      "timeCondition1OnTime": "13:48",
+      "timeCondition1OffTime": "08:00",
       "timeCondition2OnTime": "关闭",
       "timeCondition2OffTime": "关闭"
      }

+ 38 - 3
utils/myTool.go

@@ -10,6 +10,7 @@ import (
 	"path/filepath"
 	"server/dao"
 	"server/logger"
+	"server/model"
 	"strings"
 	"time"
 )
@@ -182,11 +183,45 @@ const (
 	reconnectWait = 2 * time.Second // 重连等待时间
 )
 
-func WriteDevice(frame []byte, conn net.Conn) error {
+func WriteDevice(deviceId string, 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
+			// 捕捉 "use of closed network connection" 错误
+			if ne, ok := err.(*net.OpError); ok && strings.Contains(strings.ToLower(ne.Err.Error()), "use of closed network connection") {
+				logger.Get().Warnf("Connection is closed, retrying (%d/%d)", attempts+1, maxRetries)
+
+				// 关闭旧连接(尽管这里认为连接已关闭)
+				if err := conn.Close(); err != nil {
+					logger.Get().Errorf("Failed to close connection: %v", err)
+				}
+
+				// 尝试重新建立连接
+				var newConn net.Conn
+				remoteAddr := conn.RemoteAddr().String()
+
+				// 解析原始连接的远程地址和网络接口
+				addr, networkInterface, err := parseRemoteAddr(remoteAddr)
+				if err != nil {
+					logger.Get().Errorf("Failed to parse remote address: %v", err)
+					continue // 继续下一次重试
+				}
+
+				newConn, err = net.Dial("tcp", fmt.Sprintf("%s%%%s", addr, networkInterface))
+				if err != nil {
+					logger.Get().Errorf("Reconnect failed: %v", err)
+					time.Sleep(reconnectWait) // 等待一段时间后重试
+					if attempts == 3 {
+						delete(model.ConnectionMap, deviceId)
+					}
+					continue // 继续下一次重试
+				}
+				conn = newConn
+				continue // 重试写入
+			} else {
+				// 如果是其他类型的错误,则直接返回
+				logger.Get().Errorf("Set write deadline failed: %v", err)
+				return err
+			}
 		}
 
 		_, err := conn.Write(frame)

+ 1 - 1
work/MyJob.go

@@ -9,7 +9,7 @@ import (
 func MyJob() {
 	c := cron.New()
 
-	_ = c.AddFunc("0 */2 * * * ?", func() {
+	_ = c.AddFunc("20 */2 * * * ?", func() {
 		modbus.GetSunPowerInfo()
 		modbus.GetDeviceInfo()
 	})