2025-10-23 12:33:46 +08:00

237 lines
5.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"bufio"
"encoding/hex"
"fmt"
"io"
"log"
"net"
"os"
"path/filepath"
"strings"
"sync"
"time"
"unicode/utf8"
"weatherstation/config"
"weatherstation/model"
)
type UTF8Writer struct {
w io.Writer
}
func NewUTF8Writer(w io.Writer) *UTF8Writer {
return &UTF8Writer{w: w}
}
func (w *UTF8Writer) Write(p []byte) (n int, err error) {
if utf8.Valid(p) {
return w.w.Write(p)
}
s := string(p)
s = strings.ToValidUTF8(s, "")
return w.w.Write([]byte(s))
}
var (
logFile *os.File
logFileMutex sync.Mutex
currentLogDay int
)
func getLogFileName() string {
currentTime := time.Now()
return filepath.Join("log", fmt.Sprintf("%s.log", currentTime.Format("2006-01-02")))
}
func openLogFile() (*os.File, error) {
logDir := "log"
if _, err := os.Stat(logDir); os.IsNotExist(err) {
os.MkdirAll(logDir, 0755)
}
logFileName := getLogFileName()
return os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
}
func setupLogger() {
var err error
logFile, err = openLogFile()
if err != nil {
log.Fatalf("无法创建日志文件: %v", err)
}
currentLogDay = time.Now().Day()
bufferedWriter := bufio.NewWriter(logFile)
utf8Writer := NewUTF8Writer(bufferedWriter)
go func() {
for {
time.Sleep(1 * time.Second)
logFileMutex.Lock()
bufferedWriter.Flush()
now := time.Now()
if now.Day() != currentLogDay {
oldLogFile := logFile
logFile, err = openLogFile()
if err != nil {
log.Printf("无法创建新日志文件: %v", err)
} else {
oldLogFile.Close()
currentLogDay = now.Day()
bufferedWriter = bufio.NewWriter(logFile)
utf8Writer = NewUTF8Writer(bufferedWriter)
log.SetOutput(io.MultiWriter(os.Stdout, utf8Writer))
log.Println("日志文件已轮转")
}
}
logFileMutex.Unlock()
}
}()
multiWriter := io.MultiWriter(os.Stdout, utf8Writer)
log.SetOutput(multiWriter)
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}
func startUDP() {
cfg := config.GetConfig()
err := model.InitDB()
if err != nil {
log.Fatalf("初始化数据库失败: %v", err)
}
defer model.CloseDB()
addr := fmt.Sprintf(":%d", cfg.Server.UDPPort)
conn, err := net.ListenPacket("udp", addr)
if err != nil {
log.Fatalf("无法监听UDP端口 %d: %v", cfg.Server.UDPPort, err)
}
defer conn.Close()
log.Printf("UDP服务器已启动监听端口 %d...", cfg.Server.UDPPort)
buffer := make([]byte, 2048)
for {
n, addr, err := conn.ReadFrom(buffer)
if err != nil {
log.Printf("读取数据错误: %v", err)
continue
}
rawData := buffer[:n]
log.Printf("从 %s 接收到 %d 字节数据", addr.String(), n)
hexDump := hexDump(rawData)
log.Printf("原始码流(十六进制):\n%s", hexDump)
asciiDump := asciiDump(rawData)
log.Printf("ASCII码:\n%s", asciiDump)
// 首先尝试解析为WH65LP数据
if len(rawData) == 25 && rawData[0] == 0x24 {
wh65lpData, err := model.ParseWH65LPData(rawData)
if err != nil {
log.Printf("解析WH65LP数据失败: %v", err)
} else {
log.Println("成功解析WH65LP气象站数据:")
log.Println(wh65lpData)
// 更新内存中的设备信息
model.UpdateDeviceInMemory(wh65lpData.StationID, addr, model.DeviceTypeWH65LP)
// 注册设备到数据库
err = model.RegisterDeviceInDB(wh65lpData.StationID, addr)
if err != nil {
log.Printf("注册设备失败: %v", err)
}
log.Printf("设备 %s 已注册IP: %s", wh65lpData.StationID, addr.String())
// 保存数据
err = model.SaveWH65LPData(wh65lpData, rawData)
if err != nil {
log.Printf("保存数据到数据库失败: %v", err)
} else {
log.Printf("数据已成功保存到数据库")
}
continue
}
}
// 如果不是WH65LP数据尝试解析为ECOWITT数据
data := string(rawData)
weatherData, err := model.ParseWeatherData(data)
if err != nil {
log.Printf("解析ECOWITT数据失败: %v", err)
continue
}
log.Println("成功解析ECOWITT气象站数据:")
log.Println(weatherData)
if weatherData.StationID != "" {
// 更新内存中的设备信息
model.UpdateDeviceInMemory(weatherData.StationID, addr, model.DeviceTypeEcowitt)
// 注册设备到数据库
err = model.RegisterDeviceInDB(weatherData.StationID, addr)
if err != nil {
log.Printf("注册设备失败: %v", err)
}
log.Printf("设备 %s 已注册IP: %s", weatherData.StationID, addr.String())
} else {
log.Printf("警告: 收到的数据没有站点ID")
}
err = model.SaveWeatherData(weatherData, data)
if err != nil {
log.Printf("保存数据到数据库失败: %v", err)
} else {
log.Printf("数据已成功保存到数据库")
}
}
}
func main() {
setupLogger()
startUDP() // 直接运行UDP服务器不再使用goroutine
}
func hexDump(data []byte) string {
var result strings.Builder
for i := 0; i < len(data); i += 16 {
end := i + 16
if end > len(data) {
end = len(data)
}
chunk := data[i:end]
hexStr := hex.EncodeToString(chunk)
for j := 0; j < len(hexStr); j += 2 {
if j+2 <= len(hexStr) {
result.WriteString(strings.ToUpper(hexStr[j : j+2]))
result.WriteString(" ")
}
}
result.WriteString("\n")
}
return result.String()
}
func asciiDump(data []byte) string {
var result strings.Builder
for i := 0; i < len(data); i += 64 {
end := i + 64
if end > len(data) {
end = len(data)
}
chunk := data[i:end]
for _, b := range chunk {
if b >= 32 && b <= 126 {
result.WriteByte(b)
} else {
result.WriteString(".")
}
}
result.WriteString("\n")
}
return result.String()
}