You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

309 lines
9.5 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package adl400TtyApi
import (
"fmt"
"github.com/towgo/towgo/errors/terror"
"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(terror.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(terror.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(terror.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, &registers)
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
}