package adl400TtyApi import ( "fmt" "github.com/gogf/gf/v2/errors/gerror" "github.com/towgo/towgo/towgo" "math" "tgk-touch/internal/global" "tgk-touch/internal/library/ADL400" "tgk-touch/internal/module/basicInfo/deviceManagement" "time" ) func readPhaseData(rpc towgo.JsonRpcConnection) { var p struct { CommUid string `json:"comm_uid"` } rpc.ReadParams(&p) addr := getMeterAddr(p.CommUid) rtuCommUid := p.CommUid var mp deviceManagement.MeterPower totalEnergy, aEnergy, bEnergy, cEnergy, err := mc.ReadEnergy(rtuCommUid, addr) if err != nil { panic(err) } mp.TotalActiveEnergy = math.Round(totalEnergy*100) / 100 mp.AEnergy = math.Round(aEnergy*100) / 100 mp.BEnergy = math.Round(bEnergy*100) / 100 mp.CEnergy = math.Round(cEnergy*100) / 100 _, aVoltage, bVoltage, cVoltage, err := mc.ReadVoltage(rtuCommUid, addr) if err != nil { panic(err) } mp.AVoltage = math.Round(aVoltage*100) / 100 mp.BVoltage = math.Round(bVoltage*100) / 100 mp.CVoltage = math.Round(cVoltage*100) / 100 _, aElectricCurrent, bElectricCurrent, cElectricCurrent, err := mc.ReadElectricCurrent(rtuCommUid, addr) if err != nil { panic(err) } mp.AElectricCurrent = math.Round(aElectricCurrent*100) / 100 mp.BElectricCurrent = math.Round(bElectricCurrent*100) / 100 mp.CElectricCurrent = math.Round(cElectricCurrent*100) / 100 totalPower, aPower, bPower, cPower, err := mc.ReadPower(rtuCommUid, addr) if err != nil { panic(err) } mp.TotalActivePower = math.Round(totalPower*100) / 100 mp.APower = math.Round(aPower*100) / 100 mp.BPower = math.Round(bPower*100) / 100 mp.CPower = math.Round(cPower*100) / 100 tf, af, bf, cf, err := mc.ReadPowerFactor(rtuCommUid, addr) if err != nil { panic(err) } mp.TotalPowerFactor = math.Round(tf*1000) / 1000 mp.APowerFactor = math.Round(af*100) / 100 mp.BPowerFactor = math.Round(bf*100) / 100 mp.CPowerFactor = math.Round(cf*100) / 100 if mp.TotalPowerFactor >= 1 { mp.TotalPowerFactor = 0.999 } rpc.WriteResult(mp) } func getMsgAddress(rpc towgo.JsonRpcConnection) { var p struct { CommUid string `json:"comm_uid"` } rpc.ReadParams(&p) addr, err := mc.ReadMsgAddr(p.CommUid, getMeterAddr(p.CommUid)) if err != nil { panic(err) } rpc.WriteResult(fmt.Sprintf("0x%X", addr)) } // 获取日冻结时间 func getDailyFreezingTime(rpc towgo.JsonRpcConnection) { var p struct { CommUid string `json:"comm_uid"` } rpc.ReadParams(&p) time, err := mc.ReadDailyFreezingTime(p.CommUid, getMeterAddr(p.CommUid)) if err != nil { panic(gerror.Wrap(err, "getDailyFreezingTime")) } rpc.WriteResult(time) } func geDeviceTime(rpc towgo.JsonRpcConnection) { var p struct { CommUid string `json:"comm_uid"` } rpc.ReadParams(&p) time, err := mc.ReadTime(p.CommUid, getMeterAddr(p.CommUid)) if err != nil { panic(gerror.Wrap(err, "geTime")) } rpc.WriteResult(time.Format("2006-01-02 15:04:05")) } func getReadMonthlyFreezingTime(rpc towgo.JsonRpcConnection) { var p struct { CommUid string `json:"comm_uid"` } rpc.ReadParams(&p) day, hour, err := mc.ReadMonthlyFreezingTime(p.CommUid, getMeterAddr(p.CommUid)) if err != nil { panic(gerror.Wrap(err, "getReadMonthlyFreezingTime")) } r := map[string]interface{}{} r["day"] = day r["hour"] = hour rpc.WriteResult(r) } func getFreezeTheData(rpc towgo.JsonRpcConnection) { var p struct { CommUid string `json:"comm_uid"` } rpc.ReadParams(&p) /*read, err := ADL400.H6000.Read(p.CommUid, getMeterAddr(p.CommUid)) if err != nil { panic(err) } block, err := ParseHistoricalEnergyBlock(read) if err != nil { panic(err) }*/ dayData := []*HistoricalEnergyBlock{} monthData := []*HistoricalEnergyBlock{} for i := 1; i <= 90; i++ { time.Sleep(10 * time.Second) address, err := ADL400.GetDailyBlockAddress(i) if err != nil { panic(err) } g.Log().Debugf("GetDailyBlockAddress:% X", address) read, err := address.Read(p.CommUid, getMeterAddr(p.CommUid)) if err != nil { g.Log().Error(err) continue } block, err := ParseHistoricalEnergyBlock(read) if err != nil { panic(err) } dayData = append(dayData, block) } for i := 1; i <= 48; i++ { time.Sleep(10 * time.Second) address, err := ADL400.GetMonthlyBlockAddress(i) if err != nil { g.Log().Error(err) continue } g.Log().Debugf("GetMonthlyBlockAddress:% X", address) read, err := address.Read(p.CommUid, getMeterAddr(p.CommUid)) if err != nil { g.Log().Error(err) continue } block, err := ParseHistoricalEnergyBlock(read) if err != nil { panic(err) } monthData = append(monthData, block) } r := map[string]interface{}{} r["day"] = dayData r["month"] = monthData rpc.WriteResult(r) } // HistoricalEnergyBlock 包含块读取的历史电能数据 type HistoricalEnergyBlock struct { FreezeTime time.Time // 冻结时间 TotalActiveEnergy float64 // 总有功电能 (kWh) PeakActiveEnergy float64 // 有功尖电能 (kWh) FlatActiveEnergy float64 // 有功峰电能 (kWh) OffPeakActiveEnergy float64 // 有功平电能 (kWh) ValleyActiveEnergy float64 // 有功谷电能 (kWh) TotalReactiveEnergy float64 // 总无功电能 (kvarh) PeakReactiveEnergy float64 // 无功尖电能 (kvarh) FlatReactiveEnergy float64 // 无功峰电能 (kvarh) OffPeakReactiveEnergy float64 // 无功平电能 (kvarh) ValleyReactiveEnergy float64 // 无功谷电能 (kvarh) PhaseAActiveEnergy float64 // A相正向有功电能 (kWh) PhaseBActiveEnergy float64 // B相正向有功电能 (kWh) PhaseCActiveEnergy float64 // C相正向有功电能 (kWh) MaxActiveDemand float64 // 有功最大需量 (kW) MaxActiveDemandTime time.Time // 有功最大需量发生时间 MaxReactiveDemand float64 // 无功最大需量 (kvar) MaxReactiveDemandTime time.Time // 无功最大需量发生时间 } // parseUint16Time 解析寄存器中的时间格式 func parseUint16Time(register uint16) (byte, byte) { // 寄存器格式:高字节 = 第一部分,低字节 = 第二部分 return byte(register >> 8), byte(register & 0xFF) } // parseEnergy 解析电能值 (32位数据:2个寄存器) func parseEnergy(registers []uint16, offset int) float64 { value := uint32(registers[offset])<<16 | uint32(registers[offset+1]) // 假设精度为0.01 kWh/kvarh (根据实际情况调整) return float64(value) * 0.01 } // parseDemand 解析需量值 (16位数据) func parseDemand(register uint16) float64 { // 假设精度为0.01 kW/kvar (根据实际情况调整) return float64(register) * 0.01 } // parseDateTime 解析日期时间 (年、月、日、时、分) func parseDateTime(year, month, day, hour, minute uint16) time.Time { // 处理特殊年份格式 (假设2000年基准) if year < 100 { year += 2000 } // 注意:冻结日期可能不是当前日期 return time.Date( int(year), time.Month(month), int(day), int(hour), int(minute), 0, 0, time.Local, ) } // ParseHistoricalEnergyBlock 解析 H6000 块读取的数据 func ParseHistoricalEnergyBlock(registers []uint16) (*HistoricalEnergyBlock, error) { // 验证数据长度应为 34个寄存器 * 2字节/寄存器 = 68字节 if len(registers) != 34 { return nil, fmt.Errorf("invalid data length: expected 68 bytes, got %d", len(registers)) } // 将字节数据转换为 uint16 寄存器数组 /* registers := make([]uint16, 34) err := binary.Read(bytes.NewReader(data), binary.BigEndian, ®isters) if err != nil { return nil, fmt.Errorf("binary read error: %v", err) }*/ block := &HistoricalEnergyBlock{} // 解析冻结时间 freezeYear, freezeMonth := parseUint16Time(registers[0]) // 6000H: 年-月 freezeDay, freezeHour := parseUint16Time(registers[1]) // 6001H: 日-时 block.FreezeTime = parseDateTime( uint16(freezeYear), uint16(freezeMonth), uint16(freezeDay), uint16(freezeHour), 0, ) // 解析电能数据 (32位值, 各2个寄存器) block.TotalActiveEnergy = parseEnergy(registers, 2) // 6002H-6003H block.PeakActiveEnergy = parseEnergy(registers, 4) // 6004H-6005H block.FlatActiveEnergy = parseEnergy(registers, 6) // 6006H-6007H (峰) block.OffPeakActiveEnergy = parseEnergy(registers, 8) // 6008H-6009H (平) block.ValleyActiveEnergy = parseEnergy(registers, 10) // 600AH-600BH (谷) block.TotalReactiveEnergy = parseEnergy(registers, 12) // 600CH-600DH block.PeakReactiveEnergy = parseEnergy(registers, 14) // 600EH-600FH block.FlatReactiveEnergy = parseEnergy(registers, 16) // 6010H-6011H (峰) block.OffPeakReactiveEnergy = parseEnergy(registers, 18) // 6012H-6013H (平) block.ValleyReactiveEnergy = parseEnergy(registers, 20) // 6014H-6015H (谷) block.PhaseAActiveEnergy = parseEnergy(registers, 22) // 6016H-6017H block.PhaseBActiveEnergy = parseEnergy(registers, 24) // 6018H-6019H block.PhaseCActiveEnergy = parseEnergy(registers, 26) // 601AH-601BH // 解析有功最大需量及时间 block.MaxActiveDemand = parseDemand(registers[28]) // 601CH (有功最大需量) minute, hour := parseUint16Time(registers[29]) // 601DH: 分-时 day, month := parseUint16Time(registers[30]) // 601EH: 日-月 block.MaxActiveDemandTime = parseDateTime( uint16(block.FreezeTime.Year()), uint16(month), uint16(day), uint16(hour), uint16(minute), ) // 解析无功最大需量及时间 block.MaxReactiveDemand = parseDemand(registers[31]) // 601FH (无功最大需量) minute, hour = parseUint16Time(registers[32]) // 6020H: 分-时 day, month = parseUint16Time(registers[33]) // 6021H: 日-月 block.MaxReactiveDemandTime = parseDateTime( uint16(block.FreezeTime.Year()), uint16(month), uint16(day), uint16(hour), uint16(minute), ) return block, nil }