|
@@ -2,6 +2,7 @@ package drviers
|
|
|
|
|
|
import (
|
|
|
"encoding/hex"
|
|
|
+ "fmt"
|
|
|
"reflect"
|
|
|
"strconv"
|
|
|
"strings"
|
|
@@ -33,29 +34,33 @@ type AmmeterModel struct {
|
|
|
|
|
|
type Ammeter struct {
|
|
|
AmmeterModel
|
|
|
- timestamp int32
|
|
|
+ TsSample int64
|
|
|
TotalEnergy float64
|
|
|
- TransDeno float64 ` gorm:"-"`
|
|
|
- TransDiv float64 ` gorm:"-"`
|
|
|
+ TransDeno float64 `gorm:"-"`
|
|
|
+ TransDiv float64 `gorm:"-"`
|
|
|
+ DBStatus int `json:"-"`
|
|
|
}
|
|
|
|
|
|
type AmMeterHub struct {
|
|
|
baseDevice
|
|
|
- DutSn string
|
|
|
- Protocol string
|
|
|
- chnExit chan bool
|
|
|
- loopserver bool
|
|
|
- sampleTmr *time.Timer
|
|
|
- amList map[string]*Ammeter
|
|
|
- persitList map[string]*Ammeter
|
|
|
- tmrPersist *time.Timer
|
|
|
- queryIdx int
|
|
|
+ DutSn string
|
|
|
+ DevCompCode string ` gorm:"-"`
|
|
|
+ Protocol string
|
|
|
+ chnExit chan bool
|
|
|
+ loopserver bool
|
|
|
+ sampleTmr *time.Timer
|
|
|
+ amList map[string]*Ammeter
|
|
|
+ persitList map[string]*Ammeter
|
|
|
+ tmrPersist *time.Timer
|
|
|
+
|
|
|
+ queryIdx int
|
|
|
}
|
|
|
|
|
|
func (dev *AmMeterHub) Close() error {
|
|
|
dev.sampleTmr.Stop()
|
|
|
dev.loopserver = false
|
|
|
dev.chnExit <- true
|
|
|
+ dev.baseDevice.Close()
|
|
|
return nil
|
|
|
}
|
|
|
|
|
@@ -63,15 +68,31 @@ func (dev *AmMeterHub) OnAttach(chn bus.IChannel) {
|
|
|
log.Info(dev.DutSn, " Attached!")
|
|
|
chn.SetTimeout(DEF_TCP_READ_TIMEOUT)
|
|
|
dev.sampleTmr.Reset(DEF_SAMPLE_PEER_DURATION)
|
|
|
+ dev.baseDevice.OnAttach(chn)
|
|
|
}
|
|
|
|
|
|
func (dev *AmMeterHub) OnDetach(chn bus.IChannel) {
|
|
|
log.Info(dev.DutSn, " Detached!")
|
|
|
dev.sampleTmr.Stop()
|
|
|
+ dev.baseDevice.OnDetach(chn)
|
|
|
}
|
|
|
|
|
|
func (dev *AmMeterHub) ChannelDispatch(stream []byte, args interface{}) bus.ChnDispResult {
|
|
|
- if len(stream) != 5 {
|
|
|
+ if len(stream) > 8 {
|
|
|
+ if stream[0] == 0x68 && stream[7] == 0x68 && stream[8] == 0x93 {
|
|
|
+ devname := ""
|
|
|
+ mret := dev.Route[1].iproto.ParsePacket(stream, &devname)
|
|
|
+ if mret != nil && devname == dev.DeviceName {
|
|
|
+ return bus.DispatchSingle
|
|
|
+ }
|
|
|
+ // for i := 0; i < 6; i++ {
|
|
|
+ // if stream[i+1] != stream[i+10] {
|
|
|
+ // return bus.DispatchNone
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ // log.Infof("MOUNT meter:0000[%x]", stream[1:7])
|
|
|
+ // return bus.DispatchSingle
|
|
|
+ }
|
|
|
return bus.DispatchNone
|
|
|
}
|
|
|
if ret := dev.baseDevice.ChannelDispatch(stream, args); ret != bus.DispatchNone {
|
|
@@ -129,11 +150,16 @@ func (dev *AmMeterHub) AdjustTelemetry(mval interface{}, devname string) {
|
|
|
|
|
|
if val, has := vlist["TotalActivePower"]; has {
|
|
|
diff := val.(float64) - am.TotalEnergy
|
|
|
+ if am.DBStatus == 0 { //数据库清0
|
|
|
+ diff = 0
|
|
|
+ am.DBStatus = 1
|
|
|
+ }
|
|
|
am.TotalEnergy = val.(float64)
|
|
|
vlist["ActivePowerIncrement"] = diff
|
|
|
if len(dev.persitList) == 0 {
|
|
|
dev.tmrPersist.Reset(POSTPONE_PERSIST_TIME)
|
|
|
}
|
|
|
+
|
|
|
dev.persitList[am.DevName] = am
|
|
|
}
|
|
|
}
|
|
@@ -150,15 +176,18 @@ func (dev *AmMeterHub) Run() error {
|
|
|
case msg := <-dev.Route[1].router[0]:
|
|
|
if reflect.TypeOf(msg).Kind() == reflect.Slice {
|
|
|
b := msg.([]byte)
|
|
|
- log.Info(hex.EncodeToString(b))
|
|
|
+ log.Info("[", dev.DutSn, "]:", hex.EncodeToString(b))
|
|
|
devname := "" //pam.DevName
|
|
|
mret := dev.Route[1].iproto.ParsePacket(b, &devname)
|
|
|
- if mret != nil && devname != "" {
|
|
|
+ if mret != nil && reflect.TypeOf(mret).Kind() == reflect.Map && devname != "" {
|
|
|
log.Info(devname, mret)
|
|
|
- devname = "AM10-" + devname + dev.DutSn[:4]
|
|
|
+ devname = "AM10-" + devname + dev.DevCompCode[:4]
|
|
|
dev.AdjustTelemetry(mret, devname)
|
|
|
telemetry := dev.Route[0].iproto.PackageCmd(devname, mret)
|
|
|
dev.Route[0].ibus.Send(dev.Route[0].iChn, telemetry)
|
|
|
+ if meter, has := dev.amList[devname]; has {
|
|
|
+ meter.TsSample = time.Now().Unix()
|
|
|
+ }
|
|
|
dev.SchedulNextSample(tmrTxTimout)
|
|
|
}
|
|
|
}
|
|
@@ -170,13 +199,15 @@ func (dev *AmMeterHub) Run() error {
|
|
|
dev.loopserver = false
|
|
|
case <-dev.tmrPersist.C:
|
|
|
for k, am := range dev.persitList {
|
|
|
+ if am.DBStatus == 0 {
|
|
|
+
|
|
|
+ }
|
|
|
config.GetDB().Save(am)
|
|
|
delete(dev.persitList, k)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
return nil
|
|
|
-
|
|
|
}
|
|
|
|
|
|
func DutchanDispatch(rxin interface{}, param interface{}) interface{} {
|
|
@@ -189,7 +220,6 @@ func DutchanDispatch(rxin interface{}, param interface{}) interface{} {
|
|
|
}
|
|
|
|
|
|
func (dev *AmMeterHub) Open(param ...interface{}) error {
|
|
|
-
|
|
|
if dev.DutSn != "" {
|
|
|
dev.SetRoute(dev, dev.Protocol, "dtuFtpServer", dev.DutSn, 0)
|
|
|
}
|
|
@@ -207,6 +237,23 @@ func (dev *AmMeterHub) GetDevice(devname string) interface{} {
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
+func (dev *AmMeterHub) ListDevices() interface{} {
|
|
|
+ mdev := make(map[string]interface{})
|
|
|
+ mdev["State"] = dev.Status
|
|
|
+ dinfo := make(map[string]interface{})
|
|
|
+ for sname, subdev := range dev.amList {
|
|
|
+
|
|
|
+ meterval := make(map[string]string)
|
|
|
+ meterval["TotalEnergy"] = fmt.Sprintf("%f", subdev.TotalEnergy)
|
|
|
+ if subdev.TsSample != 0 {
|
|
|
+ meterval["TsSample"] = time.Unix(subdev.TsSample, 0).Format("2006-01-02 15:04:05")
|
|
|
+ }
|
|
|
+ dinfo[sname] = meterval
|
|
|
+ }
|
|
|
+ mdev["Sub Meters"] = dinfo
|
|
|
+ return mdev
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
[{"code":"26462285","devName":"SAIR10-0000000026462285","gwDevId":"1ec2d8421b2ed30bf52b38d8579115b","id":"1ec2d84cc494690bf52b38d8579115b","protocol":"HJ212"},
|
|
|
{"code":"61748803","devName":"SAIR10-0000000061748803","gwDevId":"1ec2d8421b2ed30bf52b38d8579115b","id":"1ec2d84eb428160bf52b38d8579115b","protocol":"HJ212"}]
|
|
@@ -225,40 +272,55 @@ func (drv *AmmeterDrv) ParseTransRatio(dev *Ammeter) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func (drv *AmmeterDrv) CreateDevice(model interface{}) (int, []IDevice) {
|
|
|
+func (drv *AmmeterDrv) CreateDevice(model interface{}, filterGwId string) (int, []IDevice) {
|
|
|
if model != nil {
|
|
|
models := model.(*[]AmmeterModel)
|
|
|
for _, m := range *models {
|
|
|
var hub IDevice = nil
|
|
|
var has bool
|
|
|
+ if m.GwDevId != filterGwId {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if len(m.Code) < 4 || len(m.Address) < 8 {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ devCompID := m.DutSn
|
|
|
+ if m.DutSn == "" {
|
|
|
+ m.DutSn = m.Code + m.Address
|
|
|
+ devCompID = "0000"
|
|
|
+ }
|
|
|
if hub, has = drv.DevList[m.DutSn]; !has {
|
|
|
hub = &AmMeterHub{
|
|
|
- DutSn: m.DutSn,
|
|
|
- Protocol: m.Protocol,
|
|
|
- chnExit: make(chan bool),
|
|
|
- loopserver: false,
|
|
|
- sampleTmr: nil,
|
|
|
- amList: make(map[string]*Ammeter),
|
|
|
- persitList: make(map[string]*Ammeter),
|
|
|
- queryIdx: 0,
|
|
|
+ DutSn: m.DutSn,
|
|
|
+ Protocol: m.Protocol,
|
|
|
+ chnExit: make(chan bool),
|
|
|
+ loopserver: false,
|
|
|
+ sampleTmr: nil,
|
|
|
+ amList: make(map[string]*Ammeter),
|
|
|
+ persitList: make(map[string]*Ammeter),
|
|
|
+ queryIdx: 0,
|
|
|
+ DevCompCode: devCompID,
|
|
|
}
|
|
|
hub.Probe(m.DutSn, drv)
|
|
|
drv.DevList[m.DutSn] = hub
|
|
|
}
|
|
|
|
|
|
- dev := &Ammeter{
|
|
|
- TotalEnergy: 0,
|
|
|
- timestamp: 0,
|
|
|
- TransDiv: 1,
|
|
|
- TransDeno: 1,
|
|
|
+ if _, has := hub.(*AmMeterHub).amList[m.DevName]; !has {
|
|
|
+ dev := &Ammeter{
|
|
|
+ TotalEnergy: 0,
|
|
|
+ TsSample: 0,
|
|
|
+ TransDiv: 1,
|
|
|
+ TransDeno: 1,
|
|
|
+ DBStatus: 0,
|
|
|
+ }
|
|
|
+ config.GetDB().Find(dev, "dev_name='"+m.DevName+"'")
|
|
|
+ dev.AmmeterModel = m
|
|
|
+ drv.ParseTransRatio(dev)
|
|
|
+ hub.(*AmMeterHub).amList[dev.DevName] = dev
|
|
|
}
|
|
|
- config.GetDB().Find(dev, "dev_name='"+m.DevName+"'")
|
|
|
- dev.AmmeterModel = m
|
|
|
- drv.ParseTransRatio(dev)
|
|
|
- hub.(*AmMeterHub).amList[dev.DevName] = dev
|
|
|
}
|
|
|
}
|
|
|
- return drv.baseDriver.CreateDevice(model)
|
|
|
+ return drv.baseDriver.CreateDevice(model, filterGwId)
|
|
|
}
|
|
|
|
|
|
func (drv *AmmeterDrv) GetModel() interface{} {
|