Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support BACnetIP device #161

Merged
merged 3 commits into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 205 additions & 0 deletions device/generic_bacnetip_device.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
package device

import (
"context"
"encoding/json"
"errors"
"fmt"
"github.com/BeatTime/bacnet"
"github.com/BeatTime/bacnet/btypes"
"github.com/hootrhino/rulex/glogger"
"github.com/hootrhino/rulex/typex"
"github.com/hootrhino/rulex/utils"
"time"
)

type bacnetIpCommonConfig struct {
Ip string `json:"ip,omitempty" title:"bacnet设备ip"`
Port int `json:"port,omitempty" title:"bacnet端口,通常是47808"`
LocalPort int `json:"localPort" title:"本地监听端口,填0表示默认47808(有的模拟器必须本地监听47808才能正常交互)"`
Interval int `json:"interval" title:"采集间隔,单位秒"`
}

type bacnetIpNodeConfig struct {
IsMstp int `json:"isMstp,omitempty" title:"是否为mstp设备,若是则设备id和子网号必须填写"`
DeviceId int `json:"deviceId,omitempty" title:"设备id"`
Subnet int `json:"subnet,omitempty" title:"子网号"`
Tag string `json:"tag" validate:"required" title:"数据Tag"`
Type int `json:"type,omitempty" title:"object类型"`
Id int `json:"id,omitempty" title:"object的id"`

property btypes.PropertyData `json:"ignore"`
}

type BacnetIpConfig struct {
CommonConfig bacnetIpCommonConfig `json:"commonConfig"`
NodeConfig []bacnetIpNodeConfig `json:"nodeConfig"`
}

type GenericBacnetIpDevice struct {
typex.XStatus
status typex.DeviceState
RuleEngine typex.RuleX
bacnetIpConfig BacnetIpConfig
devId string

// Bacnet
bacnetClient bacnet.Client
remoteDev btypes.Device
}

func NewGenericBacnetIpDevice(e typex.RuleX) typex.XDevice {
g := new(GenericBacnetIpDevice)
g.RuleEngine = e
g.bacnetIpConfig = BacnetIpConfig{
CommonConfig: bacnetIpCommonConfig{},
NodeConfig: make([]bacnetIpNodeConfig, 0),
}
return g
}

func (dev *GenericBacnetIpDevice) Init(devId string, configMap map[string]interface{}) error {
dev.devId = devId
err := utils.BindSourceConfig(configMap, &dev.bacnetIpConfig)
if err != nil {
return err
}
return nil
}

func (dev *GenericBacnetIpDevice) Start(cctx typex.CCTX) error {
// 创建一个bacnetip的本地网络
client, err := bacnet.NewClient(&bacnet.ClientBuilder{
Ip: "0.0.0.0",
Port: dev.bacnetIpConfig.CommonConfig.LocalPort,
SubnetCIDR: 10, // 随便填一个,主要为了能够创建Client
})
if err != nil {
return err
}
dev.bacnetClient = client
go client.ClientRun()

// 将nodeConfig对应的配置信息
for idx, v := range dev.bacnetIpConfig.NodeConfig {
tmp := btypes.PropertyData{
Object: btypes.Object{
ID: btypes.ObjectID{
Type: btypes.ObjectType(v.Type),
Instance: btypes.ObjectInstance(v.Id),
},
Properties: []btypes.Property{
{
Type: btypes.PropPresentValue, // Present value
ArrayIndex: btypes.ArrayAll,
},
},
},
}
dev.bacnetIpConfig.NodeConfig[idx].property = tmp
}

mac := make([]byte, 6)
fmt.Sscanf(dev.bacnetIpConfig.CommonConfig.Ip, "%d.%d.%d.%d", &mac[0], &mac[1], &mac[2], &mac[3])
port := uint16(dev.bacnetIpConfig.CommonConfig.Port)
mac[4] = byte(port >> 8)
mac[5] = byte(port & 0x00FF)
dev.remoteDev = btypes.Device{
Addr: btypes.Address{
MacLen: 6,
Mac: mac,
},
}

go func(ctx context.Context) {
interval := dev.bacnetIpConfig.CommonConfig.Interval
ticker := time.NewTicker(time.Duration(interval) * time.Second)
for {
select {
case <-ctx.Done():
{
ticker.Stop()
return
}
default:
{
}
}

read, err2 := dev.read()
if err2 != nil {
glogger.GLogger.Error(err2)
} else {
dev.RuleEngine.WorkDevice(dev.Details(), string(read))
}
<-ticker.C
}
}(cctx.Ctx)

dev.status = typex.DEV_UP
return nil
}

func (dev *GenericBacnetIpDevice) OnRead(cmd []byte, data []byte) (int, error) {
read, err := dev.read()
if err != nil {
return 0, err
}
len := copy(data, read)
return len, nil
}

func (dev *GenericBacnetIpDevice) read() ([]byte, error) {
retMap := map[string]string{}
for _, v := range dev.bacnetIpConfig.NodeConfig {
property, err := dev.bacnetClient.ReadProperty(dev.remoteDev, v.property)
if err != nil {
glogger.GLogger.Error("read failed. tag = %v, err=%v", v.Tag, err)
continue
}
value := fmt.Sprintf("%v", property.Object.Properties[0].Data)
retMap[v.Tag] = value
}
bytes, _ := json.Marshal(retMap)
glogger.GLogger.Debugf("%v", retMap)
return bytes, nil
}

func (dev *GenericBacnetIpDevice) OnWrite(cmd []byte, data []byte) (int, error) {
//TODO implement me
return 0, errors.New("not Support")
}

func (dev *GenericBacnetIpDevice) OnCtrl(cmd []byte, args []byte) ([]byte, error) {
return nil, errors.New("not Support")
}

func (dev *GenericBacnetIpDevice) Status() typex.DeviceState {
return dev.status
}

func (dev *GenericBacnetIpDevice) Stop() {
if dev.bacnetClient != nil {
dev.bacnetClient.Close()
}
}

func (dev *GenericBacnetIpDevice) Property() []typex.DeviceProperty {
return []typex.DeviceProperty{}
}

func (dev *GenericBacnetIpDevice) Details() *typex.Device {
return dev.RuleEngine.GetDevice(dev.PointId)
}

func (dev *GenericBacnetIpDevice) SetState(state typex.DeviceState) {
dev.status = state
}

func (dev *GenericBacnetIpDevice) Driver() typex.XExternalDriver {
return nil
}

func (dev *GenericBacnetIpDevice) OnDCACall(UUID string, Command string, Args interface{}) typex.DCAResult {
return typex.DCAResult{}
}
6 changes: 6 additions & 0 deletions engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,12 @@ func (e *RuleEngine) InitDeviceTypeManager() error {
NewDevice: device.NewAISDevice,
},
)
e.DeviceTypeManager.Register(typex.GENERIC_BACNET_IP,
&typex.XConfig{
Engine: e,
NewDevice: device.NewGenericBacnetIpDevice,
},
)
return nil
}

Expand Down
9 changes: 5 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/hootrhino/rulex
go 1.18

require (
github.com/BeatTime/bacnet v0.2.0-gary
github.com/DrmagicE/gmqtt v0.5.0
github.com/Kowiste/ProfinetServer v0.0.0-20200929093941-9c422ae1f008
github.com/adrianmo/go-nmea v1.8.0
Expand Down Expand Up @@ -37,7 +38,7 @@ require (
github.com/rs/zerolog v1.28.0
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/shirou/gopsutil/v3 v3.23.5
github.com/sirupsen/logrus v1.9.2
github.com/sirupsen/logrus v1.9.3
github.com/suapapa/go_eddystone v1.3.1
github.com/tbrandon/mbserver v0.0.0-20211210035124-daf3c8c4269f
github.com/thinkgos/go-iecp5 v1.2.1
Expand All @@ -47,11 +48,12 @@ require (
github.com/wwhai/ntp v0.3.0
github.com/wwhai/tarmserial v1.0.0
github.com/wwhai/tinycache v0.0.0-20191004192108-46f407853014
github.com/xuri/excelize/v2 v2.7.1
go.bug.st/serial v1.5.0
go.mongodb.org/mongo-driver v1.11.6
go.uber.org/zap v1.15.0
golang.org/x/crypto v0.9.0
golang.org/x/sys v0.8.0
golang.org/x/sys v0.10.0
google.golang.org/grpc v1.55.0
google.golang.org/protobuf v1.30.0
gopkg.in/ini.v1 v1.67.0
Expand All @@ -66,7 +68,6 @@ require (
github.com/richardlehane/mscfb v1.0.4 // indirect
github.com/richardlehane/msoleps v1.0.3 // indirect
github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 // indirect
github.com/xuri/excelize/v2 v2.7.1 // indirect
github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect
)

Expand Down Expand Up @@ -144,7 +145,7 @@ require (
golang.org/x/arch v0.3.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sync v0.2.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/genproto v0.0.0-20230525234025-438c736192d0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a // indirect
Expand Down
17 changes: 12 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,8 @@ cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoIS
cloud.google.com/go/workflows v1.8.0/go.mod h1:ysGhmEajwZxGn1OhGOGKsTXc5PyxOc0vfKf5Af+to4M=
cloud.google.com/go/workflows v1.9.0/go.mod h1:ZGkj1aFIOd9c8Gerkjjq7OW7I5+l6cSvT3ujaO/WwSA=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BeatTime/bacnet v0.2.0-gary h1:2+ZMrgzmrRovVXBCQ+djXIWUQOySfyfm+hi0kD/0bXI=
github.com/BeatTime/bacnet v0.2.0-gary/go.mod h1:TnVpYMUX0Xgt5/VfJ2aT30QK2QM5H1+ZeXAVauKkjvA=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
Expand Down Expand Up @@ -458,8 +460,8 @@ github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
Expand Down Expand Up @@ -859,8 +861,10 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y=
github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
Expand Down Expand Up @@ -1014,6 +1018,7 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI=
golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
Expand Down Expand Up @@ -1228,8 +1233,9 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
Expand All @@ -1248,8 +1254,9 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
Expand Down
4 changes: 4 additions & 0 deletions plugin/http_server/http_api_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,10 @@ func (hs *HttpApiServer) LoadRoute() {
//
hs.ginEngine.GET(url("uarts"), hs.addRoute(GetUarts))
//
// 网络适配器列表
//
hs.ginEngine.GET(url("netInterfaces"), hs.addRoute(GetNetInterfaces))
//
// 获取服务启动时间
//
hs.ginEngine.GET(url("startedAt"), hs.addRoute(StartedAt))
Expand Down
8 changes: 8 additions & 0 deletions plugin/http_server/model/dto.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package model

// NetInterfaceInfo 网络适配器信息
type NetInterfaceInfo struct {
Name string `json:"name,omitempty"`
Mac string `json:"mac,omitempty"`
Addr string `json:"addr,omitempty"`
}
Loading
Loading