Переглянути джерело

Add 新增PMC-350B电表协议

YueYunyun 2 роки тому
батько
коміт
c88616cbe1

+ 26 - 0
SERVER/Meter_Service/controller/dto/meter.go

@@ -0,0 +1,26 @@
+package dto
+
+// GetMeterRatioReq 读取电表变比
+type GetMeterRatioReq struct {
+	SN      string `json:"sn"`
+	Type    string `json:"type"`
+	Addr    int    `json:"addr"`
+	Result  int    `json:"result"`
+	SerData string `json:"serData"`
+}
+
+// SetMeterRatioReq 设置电表变比
+type SetMeterRatioReq struct {
+	SN      string `json:"sn"`
+	Addr    int    `json:"addr"`
+	Type    string `json:"type"`
+	SerData string `json:"serData"`
+}
+
+// SetMeterAddressReq 设置电表地址
+type SetMeterAddressReq struct {
+	SN      string `json:"sn"`
+	AddrOld int    `json:"addrOld"`
+	AddrNew int    `json:"addrNew"`
+	Type    string `json:"type"`
+}

+ 85 - 0
SERVER/Meter_Service/controller/meter.go

@@ -0,0 +1,85 @@
+package controller
+
+import (
+	"MeterService/controller/dto"
+	"MeterService/core/api"
+	"MeterService/core/utils"
+	"MeterService/data"
+	"MeterService/meter"
+	"MeterService/service/downStreamService/proto"
+	"MeterService/service/downStreamService/proto/acrel"
+	"MeterService/service/downStreamService/proto/pmc350b"
+	"MeterService/service/rtuService"
+
+	"github.com/gin-gonic/gin"
+)
+
+func SetMeterAddress(c *gin.Context) {
+	req := dto.SetMeterAddressReq{}
+
+	if req.AddrNew == req.AddrOld {
+		api.Fail(c, "电表地址错误")
+	}
+	if req.AddrOld < 1 || req.AddrOld > 254 || req.AddrNew < 1 || req.AddrNew > 254 {
+		api.Fail(c, "电表地址错误")
+	}
+	meterHandler, w := GetClientHandler(c, req.SN, req.Type, req.AddrOld)
+	if !meterHandler.SetAddress(w, req.AddrNew) {
+		api.Fail(c, "电表地址设置失败")
+	}
+	api.Ok(c)
+}
+
+func SetMeterRatio(c *gin.Context) {
+	req := dto.SetMeterRatioReq{}
+	if req.Addr < 1 || req.Addr > 254 {
+		api.Fail(c, "电表地址错误")
+	}
+	meterHandler, w := GetClientHandler(c, req.SN, req.Type, req.Addr)
+	if !meterHandler.SetRatio(w, req.SerData) {
+		api.Fail(c, "电表比例设置失败")
+	}
+}
+
+func GetMeterRatio(c *gin.Context) {
+	req := dto.GetMeterRatioReq{}
+	if req.Addr < 1 || req.Addr > 254 {
+		api.Fail(c, "电表地址错误")
+	}
+	meterHandler, w := GetClientHandler(c, req.SN, req.Type, req.Addr)
+	dataStr, ok := meterHandler.GetRatio(w)
+	if !ok {
+		api.Fail(c, "电表比例设置失败")
+	}
+
+	api.Ok2(c, dataStr)
+}
+
+func GetClientHandler(c *gin.Context, sn string, mType string, addr int) (proto.MeterHandler, rtuService.RtuNetPgr) {
+	if !meter.VerifyMeterProto(mType) {
+		api.Fail(c, "电表协议错误")
+	}
+	_, ok := data.DtuMap.Get(sn)
+	if !ok {
+		api.Fail(c, "没有找到电表")
+	}
+	client, ok := data.OnlineSN.Get(sn)
+	if !ok {
+		api.Fail(c, "电表正在通信或已离线,请稍后再试")
+	}
+	client.MLock.Lock()
+	defer client.MLock.Unlock()
+	w := rtuService.NewRtuNetPgr(utils.IntoByte(addr))
+	w.SetClientState(client)
+	w.SetSerialNumber(sn)
+	var meterHandler proto.MeterHandler
+	switch mType {
+	case meter.MeterAdw300:
+		meterHandler = acrel.NewAdw300MeterHandler()
+	case meter.MeterPmc350b:
+		meterHandler = pmc350b.NewPmc350bMeterHandler()
+	default:
+		api.Fail(c, "电表协议未提供支持")
+	}
+	return meterHandler, w
+}

+ 4 - 1
SERVER/Meter_Service/core/modbus/api.go

@@ -25,9 +25,12 @@ type Client interface {
 	// ReadInputRegisters reads from 1 to 125 contiguous input registers in
 	// a remote device and returns input registers.
 	ReadInputRegisters(address, quantity uint16) (results []byte, err error)
-
+	//自定义函数
 	PackReadHoldingRegisters(address, quantity uint16) (results []byte, err error)
 	DePackRegisters(aduResponse []byte) (results []byte, err error)
+	PackWriteMultipleRegisters(address, quantity uint16, value []byte) (results []byte, err error)
+	DePackSetRegs(aduResponse []byte) (results []byte, err error)
+
 	// ReadHoldingRegisters reads the contents of a contiguous block of
 	// holding registers in a remote device and returns register value.
 	ReadHoldingRegisters(address, quantity uint16) (results []byte, err error)

+ 70 - 4
SERVER/Meter_Service/core/modbus/client.go

@@ -18,7 +18,11 @@ type ClientHandler interface {
 type client struct {
 	packager    Packager
 	transporter Transporter
-	aduRequest  []byte
+	//发送后存储的数据
+	aduRequest   []byte
+	quantity     uint16
+	address      uint16
+	functionCode byte
 }
 
 // NewClient creates a new modbus client with given backend handler.
@@ -125,10 +129,72 @@ func (mb *client) PackReadHoldingRegisters(address, quantity uint16) (results []
 	}
 	//存储要发送的字节数组,用于接收数据时验证
 	mb.aduRequest = response
+	mb.quantity = quantity
+	mb.address = address
+	mb.functionCode = request.FunctionCode
 	results = response
 	return
 }
 
+// Request:
+//
+//	Function code         : 1 byte (0x10)
+//	Starting address      : 2 bytes
+//	Quantity of outputs   : 2 bytes
+//	Byte count            : 1 byte
+//	Registers value       : N* bytes
+//
+// Response:
+//
+//	Function code         : 1 byte (0x10)
+//	Starting address      : 2 bytes
+//	Quantity of registers : 2 bytes
+func (mb *client) PackWriteMultipleRegisters(address, quantity uint16, value []byte) (results []byte, err error) {
+	if quantity < 1 || quantity > 123 {
+		err = fmt.Errorf("modbus: quantity '%v' must be between '%v' and '%v',", quantity, 1, 123)
+		return
+	}
+	request := ProtocolDataUnit{
+		FunctionCode: FuncCodeWriteMultipleRegisters,
+		Data:         dataBlockSuffix(value, address, quantity),
+	}
+	response, err := mb.pack_post(&request)
+	if err != nil {
+		return
+	}
+	//存储要发送的字节数组,用于接收数据时验证
+	mb.aduRequest = response
+	mb.quantity = quantity
+	mb.address = address
+	mb.functionCode = request.FunctionCode
+	results = response
+	return
+}
+
+func (mb *client) DePackSetRegs(aduResponse []byte) (results []byte, err error) {
+	response, err := mb.depack_rcv(mb.aduRequest, aduResponse)
+	if err != nil {
+		return
+	}
+	// Fixed response length
+	if len(response.Data) != 4 {
+		err = fmt.Errorf("modbus: response data size '%v' does not match expected '%v'", len(response.Data), 4)
+		return
+	}
+	respValue := binary.BigEndian.Uint16(response.Data)
+	if mb.address != respValue {
+		err = fmt.Errorf("modbus: response address '%v' does not match request '%v'", respValue, mb.address)
+		return
+	}
+	results = response.Data[2:]
+	respValue = binary.BigEndian.Uint16(results)
+	if mb.quantity != respValue {
+		err = fmt.Errorf("modbus: response quantity '%v' does not match request '%v'", respValue, mb.quantity)
+		return
+	}
+	return
+}
+
 func (mb *client) DePackRegisters(aduResponse []byte) (results []byte, err error) {
 	response, err := mb.depack_rcv(mb.aduRequest, aduResponse)
 	if err != nil {
@@ -519,7 +585,7 @@ func (mb *client) pack_post(request *ProtocolDataUnit) (aduRequest []byte, err e
 }
 
 func (mb *client) depack_rcv(aduRequest, aduResponse []byte) (response *ProtocolDataUnit, err error) {
-	var functionCode byte
+	//var functionCode byte
 	if err = mb.packager.Verify(aduRequest, aduResponse); err != nil {
 		return
 	}
@@ -528,9 +594,9 @@ func (mb *client) depack_rcv(aduRequest, aduResponse []byte) (response *Protocol
 	if err != nil {
 		return
 	}
-	functionCode = aduRequest[1]
+	//functionCode = aduRequest[1]
 	// Check correct function code returned (exception)
-	if response.FunctionCode != functionCode {
+	if response.FunctionCode != mb.functionCode {
 		err = responseError(response)
 		return
 	}

+ 1 - 1
SERVER/Meter_Service/core/modbus/rtuclient.go

@@ -95,8 +95,8 @@ func (mb *rtuPackager) Decode(adu []byte) (pdu *ProtocolDataUnit, err error) {
 	var crc crc
 	crc.reset().pushBytes(adu[0 : length-2])
 	checksum := uint16(adu[length-1])<<8 | uint16(adu[length-2])
-	//fmt.Println("Decode:", adu, ";length=", length)
 	if checksum != crc.value() {
+		fmt.Println("Decode Err:", adu, ";length=", length)
 		err = fmt.Errorf("modbus-rtu: response crc '%v' does not match expected '%v'", checksum, crc.value())
 		return
 	}

+ 16 - 0
SERVER/Meter_Service/core/utils/util.go

@@ -54,3 +54,19 @@ func TimeDiff(tm, mat int64) bool {
 		return false
 	}
 }
+
+// HfWord2byte 将一个int16转换为两个byte
+func HfWord2byte(obj int) (slice []byte) {
+	slice = append(slice, IntoByte(obj>>8))
+	slice = append(slice, IntoByte(obj&0xFF))
+	return
+}
+
+// Word2byte 将一个int转换为四个byte
+func Word2byte(obj int) (slice []byte) {
+	slice = append(slice, IntoByte(obj>>24))
+	slice = append(slice, IntoByte(obj>>16))
+	slice = append(slice, IntoByte(obj>>8))
+	slice = append(slice, IntoByte(obj&0xFF))
+	return
+}

+ 5 - 1
SERVER/Meter_Service/dataStruct/clientState.go

@@ -1,6 +1,9 @@
 package dataStruct
 
-import "MeterService/core/tcpserver"
+import (
+	"MeterService/core/tcpserver"
+	"sync"
+)
 
 type ClientState struct {
 	FD     *tcpserver.Client
@@ -10,4 +13,5 @@ type ClientState struct {
 	// PwrOff    bool  //掉电状态
 	TmOnline  string
 	TmOffline string
+	MLock     sync.Mutex
 }

+ 1 - 0
SERVER/Meter_Service/dataStruct/dtuConfig.go

@@ -25,6 +25,7 @@ type DtuConfig struct {
 
 type DtuSlave struct {
 	Addr  int               `json:"addr"`  //设备串口地址
+	Cn    string            `json:"cn"`    //设备CN
 	NO    string            `json:"no"`    //设备编号
 	LvRef float32           `json:"lvRef"` //线电压基准(220)
 	PvRef float32           `json:"pvRef"` //相电压基准(380)

+ 12 - 0
SERVER/Meter_Service/dataStruct/struct.go

@@ -77,3 +77,15 @@ type MeterRef struct {
 	PvRef float32
 	LvRef float32
 }
+type MeterRatio struct {
+	Ct int `json:"ct"`
+	Pt int `json:"pt"`
+}
+
+type MeterPMC350BParam struct {
+	PrimaryVolt    int `json:"primary_volt"`
+	SecondVolt     int `json:"second_volt"`
+	PrimaryCurrent int `json:"primary_current"`
+	SecondCurrent  int `json:"second_current"`
+	CType          int `json:"ct_type"`
+}

+ 2 - 2
SERVER/Meter_Service/main.go

@@ -4,13 +4,13 @@ import (
 	_ "MeterService/core/config" // 加载配置文件,需要放在第一行
 	"MeterService/core/db/mysql"
 	"MeterService/core/logger" // 加载logger,放第二行
+	"MeterService/meter"
 	"MeterService/service/downStreamService"
 
 	"MeterService/core/db"
 	//"MeterService/core/db/sqlite"
 
 	"MeterService/data"
-	"MeterService/meter/proto"
 	"MeterService/service/webService"
 	"os"
 	"os/signal"
@@ -33,7 +33,7 @@ func main() {
 	db.InitRedis()
 
 	// 加载电表协议
-	proto.MeterProtoInit()
+	meter.InitMeterProto()
 
 	// 初始化电表数据
 	if data.InitData() {

+ 50 - 0
SERVER/Meter_Service/meter/proto.go

@@ -0,0 +1,50 @@
+package meter
+
+const (
+	// 电表类型
+
+	MeterAdw300  = "ADW300"
+	MeterPmc350b = "PMC350B"
+
+	//  上报平台协议
+
+	PlatYcHj212 = "YC-HJ212"
+)
+
+var (
+	meterProto = make([]string, 0) //电表协议列表
+	platProto  = make([]string, 0) //上报协议列表
+)
+
+// InitMeterProto 初始化电表协议列表和上报协议列表
+func InitMeterProto() {
+	//在这里添加支持的电表协议列表
+	meterProto = append(meterProto, MeterAdw300)
+	meterProto = append(meterProto, MeterPmc350b)
+	meterProto = append(meterProto, "TEST")
+
+	//在这里添加支持的上报协议列表
+	platProto = append(platProto, PlatYcHj212)
+}
+
+// GetMeterProtoList 获取电表协议列表
+func GetMeterProtoList() []string {
+	return meterProto
+}
+
+// GetPlatProtoList 获取上报协议列表
+func GetPlatProtoList() []string {
+	return platProto
+}
+
+func VerifyMeterProto(proto string) bool {
+	if proto == "" {
+		return false
+	}
+	for _, v := range meterProto {
+		if proto == v {
+			return true
+		}
+	}
+	return false
+}

+ 0 - 26
SERVER/Meter_Service/meter/proto/proto.go

@@ -1,26 +0,0 @@
-package proto
-
-var (
-	meterProto = make([]string, 0) //电表协议列表
-	platProto  = make([]string, 0) //上报协议列表
-)
-
-// MeterProtoInit 初始化电表协议列表和上报协议列表
-func MeterProtoInit() {
-	//在这里添加支持的电表协议列表
-	meterProto = append(meterProto, "ADW300")
-	meterProto = append(meterProto, "TEST")
-
-	//在这里添加支持的上报协议列表
-	platProto = append(platProto, "YC-HJ212")
-}
-
-// GetMeterProtoList 获取电表协议列表
-func GetMeterProtoList() []string {
-	return meterProto
-}
-
-// GetPlatProtoList 获取上报协议列表
-func GetPlatProtoList() []string {
-	return platProto
-}

+ 24 - 71
SERVER/Meter_Service/service/downStreamService/collect.go

@@ -5,15 +5,15 @@ import (
 	"MeterService/core/utils"
 	"MeterService/data"
 	"MeterService/dataStruct"
-	"MeterService/database/meterCalcParam"
+	"MeterService/meter"
+	"MeterService/service/downStreamService/proto"
 	"MeterService/service/downStreamService/proto/acrel"
+	"MeterService/service/downStreamService/proto/pmc350b"
 	"MeterService/service/downStreamService/proto/test"
 	"MeterService/service/rtuService"
-	"strconv"
-	"time"
 )
 
-func collectData(sn string, config *dataStruct.DtuConfig) []*dataStruct.CollectData {
+func collectData(sn string, config *dataStruct.DtuConfig) *[]*dataStruct.CollectData {
 	array := make([]*dataStruct.CollectData, 0)
 
 	meterRef := &dataStruct.MeterRef{}
@@ -21,20 +21,21 @@ func collectData(sn string, config *dataStruct.DtuConfig) []*dataStruct.CollectD
 	logger.Debug("开始采集数据【%s】 %v", sn, config)
 
 	if !config.Enable || config.Secs < 1 {
-		return array
+		return &array
 	}
 
 	//client, ok := data.DtuMapState.Get(sn)
 	client, ok := data.OnlineSN.Get(sn)
 	if !ok {
 		logger.Error("采集数据失败,[%s]客户端不存在", sn)
-		return array
+		return &array
 	}
 
 	if !client.Online {
 		logger.Error("采集数据失败,[%s]客户端离线", sn)
 	}
-
+	client.MLock.Lock()
+	defer client.MLock.Unlock()
 	for _, cfg := range config.Slave {
 		if cfg.Addr < 1 || cfg.Addr > 254 {
 			logger.Error("采集数据失败,[%s]客户端地址错误: %d", sn, cfg.Addr)
@@ -53,80 +54,32 @@ func collectData(sn string, config *dataStruct.DtuConfig) []*dataStruct.CollectD
 			meterRef.PvRef = cfg.PvRef
 		}
 		var (
-			colData *dataStruct.CollectData
-			err     error
+			colData        *dataStruct.CollectData
+			err            error
+			collectHandler proto.MeterHandler
 		)
 		switch cfg.MType {
-		case "ADW300":
-			colData, err = acrel.CollectADW300(w, meterRef)
-			if err != nil {
-				logger.Error("采集数据失败, [%s][%s]客户端采集数据错误: %s", sn, cfg.MType, err.Error())
-				continue
-			}
-			processCollectData(colData, cfg)
-			array = append(array, colData)
+		case meter.MeterAdw300:
+			collectHandler = acrel.NewAdw300MeterHandler()
+		case meter.MeterPmc350b:
+			collectHandler = pmc350b.NewPmc350bMeterHandler()
 		default:
 			logger.Debug("Slave配置【%s】 %v", sn, cfg)
 			colData, err = test.CollectTest(w, meterRef)
 			if err != nil {
-				//logger.Error("采集数据失败, [%s][%s]客户端采集数据错误: %s", sn, cfg.MType, err.Error())
 				continue
 			}
 		}
-
-	}
-	logger.Info("采集数据完成【%s】", sn)
-	logger.Debug("采集数据完成【%s】 %v", sn, array)
-	return array
-}
-
-func processCollectData(colData *dataStruct.CollectData, cfg *dataStruct.DtuSlave) {
-	// 从机的配置需要保存到采集数据中,上报需要使用配置
-	colData.Slave = cfg
-	// 计算电表数据
-	logger.Debug("计算电表数据: %s", cfg.NO)
-	calc := &dataStruct.MeterCalcParam{}
-	now := time.Now()
-	today, _ := strconv.Atoi(now.Format("20060102"))
-	tms := int64(today)
-	if x, ok := data.CalcParam.Get(cfg.NO); ok {
-		calc = x.(*dataStruct.MeterCalcParam)
-		//logger.Debug("[%s][%d] 查询到电表计算参数: [%v]", cfg.NO, today, calc)
-		if calc.Time != tms {
-			calc.ClearDayEnergy()
-		}
-	} else {
-		logger.Debug("[%s][%d] 没有查询到电表计算参数。", cfg.NO, today)
-		calc.ClearDayEnergy()
-	}
-
-	// 计算电表数据
-	logger.Debug("[%d]计算前: [%v]", today, *calc)
-	calc.Time = tms
-	colData.CalcWithParam(calc)
-	logger.Debug("[%d]计算后: [%v]", today, *calc)
-	// 更新电表计算参数
-	data.CalcParam.Add(cfg.NO, calc)
-	db := meterCalcParam.NewMeterCalcParamDb()
-	if db != nil {
-		calcEt := &meterCalcParam.MeterCalcParam{
-			Id:       cfg.NO,
-			Time:     tms,
-			SumPower: calc.PowerRate.SumPower,
-			MaxPower: calc.PowerRate.MaxPower,
-			Count:    calc.PowerRate.Count,
-			Tps:      calc.TotalEnergy.Tp,
-			Tqs:      calc.TotalEnergy.Tq,
-			Fps:      calc.TotalEnergy.Fp,
-			Fqs:      calc.TotalEnergy.Fq,
-			Tpe:      calc.DayTotalEnergy.Tp,
-			Tqe:      calc.DayTotalEnergy.Tq,
-			Fpe:      calc.DayTotalEnergy.Fp,
-			Fqe:      calc.DayTotalEnergy.Fq,
-		}
-		err := db.AddOrUpdate(calcEt)
+		colData, err = collectHandler.Collect(w, meterRef)
 		if err != nil {
-			logger.Error("更新电表计算参数失败: %s", err.Error())
+			logger.Error("采集数据失败, [%s][%s]客户端采集数据错误: %s", sn, cfg.MType, err.Error())
+			continue
 		}
+		colData.Slave = cfg
+		array = append(array, colData)
 	}
+
+	logger.Info("采集数据完成【%s】", sn)
+	logger.Debug("采集数据完成【%s】 %v", sn, array)
+	return &array
 }

+ 73 - 3
SERVER/Meter_Service/service/downStreamService/proto/acrel/acrel.go → SERVER/Meter_Service/service/downStreamService/proto/acrel/adw300.go

@@ -2,14 +2,24 @@ package acrel
 
 import (
 	"MeterService/core/logger"
+	"MeterService/core/utils"
 	"MeterService/dataStruct"
+	"MeterService/service/downStreamService/proto"
 	"MeterService/service/rtuService"
+	"encoding/json"
 	"reflect"
 	"runtime"
 )
 
+type adw300Meter struct {
+}
+
+func NewAdw300MeterHandler() proto.MeterHandler {
+	return &adw300Meter{}
+}
+
 var (
-	adw300Meter = []dataStruct.ParsingDataConfig{
+	adw300Collects = []dataStruct.ParsingDataConfig{
 		{Origin: 0x0E, Amount: 56, Method: adw300A04C56},
 		{Origin: 0x12E, Amount: 12, Method: adw300A12eC12},
 		{Origin: 0x7A, Amount: 60, Method: adw300A7aC60},
@@ -19,11 +29,12 @@ var (
 	}
 )
 
-func CollectADW300(w rtuService.RtuNetPgr, ref *dataStruct.MeterRef) (*dataStruct.CollectData, error) {
+// Collect 采集数据
+func (m *adw300Meter) Collect(w rtuService.RtuNetPgr, ref *dataStruct.MeterRef) (*dataStruct.CollectData, error) {
 	colData := &dataStruct.CollectData{
 		MeterRef: ref,
 	}
-	for _, v := range adw300Meter {
+	for _, v := range adw300Collects {
 		if adu, err := w.GetHoldingRegs(v.Origin, v.Amount); err != nil {
 			logger.Error("ADW300 采集失败[%s]  ERROR:%v", runtime.FuncForPC(reflect.ValueOf(v.Method).Pointer()).Name(), err)
 			return colData, err
@@ -35,6 +46,65 @@ func CollectADW300(w rtuService.RtuNetPgr, ref *dataStruct.MeterRef) (*dataStruc
 	return colData, nil
 }
 
+// SetAddress 设置地址
+func (m *adw300Meter) SetAddress(w rtuService.RtuNetPgr, addr int) (result bool) {
+	var buf []byte
+	buf = append(buf, utils.HfWord2byte(addr)...)
+	if _, err := w.SetHoldingRegs(0, 1, buf); err != nil {
+		logger.Error("ADW300 设置地址失败  ERROR:%v", err)
+		result = false
+	} else {
+		result = true
+	}
+	return
+}
+
+// QueryRatio 查询电表变比
+func (m *adw300Meter) GetRatio(w rtuService.RtuNetPgr) (string, bool) {
+	if adu, err := w.GetHoldingRegs(0x0E, 2); err != nil {
+		logger.Error("ADW300 查询电表变比失败  ERROR:%v", err)
+		return "", false
+	} else {
+		ratio := &dataStruct.MeterRatio{}
+		index := 0
+		m := int16(uint16(adu[index])<<8 | uint16(adu[index+1]))
+		ratio.Pt = int(m)
+		index += 2
+		m = int16(uint16(adu[index])<<8 | uint16(adu[index+1]))
+		ratio.Ct = int(m)
+		str, err := json.Marshal(ratio)
+		if err != nil {
+			logger.Error("ADW300 查询电表变比失败  ERROR:%v", err)
+			return "", false
+		}
+		return string(str), true
+	}
+}
+
+// SetRatio 设置电表变比
+func (m *adw300Meter) SetRatio(w rtuService.RtuNetPgr, data string) bool {
+	ratio := &dataStruct.MeterRatio{}
+	if err := json.Unmarshal([]byte(data), ratio); err != nil {
+		logger.Error("ADW300 设置电表变比失败,变比数据解析失败  ERROR:%v", err)
+		return false
+	}
+	var buf []byte
+	{
+		k := utils.HfWord2byte(ratio.Pt)
+		buf = append(buf, k...)
+	}
+	{
+		k := utils.HfWord2byte(ratio.Ct)
+		buf = append(buf, k...)
+	}
+	if _, err := w.SetHoldingRegs(0x0E, 2, buf); err != nil {
+		logger.Error("ADW300 设置电表变比失败  ERROR:%v", err)
+		return false
+	}
+
+	return true
+}
+
 func adw300A04C56(adu []byte, s *dataStruct.CollectData) {
 	var (
 		index = 0

+ 365 - 0
SERVER/Meter_Service/service/downStreamService/proto/pmc350b/pmc350b.go

@@ -0,0 +1,365 @@
+package pmc350b
+
+import (
+	"MeterService/core/logger"
+	"MeterService/core/utils"
+	"MeterService/dataStruct"
+	"MeterService/service/downStreamService/proto"
+	"MeterService/service/rtuService"
+	"encoding/json"
+	"math"
+	"reflect"
+	"runtime"
+)
+
+type pmc350bMeter struct {
+}
+
+var (
+	pmc350bCollects = []dataStruct.ParsingDataConfig{
+		{Origin: 0, Amount: 58, Method: pmc350bUIP},
+		{Origin: 32, Amount: 8, Method: pmc350bTemperature},
+		{Origin: 500, Amount: 12, Method: pmc350bEnergy},
+		{Origin: 1400, Amount: 6, Method: pmc350bIHar},
+		{Origin: 1600, Amount: 6, Method: pmc350bUHar},
+		{Origin: 1330, Amount: 4, Method: pmc350bUIUnbalance},
+		{Origin: 1400 + 24, Amount: 54, Method: pmc350bHarmIAbc1},
+		{Origin: 1400 + 84, Amount: 54, Method: pmc350bHarmIAbc2},
+		{Origin: 1400 + 144, Amount: 54, Method: pmc350bHarmIAbc3},
+		{Origin: 1600 + 24, Amount: 54, Method: pmc350bHarmUAbc1},
+		{Origin: 1600 + 84, Amount: 54, Method: pmc350bHarmUAbc2},
+		{Origin: 1600 + 144, Amount: 54, Method: pmc350bHarmUAbc3},
+	}
+)
+
+func NewPmc350bMeterHandler() proto.MeterHandler {
+	return &pmc350bMeter{}
+}
+
+func (m *pmc350bMeter) Collect(w rtuService.RtuNetPgr, ref *dataStruct.MeterRef) (*dataStruct.CollectData, error) {
+	colData := &dataStruct.CollectData{
+		MeterRef: ref,
+		PT:       1,
+		CT:       1,
+	}
+	for _, v := range pmc350bCollects {
+		if adu, err := w.GetHoldingRegs(v.Origin, v.Amount); err != nil {
+			logger.Error("PMC-350B 采集失败[%s]  ERROR:%v", runtime.FuncForPC(reflect.ValueOf(v.Method).Pointer()).Name(), err)
+			return colData, err
+		} else {
+			logger.Debug("======》ADU:%v", adu)
+			v.Method(adu, colData)
+		}
+	}
+	return colData, nil
+}
+
+// SetAddress 设置地址
+func (m *pmc350bMeter) SetAddress(w rtuService.RtuNetPgr, addr int) (result bool) {
+	var buf []byte
+	buf = append(buf, utils.HfWord2byte(addr)...)
+	if _, err := w.SetHoldingRegs(6401, 1, buf); err != nil {
+		logger.Error("PMC-350B 设置地址失败  ERROR:%v", err)
+		result = false
+	} else {
+		result = true
+	}
+	return
+}
+
+// QueryRatio 查询电表变比
+func (m *pmc350bMeter) GetRatio(w rtuService.RtuNetPgr) (string, bool) {
+	if adu, err := w.GetHoldingRegs(6000, 10); err != nil {
+		logger.Error("PMC-350B 查询电表变比失败  ERROR:%v", err)
+		return "", false
+	} else {
+		var (
+			index = 0
+			n     int32
+		)
+		s := &dataStruct.MeterPMC350BParam{}
+		n = int32(uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3]))
+		s.PrimaryVolt = int(n)
+		index += 4
+		n = int32(uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3]))
+		s.SecondVolt = int(n)
+		index += 4
+		n = int32(uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3]))
+		s.PrimaryCurrent = int(n)
+		index += 4
+		n = int32(uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3]))
+		s.SecondCurrent = int(n)
+		index += 4
+		n = int32(uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3]))
+		s.CType = int(n)
+		index += 4
+		str, err := json.Marshal(s)
+		if err != nil {
+			logger.Error("PMC-350B 变比序列化失败  ERROR:%v", err)
+			return "", false
+		}
+		return string(str), true
+	}
+}
+
+// SetRatio 设置电表变比
+func (m *pmc350bMeter) SetRatio(w rtuService.RtuNetPgr, data string) bool {
+	ratio := &dataStruct.MeterPMC350BParam{}
+	if err := json.Unmarshal([]byte(data), ratio); err != nil {
+		logger.Error("PMC-350B 设置电表变比失败,变比数据解析失败  ERROR:%v", err)
+		return false
+	}
+	var buf []byte
+	{
+		k := utils.Word2byte(ratio.PrimaryVolt)
+		buf = append(buf, k...)
+	}
+	{
+		k := utils.Word2byte(ratio.SecondVolt)
+		buf = append(buf, k...)
+	}
+	{
+		k := utils.Word2byte(ratio.PrimaryCurrent)
+		buf = append(buf, k...)
+	}
+	{
+		k := utils.Word2byte(ratio.SecondCurrent)
+		buf = append(buf, k...)
+	}
+	{
+		k := utils.Word2byte(ratio.CType)
+		buf = append(buf, k...)
+	}
+	if _, err := w.SetHoldingRegs(6000, 10, buf); err != nil {
+		logger.Error("PMC-350B 设置电表变比失败  ERROR:%v", err)
+		return false
+	}
+
+	return true
+}
+
+func pmc350bUIP(adu []byte, s *dataStruct.CollectData) {
+	var (
+		index = 0
+		m     uint32
+	)
+	//ABC相电压
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	s.Ua = math.Float32frombits(m)
+	index += 4
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	s.Ub = math.Float32frombits(m)
+	index += 4
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	s.Uc = math.Float32frombits(m)
+	index += 4
+	//ABC电流
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	index += 4
+	s.Ia = math.Float32frombits(m)
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	index += 4
+	s.Ib = math.Float32frombits(m)
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	index += 4
+	s.Ic = math.Float32frombits(m)
+	index += 4
+	//ABC、总有功
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	index += 4
+	s.Pa = math.Float32frombits(m) * float32(0.001)
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	index += 4
+	s.Pb = math.Float32frombits(m) * float32(0.001)
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	index += 4
+	s.Pc = math.Float32frombits(m) * float32(0.001)
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	index += 4
+	s.P = math.Float32frombits(m) * float32(0.001)
+
+	//ABC、总无功
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	index += 4
+	s.Qa = math.Float32frombits(m) * float32(0.001)
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	index += 4
+	s.Qb = math.Float32frombits(m) * float32(0.001)
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	index += 4
+	s.Qc = math.Float32frombits(m) * float32(0.001)
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	index += 4
+	s.Q = math.Float32frombits(m) * float32(0.001)
+	//视在功率
+	index += 16
+	//ABC、总功率因素
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	index += 4
+	s.Pfa = math.Float32frombits(m)
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	index += 4
+	s.Pfb = math.Float32frombits(m)
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	index += 4
+	s.Pfc = math.Float32frombits(m)
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	index += 4
+	s.Pf = math.Float32frombits(m)
+	//频率
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	index += 4
+}
+
+func pmc350bTemperature(adu []byte, s *dataStruct.CollectData) {
+	var (
+		index = 0
+		m     uint32
+		f     float32
+	)
+	//温度
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	f = math.Float32frombits(m)
+	if math.IsNaN(float64(f)) {
+		s.TemperatureA = float32(0)
+	} else {
+		s.TemperatureA = f
+	}
+	index += 4
+
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	f = math.Float32frombits(m)
+	if math.IsNaN(float64(f)) {
+		s.TemperatureB = float32(0)
+	} else {
+		s.TemperatureB = f
+	}
+	index += 4
+
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	f = math.Float32frombits(m)
+	if math.IsNaN(float64(f)) {
+		s.TemperatureC = float32(0)
+	} else {
+		s.TemperatureC = f
+	}
+	index += 4
+
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	f = math.Float32frombits(m)
+	if math.IsNaN(float64(f)) {
+		s.TemperatureZ = float32(0)
+	} else {
+		s.TemperatureZ = f
+	}
+	index += 4
+
+}
+
+func pmc350bEnergy(adu []byte, s *dataStruct.CollectData) {
+	var (
+		index = 0
+		m     int32
+	)
+	m = int32(uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3]))
+	s.Tps = float32(m) * float32(0.01)
+	index += 4
+	m = int32(uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3]))
+	s.Fps = float32(m) * float32(0.01)
+	index += 4
+	index += 8
+	m = int32(uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3]))
+	s.Tqs = float32(m) * float32(0.01)
+	index += 4
+	m = int32(uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3]))
+	s.Fqs = float32(m) * float32(0.01)
+	index += 4
+}
+
+func pmc350bIHar(adu []byte, s *dataStruct.CollectData) {
+	subHarAbc(adu, &s.IaHar, &s.IbHar, &s.IcHar)
+}
+
+func pmc350bUHar(adu []byte, s *dataStruct.CollectData) {
+	subHarAbc(adu, &s.UaHar, &s.UbHar, &s.UcHar)
+}
+
+// ABC相畸变
+func subHarAbc(adu []byte, fa *float32, fb *float32, fc *float32) {
+	var (
+		index = 0
+		m     uint32
+	)
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	*fa = math.Float32frombits(m) * float32(10)
+	index += 4
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	*fb = math.Float32frombits(m) * float32(10)
+	index += 4
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	*fc = math.Float32frombits(m) * float32(10)
+	index += 4
+}
+
+func pmc350bUIUnbalance(adu []byte, s *dataStruct.CollectData) {
+	var (
+		index = 0
+		m     uint32
+	)
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	s.UUnbalance = math.Float32frombits(m)
+	index += 4
+	m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+	s.IUnbalance = math.Float32frombits(m)
+	index += 4
+}
+
+// 3-11
+func pmc350bHarmIAbc1(adu []byte, s *dataStruct.CollectData) {
+	subHarmAbc(0, adu, &s.Hia, &s.Hib, &s.Hic)
+}
+
+// 13-21
+func pmc350bHarmIAbc2(adu []byte, s *dataStruct.CollectData) {
+	subHarmAbc(5, adu, &s.Hia, &s.Hib, &s.Hic)
+}
+
+// 23-31
+func pmc350bHarmIAbc3(adu []byte, s *dataStruct.CollectData) {
+	subHarmAbc(10, adu, &s.Hia, &s.Hib, &s.Hic)
+}
+
+// 3-11
+func pmc350bHarmUAbc1(adu []byte, s *dataStruct.CollectData) {
+	subHarmAbc(0, adu, &s.Hua, &s.Hub, &s.Huc)
+}
+
+// 13-21
+func pmc350bHarmUAbc2(adu []byte, s *dataStruct.CollectData) {
+	subHarmAbc(5, adu, &s.Hua, &s.Hub, &s.Huc)
+}
+
+// 23-31
+func pmc350bHarmUAbc3(adu []byte, s *dataStruct.CollectData) {
+	subHarmAbc(10, adu, &s.Hua, &s.Hub, &s.Huc)
+}
+
+func subHarmAbc(orig int, adu []byte, fa *[15]float32, fb *[15]float32, fc *[15]float32) {
+	var (
+		index = 0
+		m     uint32
+	)
+	//ABC相3-11次谐波
+	for i := 0; i < 5; i++ {
+		m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+		index += 4
+		fa[i+orig] = math.Float32frombits(m) * float32(10)
+		m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+		index += 4
+		fb[i+orig] = math.Float32frombits(m) * float32(10)
+		m = uint32(adu[index])<<24 | uint32(adu[index+1])<<16 | uint32(adu[index+2])<<8 | uint32(adu[index+3])
+		index += 4
+		fc[i+orig] = math.Float32frombits(m) * float32(10)
+		index += 12 //跳过偶次谐波
+	}
+}

+ 77 - 6
SERVER/Meter_Service/service/downStreamService/proto/report/report.go → SERVER/Meter_Service/service/downStreamService/proto/report/ycHj212.go

@@ -2,14 +2,81 @@ package report
 
 import (
 	"MeterService/core/logger"
+	"MeterService/data"
 	"MeterService/dataStruct"
+	"MeterService/database/meterCalcParam"
+	"MeterService/service/downStreamService/proto"
 	"MeterService/service/reportService"
 	"fmt"
 	"strconv"
 	"time"
 )
 
-func YcHj212Report(dataArray []*dataStruct.CollectData, config *dataStruct.DtuConfig) {
+type ycHj212 struct {
+}
+
+func NewYcHj212ReportHandler() proto.ReportHandler {
+	return &ycHj212{}
+}
+
+func (*ycHj212) Adapter(colDataArray *[]*dataStruct.CollectData) {
+	for _, colData := range *colDataArray {
+		processData(colData)
+	}
+}
+
+func processData(colData *dataStruct.CollectData) {
+	// 从机的配置需要保存到采集数据中,上报需要使用配置
+	cfg := colData.Slave
+	// 计算电表数据
+	logger.Debug("计算电表数据: %s", cfg.NO)
+	calc := &dataStruct.MeterCalcParam{}
+	now := time.Now()
+	today, _ := strconv.Atoi(now.Format("20060102"))
+	tms := int64(today)
+	if x, ok := data.CalcParam.Get(cfg.NO); ok {
+		calc = x.(*dataStruct.MeterCalcParam)
+		//logger.Debug("[%s][%d] 查询到电表计算参数: [%v]", cfg.NO, today, calc)
+		if calc.Time != tms {
+			calc.ClearDayEnergy()
+		}
+	} else {
+		logger.Debug("[%s][%d] 没有查询到电表计算参数。", cfg.NO, today)
+		calc.ClearDayEnergy()
+	}
+
+	// 计算电表数据
+	logger.Debug("[%d]计算前: [%v]", today, *calc)
+	calc.Time = tms
+	colData.CalcWithParam(calc)
+	logger.Debug("[%d]计算后: [%v]", today, *calc)
+	// 更新电表计算参数
+	data.CalcParam.Add(cfg.NO, calc)
+	db := meterCalcParam.NewMeterCalcParamDb()
+	if db != nil {
+		calcEt := &meterCalcParam.MeterCalcParam{
+			Id:       cfg.NO,
+			Time:     tms,
+			SumPower: calc.PowerRate.SumPower,
+			MaxPower: calc.PowerRate.MaxPower,
+			Count:    calc.PowerRate.Count,
+			Tps:      calc.TotalEnergy.Tp,
+			Tqs:      calc.TotalEnergy.Tq,
+			Fps:      calc.TotalEnergy.Fp,
+			Fqs:      calc.TotalEnergy.Fq,
+			Tpe:      calc.DayTotalEnergy.Tp,
+			Tqe:      calc.DayTotalEnergy.Tq,
+			Fpe:      calc.DayTotalEnergy.Fp,
+			Fqe:      calc.DayTotalEnergy.Fq,
+		}
+		err := db.AddOrUpdate(calcEt)
+		if err != nil {
+			logger.Error("更新电表计算参数失败: %s", err.Error())
+		}
+	}
+}
+
+func (*ycHj212) Report(dataArray *[]*dataStruct.CollectData, config *dataStruct.DtuConfig) {
 	bs := &dataStruct.HJBaseInfo{
 		Host: config.IP,
 		ST:   config.St,
@@ -18,6 +85,7 @@ func YcHj212Report(dataArray []*dataStruct.CollectData, config *dataStruct.DtuCo
 		MN:   config.Mn,
 		Port: strconv.Itoa(config.Port),
 	}
+
 	if strArray, ok := packYcHj212(bs, dataArray); ok {
 		for _, str := range strArray {
 
@@ -31,14 +99,14 @@ func YcHj212Report(dataArray []*dataStruct.CollectData, config *dataStruct.DtuCo
 	}
 }
 
-func packYcHj212(bs *dataStruct.HJBaseInfo, dataArray []*dataStruct.CollectData) ([]string, bool) {
+func packYcHj212(bs *dataStruct.HJBaseInfo, dataArray *[]*dataStruct.CollectData) ([]string, bool) {
 	array := make([]string, 0)
-	if len(dataArray) == 0 {
+	if len(*dataArray) == 0 {
 		return array, false
 	}
 	now := time.Now()
 	nt := fmt.Sprintf("%04d%02d%02d%02d%02d00", now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute())
-	for _, d := range dataArray {
+	for _, d := range *dataArray {
 		body := fmt.Sprintf("%s=%s", d.Slave.GetBmYzKey("p"), getBmYzFloatValue(d.P)) +
 			fmt.Sprintf("&%s=%s", d.Slave.GetBmYzKey("pa"), getBmYzFloatValue(d.Pa)) +
 			fmt.Sprintf("&%s=%s", d.Slave.GetBmYzKey("pb"), getBmYzFloatValue(d.Pb)) +
@@ -91,8 +159,11 @@ func packYcHj212(bs *dataStruct.HJBaseInfo, dataArray []*dataStruct.CollectData)
 			fmt.Sprintf("&%s=%s", d.Slave.GetBmYzKey("hia"), packYcHj212Hx(d.Hia, d.HarIa, d.BaseIa, "basei")) +
 			fmt.Sprintf("&%s=%s", d.Slave.GetBmYzKey("hib"), packYcHj212Hx(d.Hib, d.HarIb, d.BaseIb, "basei")) +
 			fmt.Sprintf("&%s=%s", d.Slave.GetBmYzKey("hic"), packYcHj212Hx(d.Hic, d.HarIc, d.BaseIc, "basei"))
-
-		str := fmt.Sprintf("st=%s;cn=%s;datatime=%s;cphh=&&tid=%s&%s&", bs.ST, bs.CN, nt, d.Slave.NO, body)
+		cn := bs.CN
+		if d.Slave.Cn != "" {
+			cn = d.Slave.Cn
+		}
+		str := fmt.Sprintf("st=%s;cn=%s;datatime=%s;cphh=&&tid=%s&%s&", bs.ST, cn, nt, d.Slave.NO, body)
 		crc16 := calCRC16HJ212([]byte(str))
 		str1 := fmt.Sprintf("##00%04d", len(str)) + str + fmt.Sprintf("%04X", crc16) + "\r\n"
 		array = append(array, str1)

+ 20 - 0
SERVER/Meter_Service/service/downStreamService/proto/type.go

@@ -0,0 +1,20 @@
+package proto
+
+import (
+	"MeterService/dataStruct"
+	"MeterService/service/rtuService"
+)
+
+// MeterHandler 电表处理接口
+type MeterHandler interface {
+	Collect(w rtuService.RtuNetPgr, ref *dataStruct.MeterRef) (*dataStruct.CollectData, error)
+	SetAddress(w rtuService.RtuNetPgr, addr int) (result bool)
+	GetRatio(w rtuService.RtuNetPgr) (string, bool)
+	SetRatio(w rtuService.RtuNetPgr, ratio string) bool
+}
+
+// ReportHandler 上报处理接口
+type ReportHandler interface {
+	Adapter(dataArray *[]*dataStruct.CollectData)
+	Report(dataArray *[]*dataStruct.CollectData, config *dataStruct.DtuConfig)
+}

+ 10 - 3
SERVER/Meter_Service/service/downStreamService/report.go

@@ -2,13 +2,20 @@ package downStreamService
 
 import (
 	"MeterService/dataStruct"
+	"MeterService/meter"
+	"MeterService/service/downStreamService/proto"
 	"MeterService/service/downStreamService/proto/report"
 )
 
-func reportData(dataArray []*dataStruct.CollectData, config *dataStruct.DtuConfig) {
+func reportData(dataArray *[]*dataStruct.CollectData, config *dataStruct.DtuConfig) {
+	var reportHandler proto.ReportHandler
 	switch config.Protocol {
-	case "YC-HJ212":
-		go report.YcHj212Report(dataArray, config)
+	case meter.PlatYcHj212:
+		reportHandler = report.NewYcHj212ReportHandler()
 	default:
 	}
+	go func(arr *[]*dataStruct.CollectData, cfg *dataStruct.DtuConfig) {
+		reportHandler.Adapter(arr)
+		reportHandler.Report(arr, cfg)
+	}(dataArray, config)
 }

+ 1 - 1
SERVER/Meter_Service/service/downStreamService/service.go

@@ -173,7 +173,7 @@ func collectAndReport(nowTime time.Time, lastMinute int) int {
 		for dtuSn, client := range onlineDtu {
 			if minute%client.Config.Secs == 0 {
 				// 采集上报数据
-				if dataArray := collectData(dtuSn, client.Config); len(dataArray) > 0 {
+				if dataArray := collectData(dtuSn, client.Config); len(*dataArray) > 0 {
 					logger.Debug("开始上报平台:%s", dtuSn)
 					reportData(dataArray, client.Config)
 				}

+ 30 - 7
SERVER/Meter_Service/service/rtuService/rtuTcp.go

@@ -18,9 +18,10 @@ type rtuNetPackager struct {
 
 type RtuNetPgr interface {
 	GetHoldingRegs(address, quantity uint16) (adu []byte, err error) // 获取寄存器值
-	SetAddress(Id int)                                               // 设置电表地址
-	SetSerialNumber(sn string)                                       // 设置电表序列号
-	SetClientState(sta *dataStruct.ClientState)                      // 设置客户端
+	SetHoldingRegs(address, quantity uint16, value []byte) (adu []byte, err error)
+	SetAddress(Id int)                          // 设置电表地址
+	SetSerialNumber(sn string)                  // 设置电表序列号
+	SetClientState(sta *dataStruct.ClientState) // 设置客户端
 }
 
 func NewRtuNetPgr(Id byte) RtuNetPgr {
@@ -48,8 +49,8 @@ func (mb *rtuNetPackager) SetClientState(sta *dataStruct.ClientState) {
 func (mb *rtuNetPackager) GetHoldingRegs(address, quantity uint16) (adu []byte, err error) {
 	var result []byte
 	if mb.Sta == nil {
-		err = fmt.Errorf("客户端不存在")
-		logger.Error("发送失败,%s", err.Error())
+		err = fmt.Errorf("读命令,客户端不存在")
+		logger.Error("读命令发送失败,%s", err.Error())
 		return
 	}
 	result, err = mb.Clt.PackReadHoldingRegisters(address, quantity)
@@ -60,12 +61,34 @@ func (mb *rtuNetPackager) GetHoldingRegs(address, quantity uint16) (adu []byte,
 	res, bok := tcpserver.SendTo(mb.Sta.FD, result)
 	if !bok {
 		if utils.ConnTimeoutJudge(mb.Sta.Times) {
-			logger.Error("发送失败,连接超时")
+			logger.Error("读命令发送失败,连接超时")
 		}
-		err = fmt.Errorf("发送失败")
+		err = fmt.Errorf("读命令发送失败")
 		return
 	}
 	adu, err = mb.Clt.DePackRegisters(res)
 
 	return
 }
+
+func (mb *rtuNetPackager) SetHoldingRegs(address, quantity uint16, value []byte) (adu []byte, err error) {
+	var result []byte
+	if mb.Sta == nil {
+		err = fmt.Errorf("写命令客户端不存在")
+		return
+	}
+	result, err = mb.Clt.PackWriteMultipleRegisters(address, quantity, value)
+	if err != nil {
+		return
+	}
+	res, bok := tcpserver.SendTo(mb.Sta.FD, result)
+	if !bok {
+		if utils.ConnTimeoutJudge(mb.Sta.Times) {
+			logger.Error("写命令发送失败,连接超时")
+		}
+		err = fmt.Errorf("写命令发送失败")
+		return
+	}
+	adu, err = mb.Clt.DePackSetRegs(res)
+	return
+}

BIN
SERVER/Meter_Service/vbdsm_meter