Browse Source

日志, id换ip,重连,conn关闭

xu 1 week ago
parent
commit
5a7f2392ce
13 changed files with 332 additions and 1319 deletions
  1. 0 16
      api/device.go
  2. 1 0
      dao/device.go
  3. 40 42
      initialize/myData.go
  4. 1 1
      logs/app.log
  5. 0 1065
      logs/app.log.20250319.log
  6. 0 17
      modbus/instruction.go
  7. 11 5
      modbus/operate.go
  8. 1 1
      model/common.go
  9. 0 1
      router/router.go
  10. 184 10
      service/cron.go
  11. 21 37
      service/device.go
  12. 37 33
      static/data.json
  13. 36 91
      utils/myTool.go

+ 0 - 16
api/device.go

@@ -140,19 +140,3 @@ func GetSunDevices(c *gin.Context) {
 	}
 	model.OkWithData(devices, c)
 }
-
-func UpdateRegisterAddress(c *gin.Context) {
-	var id string
-	err := c.ShouldBindJSON(&id)
-	if err != nil {
-		model.FailWithMessage(err.Error(), c)
-		return
-	}
-	err = service.UpdateRegisterAddress(id)
-	if err != nil {
-		logger.Get().Error(err.Error())
-		model.FailWithMessage(err.Error(), c)
-		return
-	}
-	model.Ok(c)
-}

+ 1 - 0
dao/device.go

@@ -5,6 +5,7 @@ import "time"
 type Device struct {
 	ID          int          `json:"id"`
 	Sn          string       `json:"sn"`
+	Ip          string       `json:"ip"`
 	RegionId    int          `json:"regionId"`
 	Name        string       `json:"name"`
 	Genre       string       `json:"genre"`

+ 40 - 42
initialize/myData.go

@@ -3,7 +3,7 @@ package initialize
 import (
 	"encoding/hex"
 	"fmt"
-	"log"
+	"io"
 	"net"
 	"os"
 	"runtime"
@@ -42,9 +42,8 @@ func InitInductanceTCP() {
 	if err != nil {
 		logger.Get().Println(err)
 	} else {
-		logger.Get().Println(lis)
 		model.InductanceTCP = lis
-		logger.Get().Println("inductanceTCP启动成功")
+		logger.Get().Printf("inductanceTCP启动成功 %v \n", lis)
 	}
 	go StartInductanceTCP()
 }
@@ -56,53 +55,43 @@ func StartInductanceTCP() {
 		logger.Get().Println("进入InductanceTCP循环")
 		conn, err := model.InductanceTCP.Accept()
 		if err != nil {
-			log.Println(err)
+			logger.Get().Println(err)
 		}
+
 		remoteAddr := conn.RemoteAddr().String()
 		logger.Get().Printf("lis Accept conn = %s\n", remoteAddr)
 
-		model.Mutex.Lock()
-
-		deviceId, err := GetDeviceId(conn)
+		// 解析远程地址
+		addr, err := net.ResolveTCPAddr("tcp", remoteAddr)
 		if err != nil {
-			log.Println("Error getting device ID:", err)
-			//conn.Close()
-			model.Mutex.Unlock()
-			continue
+			// 处理错误...
+			logger.Get().Errorf("解析错误 conn = %s\n", addr.IP.String())
 		}
 
-		model.ConnectionMap1.Store(deviceId, conn)
+		model.ConnectionMap1.Store(addr.IP.String(), conn)
+
+		//每次连接 进行重连操作
+		service.DeviceAdjustment(addr.IP.String())
 
-		model.Mutex.Unlock()
 		// 使用 Load 方法尝试获取连接
-		if conn1, ok := model.ConnectionMap1.Load(deviceId); ok {
+		if conn1, ok := model.ConnectionMap1.Load(addr.IP.String()); ok {
 			// 成功找到连接
 			netConn := conn1.(net.Conn)
 			// 在这里处理 netConn
-			go handler.ReadAndHandle(netConn, deviceId)
+			go handler.ReadAndHandle(netConn, addr.IP.String())
 			go handler.Handler()
 		} else {
 			// 没有找到对应的连接
-			log.Printf("Connection for key %s not found", deviceId)
+			logger.Get().Printf("启动 Connection for key %s not found", addr.IP.String())
 		}
 	}
 }
 
-func GetDeviceId(conn net.Conn) (id string, err error) {
-	// 发送 Modbus RTU 帧
-	//FE 04 03 EE 00 08 85 B2
-	data, err := utils.WriteAndReadDevice(modbus.ReadDeviceId, conn, 9, 2)
-	if err != nil {
-		return
-	}
-	return string(data), err
-}
-
-func (o *ModbusHandler) ReadAndHandle(conn net.Conn, deviceId string) {
+func (o *ModbusHandler) ReadAndHandle(conn net.Conn, remoteAddr string) {
 	for {
 		buffer := make([]byte, 1024)
 		n, err := conn.Read(buffer)
-		if err != nil {
+		if err != nil && err != io.EOF {
 			if isConnReset(err) {
 				logger.Get().Error("连接被远程主机强制关闭")
 			} else if os.IsTimeout(err) {
@@ -111,10 +100,11 @@ func (o *ModbusHandler) ReadAndHandle(conn net.Conn, deviceId string) {
 				// 处理其他类型的错误
 				logger.Get().Errorf("读取错误: %s\n", err)
 			}
+			defer conn.Close()
 			return
 		}
 		queueData := model.QueueData{
-			Id:    deviceId,
+			Ip:    remoteAddr,
 			Value: buffer[:n],
 		}
 		ok, cnt := o.queue.Put(&queueData)
@@ -176,12 +166,13 @@ func (o *ModbusHandler) Handler() interface{} {
 }
 
 func parseData(data *model.QueueData) {
-	reg, dev, err := utils.GetDataByDeviceId(data.Id)
+	reg, dev, err := utils.GetDataByDeviceIP(data.Ip)
 	if err != nil {
 		logger.Get().Errorln("Error getting register and device:", err)
 		return
 	}
 	toString := hex.EncodeToString(data.Value)
+	logger.Get().Infof("deviceIP: %s, value: %s", data.Ip, toString)
 	switch toString[0:2] {
 	case "fe":
 		switch toString[2:8] { // 开关灯
@@ -194,7 +185,7 @@ func parseData(data *model.QueueData) {
 				dev.DeviceLoops[relyId].State = 1
 			}
 			for i, device := range reg.Devices {
-				if device.Sn == data.Id {
+				if device.Ip == data.Ip {
 					reg.Devices[i] = dev
 				}
 			}
@@ -205,9 +196,8 @@ func parseData(data *model.QueueData) {
 				return
 			}
 		case "0f0000":
-
 			OperationCommand := hex.EncodeToString(modbus.OperationCommand)
-			logger.Get().Infof("deviceId: %s, value: %s", data.Id, OperationCommand)
+			logger.Get().Infof("deviceId: %s, value: %s", data.Ip, OperationCommand)
 			if OperationCommand[14:16] == "00" {
 				for i, loop := range dev.DeviceLoops {
 					loop.State = 0
@@ -220,7 +210,7 @@ func parseData(data *model.QueueData) {
 				}
 			}
 			for i, device := range reg.Devices {
-				if device.Sn == data.Id {
+				if device.Sn == data.Ip {
 					reg.Devices[i] = dev
 				}
 			}
@@ -247,7 +237,7 @@ func parseData(data *model.QueueData) {
 				binStr += fmt.Sprintf("%08b", b)
 			}
 			for i, device := range reg.Devices {
-				if device.Sn == data.Id {
+				if device.Ip == data.Ip {
 					reg.Devices[i].State = 1
 					reg.Devices[i].OnlineTime = time.Now()
 					if len(device.DeviceLoops) == 8 {
@@ -256,7 +246,7 @@ func parseData(data *model.QueueData) {
 						}
 					} else {
 						for j := len(device.DeviceLoops) - 1; j >= 0; j-- {
-							reg.Devices[i].DeviceLoops[3-j].State = int(binStr[j+3] - '0')
+							reg.Devices[i].DeviceLoops[3-j].State = int(binStr[j+4] - '0')
 						}
 					}
 
@@ -295,23 +285,31 @@ func parseData(data *model.QueueData) {
 			//电池
 			if float64(batteryVoltage)/100 < 5 {
 				data1 := modbus.DeviceSwitch(8, 1)
-				if conn1, ok := model.ConnectionMap1.Load(data.Id); ok {
+				if conn1, ok := model.ConnectionMap1.Load(data.Ip); ok {
 					// 成功找到连接
 					netConn := conn1.(net.Conn)
-					utils.WriteDevice(data1, netConn)
+					err := utils.WriteDevice(data1, netConn)
+					if err != nil {
+						logger.Get().Errorf("电池符合控制 写命令错误: %s -- conn: %v", err, netConn.RemoteAddr().String())
+						return
+					}
 				} else {
 					// 没有找到对应的连接
-					logger.Get().Printf("Connection for key %s not found", data.Id)
+					logger.Get().Printf("电池符合控制Connection for key %s not found", data.Ip)
 				}
 			} else {
 				data1 := modbus.DeviceSwitch(8, 0)
-				if conn1, ok := model.ConnectionMap1.Load(data.Id); ok {
+				if conn1, ok := model.ConnectionMap1.Load(data.Ip); ok {
 					// 成功找到连接
 					netConn := conn1.(net.Conn)
-					utils.WriteDevice(data1, netConn)
+					err := utils.WriteDevice(data1, netConn)
+					if err != nil {
+						logger.Get().Errorf("电池符合控制 写命令错误: %s -- conn: %v", err, netConn.RemoteAddr().String())
+						return
+					}
 				} else {
 					// 没有找到对应的连接
-					logger.Get().Printf("Connection for key %s not found", data.Id)
+					logger.Get().Printf("电池符合控制Connection for key %s not found", data.Ip)
 				}
 			}
 		}

+ 1 - 1
logs/app.log

@@ -1 +1 @@
-app.log.20250321.log
+app.log.20250323.log

File diff suppressed because it is too large
+ 0 - 1065
logs/app.log.20250319.log


+ 0 - 17
modbus/instruction.go

@@ -58,23 +58,6 @@ func SolarEnergyData() (data []byte) {
 	return
 }
 
-// UpdateRegisterAddress 修改寄存器地址
-func UpdateRegisterAddress() (data []byte) {
-	data = append(data, 0x01)
-	data = append(data, 0x10)
-	data = append(data, 0x00)
-	data = append(data, 0x00)
-	data = append(data, 0x00)
-	data = append(data, 0x01)
-	data = append(data, 0x02)
-	data = append(data, 0x00)
-	data = append(data, 0x11)
-	crc16 := utils.CRC16(data)
-	data = append(data, byte(crc16&0xFF))
-	data = append(data, byte(crc16>>8))
-	return
-}
-
 func ReadDeviceInfo(number int) (data []byte) {
 	data = append(data, 0xFE)
 	data = append(data, 0x01)

+ 11 - 5
modbus/operate.go

@@ -17,9 +17,12 @@ func GetSunPowerInfo() error {
 		addr := key.(string)     // 假设键是 string 类型
 		conn := value.(net.Conn) // 假设值是 net.Conn 类型
 
-		_, dev, _ := utils.GetDataByDeviceId(addr)
+		_, dev, _ := utils.GetDataByDeviceIP(addr)
 		if dev.IsSun && dev.State == 1 { //打开  并且在线
-			utils.WriteDevice(SolarEnergyData(), conn)
+			err := utils.WriteDevice(SolarEnergyData(), conn)
+			if err != nil {
+				logger.Get().Errorf("获取太阳能信息 写命令错误: %s -- conn: %v", err, conn.RemoteAddr().String())
+			}
 		}
 
 		// 返回 true 继续遍历,返回 false 提前终止遍历
@@ -34,8 +37,11 @@ func GetDeviceInfo() {
 		addr := key.(string)     // 假设键是 string 类型
 		conn := value.(net.Conn) // 假设值是 net.Conn 类型
 
-		_, dev, _ := utils.GetDataByDeviceId(addr)
-		utils.WriteDevice(ReadDeviceInfo(dev.LoopNumber), conn)
+		_, dev, _ := utils.GetDataByDeviceIP(addr)
+		err := utils.WriteDevice(ReadDeviceInfo(dev.LoopNumber), conn)
+		if err != nil {
+			logger.Get().Errorf("获取设备信息 写命令错误: %s -- conn: %v", err, conn.RemoteAddr().String())
+		}
 		time.Sleep(1 * time.Second)
 		// 返回 true 继续遍历,返回 false 提前终止遍历
 		return true
@@ -75,7 +81,7 @@ func DealWithOffline() {
 		}
 
 		for i2, device := range region.Devices {
-			if now.After(device.OnlineTime.Add(13*time.Minute)) && device.State != 0 {
+			if now.After(device.OnlineTime.Add(5*time.Minute)) && device.State != 0 {
 				regions[i].Devices[i2].State = 0
 			}
 		}

+ 1 - 1
model/common.go

@@ -13,7 +13,7 @@ var (
 )
 
 type QueueData struct {
-	Id    string `json:"id"`
+	Ip    string `json:"ip"`
 	Value []byte `json:"value"`
 }
 

+ 0 - 1
router/router.go

@@ -22,7 +22,6 @@ func InitRouter() *gin.Engine {
 		Group.POST("deviceBatchSwitch", api.BatchDeviceSwitch)
 		Group.GET("getOnlineDevice", api.GetOnlineDevice)
 		Group.GET("getSunDevices", api.GetSunDevices)
-		Group.PUT("updateRegisterAddress", api.UpdateRegisterAddress)
 	}
 	return router
 }

+ 184 - 10
service/cron.go

@@ -1,11 +1,13 @@
 package service
 
 import (
+	"fmt"
 	"net"
 	"server/logger"
 	"server/modbus"
 	"server/model"
 	"server/utils"
+	"sort"
 	"time"
 )
 
@@ -22,10 +24,7 @@ func (c Cron) RelayOnOffTimeTask() {
 	}
 	relayMap := make(map[string]map[int]int)
 	for _, d := range devices {
-		//if d.State == 0 {
-		//	continue
-		//}
-		tmp, isExist := relayMap[d.Sn]
+		tmp, isExist := relayMap[d.Ip]
 		if !isExist { // 回路id  回路状态
 			tmp = make(map[int]int)
 		}
@@ -94,13 +93,13 @@ func (c Cron) RelayOnOffTimeTask() {
 				isTiming = 1
 			}
 			if isTiming == 1 {
-				relayMap[d.Sn] = tmp
+				relayMap[d.Ip] = tmp
 			}
 		}
 	}
 	for key, value := range relayMap {
 
-		reg, dev, err := utils.GetDataByDeviceId(key)
+		reg, dev, err := utils.GetDataByDeviceIP(key)
 		if err != nil {
 			logger.Get().Errorf("GetDataByDeviceId err = %s\n", err.Error())
 		}
@@ -111,11 +110,11 @@ func (c Cron) RelayOnOffTimeTask() {
 				// 成功找到连接
 				netConn := conn1.(net.Conn)
 				err := utils.WriteDevice(data, netConn)
-				time.Sleep(1 * time.Second)
 				if err != nil {
-					logger.Get().Errorf("WriteDevice err = %s\n", err.Error())
+					logger.Get().Errorf("定时控制 写命令错误: %s -- conn: %v", err, netConn.RemoteAddr().String())
+					return
 				}
-
+				time.Sleep(1 * time.Second)
 				for j, loop := range dev.DeviceLoops {
 					if loop.ID == i {
 						dev.DeviceLoops[j].State = i2
@@ -123,7 +122,7 @@ func (c Cron) RelayOnOffTimeTask() {
 				}
 			} else {
 				// 没有找到对应的连接
-				logger.Get().Printf("Connection for key %s not found", key)
+				logger.Get().Printf("定时Connection for key %s not found", key)
 			}
 		}
 
@@ -143,3 +142,178 @@ func (c Cron) RelayOnOffTimeTask() {
 		}
 	}
 }
+
+// DeviceAdjustment 设备调正
+func DeviceAdjustment(ip string) {
+	reg, dev, _ := utils.GetDataByDeviceIP(ip)
+
+	rcTime, rlTime, err := utils.SunriseSunsetForChina(28.23, 113.05)
+	tmp := make(map[int]int)
+	for _, relay := range dev.DeviceLoops {
+		//日出日落时间
+		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, err := ss(relay.TimeCondition1OnTime, relay.TimeCondition1OffTime, relay.TimeCondition2OnTime, relay.TimeCondition2OffTime)
+		if err != nil {
+			return
+		}
+		tmp[relay.ID] = state
+	}
+	logger.Get().Printf("[DEBUG] %v", tmp)
+	for i, i2 := range tmp {
+		data := modbus.DeviceLoopSwitch(i, i2)
+		if conn1, ok := model.ConnectionMap1.Load(ip); ok {
+			// 成功找到连接
+			netConn := conn1.(net.Conn)
+			err := utils.WriteDevice(data, netConn)
+			if err != nil {
+				logger.Get().Errorf("定时控制 写命令错误: %s -- conn: %v", err, netConn.RemoteAddr().String())
+				return
+			}
+			time.Sleep(2 * time.Second)
+			for j, loop := range dev.DeviceLoops {
+				if loop.ID == i {
+					dev.DeviceLoops[j].State = i2
+				}
+			}
+		} else {
+			// 没有找到对应的连接
+			logger.Get().Printf("重连Connection for key %s not found", ip)
+		}
+	}
+
+	for i, device := range reg.Devices {
+		if device.Sn == dev.Sn {
+			reg.Devices[i] = dev
+		}
+	}
+
+	data, err := utils.SaveRegionOnData(reg)
+	if err != nil {
+		logger.Get().Errorf("重连SaveRegionOnData err = %s\n", err.Error())
+	}
+	err = SaveData(data)
+	if err != nil {
+		logger.Get().Errorf("SaveData err = %s\n", err.Error())
+	}
+	return
+}
+
+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)
+		start := time.Date(0, time.January, 1, period.start.Hour(), period.start.Minute(), period.start.Second(), period.start.Nanosecond(), time.UTC)
+		end := time.Date(0, time.January, 1, period.end.Hour(), period.end.Minute(), period.end.Second(), period.end.Nanosecond(), time.UTC)
+
+		if start.After(end) { // 跨越午夜
+			if now.After(start) || now.Before(end) {
+				return period.state
+			}
+		} else { // 不跨越午夜
+			if now.After(start) && now.Before(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)
+	fmt.Printf("%s  %d\n", timeControls, state)
+	return state, nil
+}

+ 21 - 37
service/device.go

@@ -15,12 +15,7 @@ func SaveData(data []dao.Region) error {
 		return fmt.Errorf("数据不能为空")
 	}
 	utils.SaveRegions(data)
-	//err := utils.SaveData("static/data.json", data)
-	//if err != nil {
-	//	return err
-	//}
-	// Remove the redundant return err statement.
-	return nil // Return nil to indicate success
+	return nil
 }
 
 func DeviceSave(device dao.Device) error {
@@ -37,14 +32,19 @@ func DeviceSave(device dao.Device) error {
 	if err != nil {
 		return err
 	}
-	// Remove the redundant return err statement.
-	return nil // Return nil to indicate success
+	return nil
 }
 
-func DevicesSave(device []dao.Device) error {
+func DevicesSave(devices []dao.Device) error {
 	regions, _ := utils.LoadData()
 
-	regions[0].Devices = device
+	for i, rd := range regions[0].Devices {
+		for _, d := range devices {
+			if rd.Sn == d.Sn {
+				regions[0].Devices[i] = d
+			}
+		}
+	}
 	err := SaveData(regions)
 	if err != nil {
 		return err
@@ -55,39 +55,40 @@ func DevicesSave(device []dao.Device) error {
 
 func DeviceLoopSwitch(deviceLoop dao.DeviceLoop) error {
 	data := modbus.DeviceLoopSwitch(deviceLoop.ID, deviceLoop.State)
-	if conn1, ok := model.ConnectionMap1.Load(deviceLoop.DeviceId); ok {
+	_, dev1, _ := utils.GetDataByDeviceId(deviceLoop.DeviceId)
+	if conn1, ok := model.ConnectionMap1.Load(dev1.Ip); ok {
 		// 成功找到连接
 		netConn := conn1.(net.Conn)
-		_, dev, _ := utils.GetDataByDeviceId(deviceLoop.DeviceId)
+		_, dev, _ := utils.GetDataByDeviceIP(dev1.Ip)
 		if dev.State == 0 {
 			return fmt.Errorf("设备离线无法操作")
 		}
 
 		err := utils.WriteDevice(data, netConn)
 		if err != nil {
-			fmt.Printf("Write device error: %v\n", err)
+			logger.Get().Errorf("设备回路开关 写命令错误: %s -- conn: %v", err, netConn.RemoteAddr().String())
 			return err
 		}
 	} else {
 		// 没有找到对应的连接
-		logger.Get().Printf("Connection for key %s not found", deviceLoop.DeviceId)
+		logger.Get().Printf("设备回路开关Connection for key %s not found", dev1.Ip)
 	}
 	return nil
 }
 func DeviceSwitch(req model.DeviceRequest) error {
 	data := modbus.DeviceSwitch(req.Device.LoopNumber, req.State)
-	if conn1, ok := model.ConnectionMap1.Load(req.Device.Sn); ok {
+	if conn1, ok := model.ConnectionMap1.Load(req.Device.Ip); ok {
 		// 成功找到连接
 		netConn := conn1.(net.Conn)
 		modbus.OperationCommand = data
 		err := utils.WriteDevice(data, netConn)
 		if err != nil {
-			logger.Get().Errorf("Write device error: %v\n", err)
+			logger.Get().Errorf("设备开关 写命令错误: %s -- conn: %v", err, netConn.RemoteAddr().String())
 			return err
 		}
 	} else {
 		// 没有找到对应的连接
-		logger.Get().Printf("Connection for key %s not found", req.Device.Sn)
+		logger.Get().Printf("设备开关Connection for key %s not found", req.Device.Ip)
 	}
 	return nil
 }
@@ -99,17 +100,16 @@ func DeviceBatchSwitch(req model.DevicesRequest) error {
 		}
 		data := modbus.DeviceSwitch(device.LoopNumber, req.State)
 		modbus.OperationCommand = data
-		if conn1, ok := model.ConnectionMap1.Load(device.Sn); ok {
+		if conn1, ok := model.ConnectionMap1.Load(device.Ip); ok {
 			// 成功找到连接
 			netConn := conn1.(net.Conn)
 			err := utils.WriteDevice(data, netConn)
 			if err != nil {
-				fmt.Printf("Write device error: %v\n", err)
-				return err
+				logger.Get().Errorf("设备批量控制 写命令错误: %s -- conn: %v", err, netConn.RemoteAddr().String())
 			}
 		} else {
 			// 没有找到对应的连接
-			logger.Get().Printf("Connection for key %s not found", device.Sn)
+			logger.Get().Printf("设备批量控制Connection for key %s not found", device.Ip)
 		}
 	}
 	return nil
@@ -142,19 +142,3 @@ func GetSunDevices() (devices []dao.Device, err error) {
 	}
 	return
 }
-
-func UpdateRegisterAddress(deviceId string) error {
-	if conn1, ok := model.ConnectionMap1.Load(deviceId); ok {
-		// 成功找到连接
-		netConn := conn1.(net.Conn)
-		err := utils.WriteDevice(modbus.UpdateRegisterAddress(), netConn)
-		if err != nil {
-			logger.Get().Errorf("UpdateRegisterAddress error: %v\n", err)
-			return err
-		}
-	} else {
-		// 没有找到对应的连接
-		logger.Get().Printf("Connection for key %s not found", deviceId)
-	}
-	return nil
-}

+ 37 - 33
static/data.json

@@ -7,21 +7,22 @@
       {
         "id": 1,
         "sn": "JM36xWRZq6PiwmKV",
+        "ip": "192.168.110.73",
         "regionId": 1,
         "name": "维修车间",
         "genre": "八回路控制",
         "state": 1,
         "isSun": true,
         "loopNumber": 8,
-        "onlineTime": "2025-03-21T11:44:00.0106313+08:00",
+        "onlineTime": "2025-03-23T14:29:00.011787+08:00",
         "deviceLoops": [
           {
             "id": 1,
             "deviceId": "JM36xWRZq6PiwmKV",
             "name": "回路12",
-            "state": 1,
-            "timeCondition1OnTime": "08:10",
-            "timeCondition1OffTime": "关闭",
+            "state": 0,
+            "timeCondition1OnTime": "16:00",
+            "timeCondition1OffTime": "08:10",
             "timeCondition2OnTime": "关闭",
             "timeCondition2OffTime": "关闭"
           },
@@ -29,9 +30,9 @@
             "id": 2,
             "deviceId": "JM36xWRZq6PiwmKV",
             "name": "回路2",
-            "state": 1,
-            "timeCondition1OnTime": "关闭",
-            "timeCondition1OffTime": "关闭",
+            "state": 0,
+            "timeCondition1OnTime": "16:00",
+            "timeCondition1OffTime": "08:10",
             "timeCondition2OnTime": "关闭",
             "timeCondition2OffTime": "关闭"
           },
@@ -39,9 +40,9 @@
             "id": 3,
             "deviceId": "JM36xWRZq6PiwmKV",
             "name": "回路3",
-            "state": 1,
+            "state": 0,
             "timeCondition1OnTime": "16:00",
-            "timeCondition1OffTime": "关闭",
+            "timeCondition1OffTime": "08:10",
             "timeCondition2OnTime": "关闭",
             "timeCondition2OffTime": "关闭"
           },
@@ -49,9 +50,9 @@
             "id": 4,
             "deviceId": "JM36xWRZq6PiwmKV",
             "name": "回路4",
-            "state": 1,
+            "state": 0,
             "timeCondition1OnTime": "16:00",
-            "timeCondition1OffTime": "关闭",
+            "timeCondition1OffTime": "08:10",
             "timeCondition2OnTime": "关闭",
             "timeCondition2OffTime": "关闭"
           },
@@ -59,9 +60,9 @@
             "id": 5,
             "deviceId": "JM36xWRZq6PiwmKV",
             "name": "回路5",
-            "state": 1,
+            "state": 0,
             "timeCondition1OnTime": "16:00",
-            "timeCondition1OffTime": "关闭",
+            "timeCondition1OffTime": "08:10",
             "timeCondition2OnTime": "关闭",
             "timeCondition2OffTime": "关闭"
           },
@@ -69,9 +70,9 @@
             "id": 6,
             "deviceId": "JM36xWRZq6PiwmKV",
             "name": "回路6",
-            "state": 1,
+            "state": 0,
             "timeCondition1OnTime": "16:00",
-            "timeCondition1OffTime": "关闭",
+            "timeCondition1OffTime": "08:10",
             "timeCondition2OnTime": "关闭",
             "timeCondition2OffTime": "关闭"
           },
@@ -79,9 +80,9 @@
             "id": 7,
             "deviceId": "JM36xWRZq6PiwmKV",
             "name": "回路7",
-            "state": 1,
+            "state": 0,
             "timeCondition1OnTime": "16:00",
-            "timeCondition1OffTime": "关闭",
+            "timeCondition1OffTime": "08:10",
             "timeCondition2OnTime": "关闭",
             "timeCondition2OffTime": "关闭"
           },
@@ -89,9 +90,9 @@
             "id": 8,
             "deviceId": "JM36xWRZq6PiwmKV",
             "name": "回路8",
-            "state": 1,
+            "state": 0,
             "timeCondition1OnTime": "16:00",
-            "timeCondition1OffTime": "关闭",
+            "timeCondition1OffTime": "08:10",
             "timeCondition2OnTime": "关闭",
             "timeCondition2OffTime": "关闭"
           }
@@ -105,52 +106,53 @@
       },
       {
         "id": 3,
-        "sn": "JM453Sa4a8pdYdgV",
+        "sn": "JM45L1V0q2TrA8tn",
+        "ip": "192.168.110.109",
         "regionId": 1,
         "name": "洗车房",
         "genre": "四回路控制",
-        "state": 0,
+        "state": 1,
         "isSun": false,
         "loopNumber": 4,
-        "onlineTime": "2025-01-19T09:46:00.028035846+08:00",
+        "onlineTime": "2025-03-23T14:29:01.0073454+08:00",
         "deviceLoops": [
           {
             "id": 1,
-            "deviceId": "JM453Sa4a8pdYdgV",
+            "deviceId": "JM45L1V0q2TrA8tn",
             "name": "回路1",
             "state": 0,
             "timeCondition1OnTime": "16:00",
-            "timeCondition1OffTime": "关闭",
+            "timeCondition1OffTime": "08:10",
             "timeCondition2OnTime": "关闭",
             "timeCondition2OffTime": "关闭"
           },
           {
             "id": 2,
-            "deviceId": "JM453Sa4a8pdYdgV",
+            "deviceId": "JM45L1V0q2TrA8tn",
             "name": "回路2",
-            "state": 0,
-            "timeCondition1OnTime": "16:00",
-            "timeCondition1OffTime": "关闭",
+            "state": 1,
+            "timeCondition1OnTime": "01:00",
+            "timeCondition1OffTime": "16:10",
             "timeCondition2OnTime": "关闭",
             "timeCondition2OffTime": "关闭"
           },
           {
             "id": 3,
-            "deviceId": "JM453Sa4a8pdYdgV",
+            "deviceId": "JM45L1V0q2TrA8tn",
             "name": "回路3",
             "state": 0,
             "timeCondition1OnTime": "16:00",
-            "timeCondition1OffTime": "关闭",
+            "timeCondition1OffTime": "08:10",
             "timeCondition2OnTime": "关闭",
             "timeCondition2OffTime": "关闭"
           },
           {
             "id": 4,
-            "deviceId": "JM453Sa4a8pdYdgV",
+            "deviceId": "JM45L1V0q2TrA8tn",
             "name": "回路4",
             "state": 0,
             "timeCondition1OnTime": "16:00",
-            "timeCondition1OffTime": "关闭",
+            "timeCondition1OffTime": "08:10",
             "timeCondition2OnTime": "关闭",
             "timeCondition2OffTime": "关闭"
           }
@@ -165,6 +167,7 @@
       {
         "id": 2,
         "sn": "JM45U0zGDCMhgrxc",
+        "ip": "",
         "regionId": 1,
         "name": "污泥厂大配电房",
         "genre": "四回路控制",
@@ -224,6 +227,7 @@
       {
         "id": 4,
         "sn": "JM45S67eqnSKueAK",
+        "ip": "",
         "regionId": 1,
         "name": "生活区",
         "genre": "四回路控制",
@@ -281,6 +285,6 @@
         }
       }
     ],
-    "version": 5362
+    "version": 9377
   }
 ]

+ 36 - 91
utils/myTool.go

@@ -9,6 +9,7 @@ import (
 	"path/filepath"
 	"server/dao"
 	"server/logger"
+	"server/model"
 	"strings"
 	"sync"
 	"time"
@@ -82,8 +83,8 @@ func GetAllDevices() (devices []dao.Device, err error) {
 	return devices, err
 }
 
-// GetDataByDeviceId 按设备id获取信息 地区+设备
-func GetDataByDeviceId(deviceId string) (reg dao.Region, dev dao.Device, err error) {
+// GetDataByDeviceIP 按设备ip获取信息 地区+设备
+func GetDataByDeviceIP(remoteAddr string) (reg dao.Region, dev dao.Device, err error) {
 	regions, err := LoadData()
 	if err != nil {
 		return reg, dev, err
@@ -91,13 +92,30 @@ func GetDataByDeviceId(deviceId string) (reg dao.Region, dev dao.Device, err err
 
 	for _, region := range regions {
 		for _, device := range region.Devices {
-			if device.Sn == deviceId {
+			if device.Ip == remoteAddr {
 				return region, device, nil
 			}
 		}
 	}
 
-	return reg, dev, fmt.Errorf("设备%s未找到", deviceId)
+	return reg, dev, fmt.Errorf("设备%s未找到", remoteAddr)
+}
+
+func GetDataByDeviceId(id string) (reg dao.Region, dev dao.Device, err error) {
+	regions, err := LoadData()
+	if err != nil {
+		return reg, dev, err
+	}
+
+	for _, region := range regions {
+		for _, device := range region.Devices {
+			if device.Sn == id {
+				return region, device, nil
+			}
+		}
+	}
+
+	return reg, dev, fmt.Errorf("设备id%s未找到", id)
 }
 
 func SaveRegionOnData(data dao.Region) ([]dao.Region, error) {
@@ -158,46 +176,8 @@ func SaveRegions(regions []dao.Region) {
 
 // SaveData 保存数据到文件
 func SaveData(path string, newData []dao.Region) error {
-	// 加载当前数据
-	currentRegions, err := LoadData()
-	if err != nil {
-		return err
-	}
-
-	// 创建一个映射以便快速查找
-	regionMap := make(map[string]dao.Region)
-	orderSlice := make([]string, 0, len(currentRegions)) // 用于保存顺序的切片
-	for _, region := range currentRegions {
-		regionMap[region.Name] = region
-		orderSlice = append(orderSlice, region.Name)
-	}
-
-	// 遍历传入的新数据,进行版本控制检查
-	for _, newRegion := range newData {
-		existingRegion, exists := regionMap[newRegion.Name]
-		if exists {
-			if existingRegion.Version != newRegion.Version {
-				return fmt.Errorf("版本冲突: 区域 '%s' 的当前版本=%d, 提交版本=%d", newRegion.Name, existingRegion.Version, newRegion.Version)
-			}
-			// 更新版本号
-			newRegion.Version++
-			regionMap[newRegion.Name] = newRegion
-		} else {
-			// 如果区域不存在,则直接添加(假设这是新增的区域)
-			newRegion.Version = 1 // 新增区域的初始版本号设为1
-			regionMap[newRegion.Name] = newRegion
-			orderSlice = append(orderSlice, newRegion.Name) // 添加新区域到顺序切片
-		}
-	}
-
-	// 将 map 按照 orderSlice 的顺序转换回 slice
-	updatedRegions := make([]dao.Region, 0, len(regionMap))
-	for _, name := range orderSlice {
-		updatedRegions = append(updatedRegions, regionMap[name])
-	}
-
 	// 序列化数据
-	data, err := json.MarshalIndent(updatedRegions, "", "  ")
+	data, err := json.MarshalIndent(newData, "", "  ")
 	if err != nil {
 		return fmt.Errorf("JSON 序列化失败: %v", err)
 	}
@@ -274,7 +254,12 @@ func checkConnection(conn net.Conn) error {
 // checkAndReconnect 检查是否需要重连,并在必要时执行重连
 func checkAndReconnect(conn net.Conn) (net.Conn, error) {
 	remoteAddr := conn.RemoteAddr().String()
-
+	// 解析远程地址
+	addr1, err := net.ResolveTCPAddr("tcp", remoteAddr)
+	if err != nil {
+		// 处理错误...
+		logger.Get().Errorf("解析错误 conn = %s\n", addr1.IP.String())
+	}
 	// 关闭旧连接
 	if err := conn.Close(); err != nil {
 		logger.Get().Errorf("Failed to close connection: %v", err)
@@ -282,7 +267,7 @@ func checkAndReconnect(conn net.Conn) (net.Conn, error) {
 	}
 
 	// 解析原始连接的远程地址和网络接口
-	addr, networkInterface, err := parseRemoteAddr(remoteAddr)
+	addr, networkInterface, err := parseRemoteAddr(addr1.IP.String())
 	if err != nil {
 		logger.Get().Errorf("Failed to parse remote address: %v", err)
 		return nil, err
@@ -475,53 +460,13 @@ func WriteDevice1(frame []byte, conn net.Conn) error {
 }
 
 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 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) // 等待一段时间后重试
-				continue                  // 继续下一次重试
-			}
-			conn = newConn
-			continue // 重试写入
-		}
-
-		// 如果不是对端强制关闭连接的错误,则直接返回错误
-		logger.Get().Errorf("Write failed: %v", err)
-		return fmt.Errorf("write failed after %d retries: %v", attempts+1, err)
+	_, err := conn.Write(frame)
+	if err != nil {
+		defer conn.Close()
+		model.ConnectionMap1.Delete(conn.RemoteAddr().String())
+		return err
 	}
-
-	return fmt.Errorf("failed to write after %d retries", maxRetries)
+	return nil
 }
 
 // 解析远程地址,提取 IP 地址和网络接口名称