diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7..64c887a 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/README.md b/README.md index d9dcf36..d9f67d9 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ "task_id": "6589", "address": "房间南侧", "type": "1", - "facility": "02" + "facility": "02" }, { "host_uuid": "qbxmjyzrkpntfgswaevodhluicqzxplkm", diff --git a/business/gpio_ctrl.go b/business/gpio_ctrl.go new file mode 100644 index 0000000..37f3184 --- /dev/null +++ b/business/gpio_ctrl.go @@ -0,0 +1,47 @@ +// gpio_controller.go +package business + +import ( + "fmt" + "os" + "strconv" + "time" +) + +const BuzzerGPIO = 109 + +// TriggerBuzzer 触发蜂鸣器响指定秒数 +func TriggerBuzzer(seconds int) { + if seconds <= 0 { + seconds = 10 + } + + // 必须用同步!异步 goroutine 在某些系统里会被静默丢弃 + fmt.Printf("蜂鸣器开始响铃 %d 秒...\n", seconds) + + gpioPath := fmt.Sprintf("/sys/class/gpio/gpio%d", BuzzerGPIO) + + // 1. 强制导出(即使已经导出也没事) + os.WriteFile("/sys/class/gpio/export", []byte(strconv.Itoa(BuzzerGPIO)), 0666) + time.Sleep(50 * time.Millisecond) + + // 2. 强制设为输出 + os.WriteFile(fmt.Sprintf("%s/direction", gpioPath), []byte("out"), 0666) + time.Sleep(10 * time.Millisecond) + + // 3. 拉高 → 响 + if err := os.WriteFile(fmt.Sprintf("%s/value", gpioPath), []byte("1"), 0666); err != nil { + fmt.Printf("GPIO拉高失败: %v\n", err) + } else { + fmt.Println("GPIO109 已拉高 → 蜂鸣器响!") + } + + time.Sleep(time.Duration(seconds) * time.Second) + + // 4. 拉低 → 停 + if err := os.WriteFile(fmt.Sprintf("%s/value", gpioPath), []byte("0"), 0666); err != nil { + fmt.Printf("GPIO拉低失败: %v\n", err) + } else { + fmt.Println("GPIO109 已拉低 → 蜂鸣器停止") + } +} diff --git a/connect/ws_channel.go b/connect/ws_channel.go index 6d6ec2a..2fa13b4 100644 --- a/connect/ws_channel.go +++ b/connect/ws_channel.go @@ -17,6 +17,17 @@ var ( wsURL = "ws://172.17.0.1:18080/ws" ) +type AlertMessage struct { + UUID string `json:"uuid"` + Topic string `json:"topic"` + QoS int `json:"qos"` + Content string `json:"content"` + Timeout int `json:"timeout"` +} +type AlertContent struct { + Type int `json:"type"` // 1=蜂鸣器告警 + BuzzerDuration int `json:"buzzer_duration"` // 响多久(秒) +} type WSMessage struct { ID int64 `json:"id,omitempty"` Method string `json:"method"` @@ -46,8 +57,9 @@ type MetricDataParams struct { } type PublishParams struct { - Topic string `json:"topic"` - Data json.RawMessage `json:"data,omitempty"` + Topic string `json:"topic"` + Data json.RawMessage `json:"data,omitempty"` + Content json.RawMessage `json:"content,omitempty"` } type WSClient struct { @@ -65,15 +77,6 @@ type WSClient struct { reconnectFlag bool } -// ==================== Public API ==================== - -//// GetWSClient returns the global WebSocket client instance -//func GetWSClient() *WSClient { -// wsMutex.RLock() -// defer wsMutex.RUnlock() -// return wsClient -//} - // InitWSChannel initializes WebSocket connection func InitWSChannel() error { wsMutex.Lock() @@ -361,7 +364,9 @@ func (c *WSClient) handlePublishMessage(message WSMessage) { logger.Logger.Printf("Failed to parse publish message parameters: %v", err) return } - + // 加这一行!万能抓包,永不漏! + logger.Logger.Printf("WebSocket 收到 publish 消息 → Topic: %s | 原始数据: %s", + publishParams.Topic, string(publishParams.Data)) c.mutex.Lock() callback, exists := c.subscribers[publishParams.Topic] c.mutex.Unlock() @@ -458,11 +463,11 @@ func (c *WSClient) autoReRegister() { } c.mutex.Unlock() - for topic, callback := range subscribers { - if err := SubscribeTopic(topic, callback); err != nil { - logger.Logger.Printf("Failed to re-subscribe topic %s: %v", topic, err) - } - } + //for topic, callback := range subscribers { + // if err := SubscribeTopic(topic, callback); err != nil { + // logger.Logger.Printf("Failed to re-subscribe topic %s: %v", topic, err) + // } + //} } } diff --git a/dthjjc b/dthjjc index dfcf994..3354203 100644 Binary files a/dthjjc and b/dthjjc differ diff --git a/main.go b/main.go index cc49847..811b6bc 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,7 @@ import ( "log" "os" "os/signal" + "strconv" "syscall" "time" ) @@ -126,6 +127,13 @@ func runNormalMode() { if err := connect.SubscribeTopic("device_updates", handleDeviceUpdates); err != nil { log.Fatal("Topic subscription failed:", err) } + logger.Logger.Printf("Subscribing to alert topic (/dthjjc/alert) for buzzer...") + + if err := connect.SubscribeTopic("/dthjjc/alert", handleAlertMessage); err != nil { + logger.Logger.Printf("Failed to subscribe alert topic: %v (continue anyway)", err) + } else { + logger.Logger.Printf("Successfully subscribed to /dthjjc/alert → buzzer ready!") + } // 8. 启动数据采集循环 logger.Logger.Printf("Starting data collection loop...") @@ -171,3 +179,63 @@ func startDataCollectionLoop(businessManager *business.BusinessManager) { } } + +func handleAlertMessage(params *connect.PublishParams) { + payload := params.Content + if len(payload) == 0 { + payload = params.Data + } + if len(payload) == 0 { + logger.Logger.Printf("平台告警空包 → 强制响 3 秒") + business.TriggerBuzzer(3) + return + } + + raw := string(payload) + logger.Logger.Printf("收到告警原始内容 → %s", raw) + + type Cmd struct { + Type int `json:"type"` + BuzzerDuration json.RawMessage `json:"buzzer_duration"` // 万能类型! + } + var cmd Cmd + + var outer string + if json.Unmarshal(payload, &outer) == nil { + logger.Logger.Printf("检测到外层是字符串 → %s", outer) + raw = outer + } + + if err := json.Unmarshal([]byte(raw), &cmd); err != nil { + logger.Logger.Printf("最终解析失败: %v → 暴力识别", err) + } else if cmd.Type == 1 { + + dur := 3 + var temp interface{} + if json.Unmarshal(cmd.BuzzerDuration, &temp) == nil { + switch v := temp.(type) { + case string: + if n, err := strconv.Atoi(v); err == nil { + dur = n + } + case float64: + dur = int(v) + case int: + dur = v + } + } + if dur <= 0 { + dur = 3 + } + + logger.Logger.Printf("平台告警解析成功 → 蜂鸣器响 %d 秒!!!", dur) + business.TriggerBuzzer(dur) + return + } + + // 终极兜底:只要包含 type 和 1 就响 + //if strings.Contains(raw, "type") && strings.Contains(raw, "1") { + // logger.Logger.Printf("暴力识别告警指令 → 强制响 3 秒") + // business.TriggerBuzzer(3) + //} +} diff --git a/连接线路.drawio b/连接线路.drawio new file mode 100644 index 0000000..3a6ef4f --- /dev/null +++ b/连接线路.drawio @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +