package m9zApi import ( "encoding/json" "fmt" "os" "path/filepath" "sort" "sync" "time" "github.com/gogf/gf/v2/errors/gerror" "github.com/towgo/towgo/lib/system" g "tgk-touch/internal/global" "tgk-touch/internal/library/m9z" ) var l sync.Mutex var historyLock sync.Mutex var filePath = system.GetPathOfProgram() + "data/data.json" const ( maxItems = 50 ) func ScanM9z() { if !l.TryLock() { return } defer l.Unlock() cuid := g.Config().DeviceInfo.DeviceId for i := 0; i < configuredLoopCount(); i++ { read, err := m9z.SubLoopParametersRead(cuid, uint(i)) if err != nil { g.Log().Error("sub loop parameters read error:", err) continue } if read == nil { continue } faults := m9z.BuildLoopFaults(uint(i+1), read.AlarmStatus, read.AlarmCode) recordLoopFaults(cuid, uint(i+1), read.DCVoltage, faults) } } func recordLoopFaults(commUid string, loopIdx uint, voltage float32, faults []m9z.LoopFault) { for _, fault := range faults { item := M9zFaultHistory{ CommUid: commUid, LoopIdx: loopIdx, Voltage: voltage, FaultMsg: fault.Message, FaultCode: fault.Code, FaultTime: time.Now(), } if err := addData(item); err != nil { g.Log().Error(gerror.Wrap(err, "create error")) } } } func readData() ([]M9zFaultHistory, error) { if _, err := os.Stat(filePath); os.IsNotExist(err) { file, err := createFileWithPath(filePath) if err != nil { return nil, gerror.Wrap(err, "create file error") } _ = file.Close() return []M9zFaultHistory{}, nil } data, err := os.ReadFile(filePath) if err != nil { return nil, fmt.Errorf("读取文件失败: %v", err) } var items []M9zFaultHistory if len(data) > 0 { if err := json.Unmarshal(data, &items); err != nil { return nil, fmt.Errorf("解析 JSON 失败: %v", err) } } for i := range items { items[i].ID = int64(i + 1) } return items, nil } func writeData(items []M9zFaultHistory) error { data, err := json.MarshalIndent(items, "", " ") if err != nil { return fmt.Errorf("序列化 JSON 失败: %v", err) } return os.WriteFile(filePath, data, 0644) } func addData(newItem M9zFaultHistory) error { historyLock.Lock() defer historyLock.Unlock() items, err := readData() if err != nil { return gerror.Wrap(err, "readData") } for _, item := range items { if item.CommUid == newItem.CommUid && item.LoopIdx == newItem.LoopIdx && item.FaultCode == newItem.FaultCode && item.FaultMsg == newItem.FaultMsg && item.OperateStatus == 0 { return nil } } if newItem.FaultTime.IsZero() { newItem.FaultTime = time.Now() } items = append(items, newItem) if len(items) > maxItems { sort.Slice(items, func(i, j int) bool { return items[i].FaultTime.Before(items[j].FaultTime) }) items = items[len(items)-maxItems:] } for i := range items { items[i].ID = int64(i + 1) } if err := writeData(items); err != nil { return gerror.Wrap(err, "writeData") } return nil } func deleteById(id int) error { historyLock.Lock() defer historyLock.Unlock() items, err := readData() if err != nil { return gerror.Wrap(err, "readData") } if id < 1 || id > len(items) { return fmt.Errorf("ID %d 超出范围", id) } items = append(items[:id-1], items[id:]...) for i := id - 1; i < len(items); i++ { items[i].ID = int64(i + 1) } return writeData(items) } func createFileWithPath(filePath string) (*os.File, error) { if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil { return nil, err } return os.Create(filePath) }