first commit
This commit is contained in:
164
poweroff_linux/shutdown.go
Normal file
164
poweroff_linux/shutdown.go
Normal file
@ -0,0 +1,164 @@
|
||||
// 通过串口接收指令触发系统关机的程序
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go.bug.st/serial"
|
||||
)
|
||||
|
||||
// Config 配置结构体,从 config.json 文件读取
|
||||
type Config struct {
|
||||
SerialPort string `json:"port"` // 串口设备路径,如 COM1 或 /dev/ttyUSB0
|
||||
BaudRate int `json:"baudRate"` // 串口波特率
|
||||
ShutdownWord string `json:"shutdownWord"` // 触发关机的指令文本
|
||||
}
|
||||
|
||||
// loadConfig 从指定路径加载配置文件并解析为 Config 结构体
|
||||
func loadConfig(configPath string) (*Config, error) {
|
||||
data, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var config Config
|
||||
err = json.Unmarshal(data, &config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 加载配置文件
|
||||
config, err := loadConfig("config.json")
|
||||
if err != nil {
|
||||
log.Fatalf("加载配置文件失败: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("已监听串口 %s (波特率 %d),等待指令 '%s'...", config.SerialPort, config.BaudRate, config.ShutdownWord)
|
||||
|
||||
// 串口读取缓冲区和数据接收缓冲区
|
||||
buf := make([]byte, 1024)
|
||||
var buffer bytes.Buffer
|
||||
|
||||
// 外层循环:持续尝试连接串口
|
||||
for {
|
||||
mode := &serial.Mode{
|
||||
BaudRate: config.BaudRate,
|
||||
}
|
||||
|
||||
// 尝试打开串口
|
||||
port, err := serial.Open(config.SerialPort, mode)
|
||||
if err != nil {
|
||||
log.Printf("打开串口 %s 失败: %v,5秒后重试...", config.SerialPort, err)
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
defer port.Close()
|
||||
log.Printf("串口 %s 已连接", config.SerialPort)
|
||||
|
||||
// 设置读取超时为1秒,避免阻塞
|
||||
port.SetReadTimeout(time.Second * 1)
|
||||
|
||||
// 串口初始化后发送 start 指令
|
||||
_, err = port.Write([]byte("start\r\n"))
|
||||
if err != nil {
|
||||
log.Printf("发送 start 失败: %v", err)
|
||||
port.Close()
|
||||
continue
|
||||
}
|
||||
log.Printf("已发送 start")
|
||||
|
||||
// 启动定时发送 blive的协程
|
||||
sendDone := make(chan struct{})
|
||||
go func() {
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
_, err := port.Write([]byte("blive\r\n"))
|
||||
if err != nil {
|
||||
log.Printf("发送 blive 失败: %v", err)
|
||||
return
|
||||
}
|
||||
case <-sendDone:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// 内层循环:读取串口数据
|
||||
for {
|
||||
n, err := port.Read(buf)
|
||||
if err != nil {
|
||||
if err.Error() == "timeout" {
|
||||
continue
|
||||
}
|
||||
log.Printf("读取串口错误: %v,重新连接...", err)
|
||||
close(sendDone)
|
||||
port.Close()
|
||||
break
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
// 将接收到的数据写入缓冲区
|
||||
buffer.Write(buf[:n])
|
||||
|
||||
data := buffer.String()
|
||||
// 检查是否接收到完整的一行数据(以 \r\n 或 \n 结尾)
|
||||
if strings.Contains(data, "\r\n") || strings.Contains(data, "\n") {
|
||||
var lines []string
|
||||
if strings.Contains(data, "\r\n") {
|
||||
lines = strings.Split(dataAfter(data, "\r\n"), "\r\n")
|
||||
} else {
|
||||
lines = strings.Split(dataAfter(data, "\n"), "\n")
|
||||
}
|
||||
|
||||
// 处理每一行数据
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
log.Printf("收到: %s", line)
|
||||
// 如果匹配到关机指令,执行关机
|
||||
if line == config.ShutdownWord {
|
||||
executeShutdown()
|
||||
}
|
||||
}
|
||||
buffer.Reset()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dataAfter 获取字符串中最后一个分隔符之前的内容
|
||||
// 用于处理跨数据包的行边界问题,保留最后一个不完整的行
|
||||
func dataAfter(s, sep string) string {
|
||||
idx := strings.LastIndex(s, sep)
|
||||
if idx == -1 {
|
||||
return s
|
||||
}
|
||||
return s[:idx]
|
||||
}
|
||||
|
||||
// executeShutdown 执行系统关机命令
|
||||
func executeShutdown() {
|
||||
log.Println("触发关机指令!")
|
||||
log.Println("执行关机命令: shutdown -h now")
|
||||
cmd := exec.Command("shutdown", "-h", "now")
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.Fatalf("关机命令执行失败: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user