|
|
package m9zApi
|
|
|
|
|
|
import (
|
|
|
"encoding/json"
|
|
|
"fmt"
|
|
|
"github.com/towgo/towgo/errors/terror"
|
|
|
"github.com/towgo/towgo/lib/system"
|
|
|
"os"
|
|
|
"path/filepath"
|
|
|
"sort"
|
|
|
"sync"
|
|
|
"tgk-touch/internal/global"
|
|
|
"tgk-touch/internal/library/m9z"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
var l sync.Mutex
|
|
|
var filePath = system.GetPathOfProgram() + "data/data.json" // JSON 文件路径
|
|
|
|
|
|
const (
|
|
|
maxItems = 50 // 最大存储条数
|
|
|
)
|
|
|
|
|
|
func ScanM9z() {
|
|
|
|
|
|
tryLock := l.TryLock()
|
|
|
if !tryLock {
|
|
|
return
|
|
|
}
|
|
|
defer l.Unlock()
|
|
|
/** 挨个查询是否有报警*/
|
|
|
cuid := deviceInfo["deviceId"].(string)
|
|
|
for i := 0; i < 10; 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
|
|
|
}
|
|
|
if read.AlarmStatus != 0 {
|
|
|
var mph M9zFaultHistory
|
|
|
mph.CommUid = cuid
|
|
|
mph.LoopIdx = uint(i) + 1
|
|
|
mph.FaultCode = read.AlarmCode
|
|
|
mph.Voltage = read.DCVoltage
|
|
|
mph.FaultTime = time.Now()
|
|
|
|
|
|
switch read.AlarmStatus {
|
|
|
case 1:
|
|
|
mph.FaultMsg = "欠压/短路故障"
|
|
|
break
|
|
|
case 2:
|
|
|
mph.FaultMsg = "过压/开路故障"
|
|
|
break
|
|
|
case 8:
|
|
|
mph.FaultMsg = "电源故障"
|
|
|
break
|
|
|
case 9:
|
|
|
mph.FaultMsg = "欠压/电源故障"
|
|
|
break
|
|
|
default:
|
|
|
mph.FaultMsg = "未知异常"
|
|
|
}
|
|
|
err = addData(mph)
|
|
|
if err != nil {
|
|
|
g.Log().Error(terror.Wrap(err, "create error"))
|
|
|
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 读取现有数据(如果文件不存在则返回空切片)
|
|
|
func readData() ([]M9zFaultHistory, error) {
|
|
|
|
|
|
if _, err := os.Stat(filePath); os.IsNotExist(err) {
|
|
|
_, err := createFileWithPath(filePath)
|
|
|
if err != nil {
|
|
|
return nil, terror.Wrap(err, "create file error")
|
|
|
}
|
|
|
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)
|
|
|
}
|
|
|
}
|
|
|
// 确保ID匹配索引+1(处理旧数据或缺失ID)
|
|
|
for i := range items {
|
|
|
items[i].ID = int64(i + 1)
|
|
|
}
|
|
|
return items, nil
|
|
|
}
|
|
|
|
|
|
// 写入数据到 JSON 文件
|
|
|
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 {
|
|
|
// 1. 读取现有数据
|
|
|
items, err := readData()
|
|
|
if err != nil {
|
|
|
return terror.Wrap(err, "readData")
|
|
|
}
|
|
|
|
|
|
// 2. 追加新数据
|
|
|
items = append(items, newItem)
|
|
|
|
|
|
// 3. 检查容量,如果超过 maxItems 则删除最早的数据(按时间排序)
|
|
|
if len(items) > maxItems {
|
|
|
// 按 Timestamp 排序(最早的在前)
|
|
|
sort.Slice(items, func(i, j int) bool {
|
|
|
return items[i].FaultTime.Before(items[j].FaultTime)
|
|
|
})
|
|
|
// 删除最早的数据(保留最新的 maxItems 条)
|
|
|
items = items[1:]
|
|
|
for i, _ := range items {
|
|
|
items[i].ID = int64(i + 1)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 4. 写回文件
|
|
|
err = writeData(items)
|
|
|
|
|
|
if err != nil {
|
|
|
return terror.Wrap(err, "writeData")
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// 按ID删除数据
|
|
|
func deleteById(id int) error {
|
|
|
items, err := readData()
|
|
|
if err != nil {
|
|
|
return terror.Wrap(err, "readData")
|
|
|
}
|
|
|
|
|
|
if id < 1 || id > len(items) {
|
|
|
return fmt.Errorf("ID %d 超出范围", id)
|
|
|
}
|
|
|
|
|
|
// 删除指定索引的数据(id-1)
|
|
|
items = append(items[:id-1], items[id:]...)
|
|
|
|
|
|
// 重新分配ID(确保后续数据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) {
|
|
|
// 创建所有必需的父目录(使用 0755 权限)
|
|
|
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
// 创建并打开文件(如果已存在则截断)
|
|
|
return os.Create(filePath)
|
|
|
}
|