package service import ( "encoding/hex" "encoding/json" "errors" "fmt" "github.com/tarm/serial" "log" "smart_tunnel_edge/util/config" "smart_tunnel_edge/util/logger" "strconv" "time" ) var ( parity = map[string]serial.Parity{ "N": serial.ParityNone, // 无校验 "E": serial.ParityEven, // 偶校验 "O": serial.ParityOdd, // 奇校验 "M": serial.ParityMark, // 标记校验 "S": serial.ParitySpace, // 空格校验 } serialPort = make(map[int8]*serial.Port) env = make(map[string]int64) //存储环境传感器光照的切片 opt = make(map[string]int64) //存储光照传感器光照的切片 ) var ( isLightOperate bool // 标记是否进行开灯或调节亮度操作 timer *time.Timer // 用于延时关闭灯的计时器 lastCarTime time.Time // 记录上次来车的时间 lightDuration = 2 * time.Minute // 灯亮的持续时间(2分钟) ) func GetSerialPort(serialID int8) (*serial.Port, error) { port, exists := serialPort[serialID] if !exists { return nil, errors.New("serial port not found") } return port, nil } func OpenSerialPort(portMap map[int8]*config.SerialPort) error { fmt.Println("打开串口...") var lastError error // 遍历串口配置 for _, port := range portMap { // 串口配置 c := &serial.Config{ Name: port.Address, Baud: port.BaudRate, Size: port.DataBits, StopBits: serial.StopBits(port.StopBits), Parity: parity[port.Parity], ReadTimeout: time.Duration(port.Timeout), } // 打开串口 pt, err := serial.OpenPort(c) serialPort[port.Code] = pt if err != nil { logger.Logger.Errorf("无法打开串口 %s: %v", port.Address, err) if lastError == nil { lastError = err } continue } go listenPort(port.Code, pt) //开启线程监听串口 } return lastError } func listenPort(portCode int8, port *serial.Port) { fmt.Println("监听串口...") buf := make([]byte, 128) for { // 读取数据 n, err := port.Read(buf) if err != nil { log.Printf("读取串口数据失败: %v", err) return } if n > 0 { dataString := hex.EncodeToString(buf[:n]) //fmt.Println("数据:", dataString) switch { case len(dataString) == 42 && dataString[2:6] == "0310": //环境传感器数据 //fmt.Print("环境传感:") shiDu, _ := strconv.ParseInt(dataString[6:10], 16, 0) wenDu, _ := strconv.ParseInt(dataString[10:14], 16, 0) gz, _ := strconv.ParseInt(dataString[30:38], 16, 0) if _, exists := env[dataString[0:2]]; !exists { env[dataString[0:2]] = gz } data := EnvData{Temperature: float64(wenDu) / 10.0, Humidity: float64(shiDu) / 10.0, Illuminance: gz} for _, dev := range config.DevConfig.EnvDevs { if dev.Address == dataString[0:2] { data.Sn = dev.Sn break } } jsonData, _ := json.Marshal(data) topic := MqttService.GetTopic(TopicGatherDataEnv) err := MqttService.Publish(topic, jsonData) if err != nil { logger.Logger.Errorf("MQTT Publish err = %s", err.Error()) continue } case len(dataString) == 14 && dataString[2:6] == "0302": //光照传感器数据 //fmt.Printf("光传感:") gz, _ := strconv.ParseInt(dataString[6:10], 16, 0) if _, exists := env[dataString[0:2]]; !exists { opt[dataString[0:2]] = gz } data := OpticalData{Illuminance: gz} for _, dev := range config.DevConfig.EnvDevs { if dev.Address == dataString[0:2] { data.Sn = dev.Sn break } } jsonData, _ := json.Marshal(data) topic := MqttService.GetTopic(TopicGatherDataOpt) err := MqttService.Publish(topic, jsonData) if err != nil { logger.Logger.Errorf("MQTT Publish err = %s", err.Error()) continue } case len(dataString) == 16 && dataString[0:2] == "78" && dataString[8:16] == "40790d0a": //雷达数据 dataBytes, _ := hex.DecodeString(dataString) speed, _ := strconv.Atoi(string(dataBytes)[1:4]) // 配置实例 policy := config.Instance().Policy if speed > 5 && policy.Id == 2 { // 速度大于5且策略为根据来车调光(2代表根据来车改变光照) now := time.Now() // 记录来车时间 // 如果已经操作过灯 if isLightOperate { // 如果在两分钟内再来车,延长计时 if now.Sub(lastCarTime) <= lightDuration { timer.Reset(lightDuration) } } else { OperationLampSwitchJudge(portCode, HighLightLevel, 2, 1) //brightness代表亮度,way代表开关继电器回路数,turnOf代表开还是关,1代表开,0代表关 isLightOperate = true timer = time.AfterFunc(lightDuration, func() { OperationLampSwitchJudge(portCode, LowLightLevel, 2, 0) isLightOperate = false }) } // 更新最后来车时间 lastCarTime = now } continue //default: // // 其他情况可以处理默认数据 // fmt.Printf("错误数据: %s \n", dataString) } if config.Instance().Policy.Id == 1 && config.Instance().Nums.EnvNum == len(env) && config.Instance().Nums.OptNum == len(opt) { envAverage := calculateAverage(env) optAverage := calculateAverage(opt) control := config.Instance().Policy.Control if envAverage-optAverage >= 20000 { //如果相差20000Lux开两路或者调节亮度为90% if control == RegulateLight { go SetLampBright(1, 90) go SetLampBright(2, 90) } else if control == RegulateSwitch { go SetSwitchMultiRelay(1, 1, []int{1, 2, 3}) //int[]{}表达控制的回路 go SetSwitchMultiRelay(2, 1, []int{1, 2, 3}) } } else if envAverage-optAverage >= 10000 { //如果相差10000Lux开两路或者调节亮度为60% if control == RegulateLight { go SetLampBright(1, 60) go SetLampBright(2, 60) } else if control == RegulateSwitch { go SetSwitchRelay(1, 3, 0) //不管如何先将第三路关闭 go SetSwitchRelay(2, 3, 0) go SetSwitchMultiRelay(1, 1, []int{1, 2}) go SetSwitchMultiRelay(2, 1, []int{1, 2}) } } else { if control == RegulateLight { go SetLampBright(1, 30) go SetLampBright(2, 30) } else if control == RegulateSwitch { go SetSwitchMultiRelay(1, 0, []int{2, 3}) go SetSwitchMultiRelay(2, 0, []int{2, 3}) } } env = make(map[string]int64) opt = make(map[string]int64) } } time.Sleep(100 * time.Millisecond) // 设置延迟,避免CPU占用过高 } } func calculateAverage(data map[string]int64) float64 { var sum int64 for _, value := range data { sum += value } if len(data) == 0 { return 0 // 防止除以零 } return float64(sum) / float64(len(data)) }