1
0
mirror of https://github.com/mainflux/mainflux.git synced 2025-05-12 19:29:30 +08:00
Dušan Borovčanin ea3a891c91
MF-1190 - Add pkg for library packages (#1191)
* Move messaging to pkg

Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com>

* Move errors to pkg

Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com>

* Move Transformers to pkg

Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com>

* Move SDK to pkg

Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com>

* Remove Transformers from root

Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com>

* Fix make proto

Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com>

* Add copyrights header

Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com>

* Fix CI

Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com>

* Move Auth client to pkg

Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com>

* Fix dependencies

Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com>

* Update dependencies and vendors

Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com>

* Fix CI

Signed-off-by: dusanb94 <dusan.borovcanin@mainflux.com>
2020-06-03 15:16:19 +02:00

229 lines
5.0 KiB
Go

// Copyright (c) Mainflux
// SPDX-License-Identifier: Apache-2.0
package gopcua
import (
"context"
opcuaGopcua "github.com/gopcua/opcua"
"github.com/gopcua/opcua/id"
uaGopcua "github.com/gopcua/opcua/ua"
"github.com/mainflux/mainflux/logger"
"github.com/mainflux/mainflux/opcua"
"github.com/mainflux/mainflux/pkg/errors"
)
const maxChildrens = 4 // max browsing node children level
// NodeDef represents the node browser responnse
type NodeDef struct {
NodeID *uaGopcua.NodeID
NodeClass uaGopcua.NodeClass
BrowseName string
Description string
AccessLevel uaGopcua.AccessLevelType
Path string
DataType string
Writable bool
Unit string
Scale string
Min string
Max string
}
var _ opcua.Browser = (*browser)(nil)
type browser struct {
ctx context.Context
logger logger.Logger
}
// NewBrowser returns new OPC-UA browser instance.
func NewBrowser(ctx context.Context, log logger.Logger) opcua.Browser {
return browser{
ctx: ctx,
logger: log,
}
}
func (c browser) Browse(serverURI, nodeID string) ([]opcua.BrowsedNode, error) {
opts := []opcuaGopcua.Option{
opcuaGopcua.SecurityMode(uaGopcua.MessageSecurityModeNone),
}
oc := opcuaGopcua.NewClient(serverURI, opts...)
if err := oc.Connect(c.ctx); err != nil {
return nil, errors.Wrap(errFailedConn, err)
}
defer oc.Close()
nodeList, err := browse(oc, nodeID, "", 0)
if err != nil {
return nil, err
}
nodes := []opcua.BrowsedNode{}
for _, s := range nodeList {
node := opcua.BrowsedNode{
NodeID: s.NodeID.String(),
DataType: s.DataType,
Description: s.Description,
Unit: s.Unit,
Scale: s.Scale,
BrowseName: s.BrowseName,
}
nodes = append(nodes, node)
}
return nodes, nil
}
func browse(oc *opcuaGopcua.Client, nodeID, path string, level int) ([]NodeDef, error) {
if level > maxChildrens {
return nil, nil
}
nid, err := uaGopcua.ParseNodeID(nodeID)
if err != nil {
return []NodeDef{}, err
}
n := oc.Node(nid)
attrs, err := n.Attributes(
uaGopcua.AttributeIDNodeClass,
uaGopcua.AttributeIDBrowseName,
uaGopcua.AttributeIDDescription,
uaGopcua.AttributeIDAccessLevel,
uaGopcua.AttributeIDDataType,
)
if err != nil {
return nil, err
}
var def = NodeDef{
NodeID: n.ID,
}
switch err := attrs[0].Status; err {
case uaGopcua.StatusOK:
def.NodeClass = uaGopcua.NodeClass(attrs[0].Value.Int())
default:
return nil, err
}
switch err := attrs[1].Status; err {
case uaGopcua.StatusOK:
def.BrowseName = attrs[1].Value.String()
default:
return nil, err
}
switch err := attrs[2].Status; err {
case uaGopcua.StatusOK:
def.Description = attrs[2].Value.String()
case uaGopcua.StatusBadAttributeIDInvalid:
// ignore
default:
return nil, err
}
switch err := attrs[3].Status; err {
case uaGopcua.StatusOK:
def.AccessLevel = uaGopcua.AccessLevelType(attrs[3].Value.Int())
def.Writable = def.AccessLevel&uaGopcua.AccessLevelTypeCurrentWrite == uaGopcua.AccessLevelTypeCurrentWrite
case uaGopcua.StatusBadAttributeIDInvalid:
// ignore
default:
return nil, err
}
switch err := attrs[4].Status; err {
case uaGopcua.StatusOK:
switch v := attrs[4].Value.NodeID().IntID(); v {
case id.DateTime:
def.DataType = "time.Time"
case id.Boolean:
def.DataType = "bool"
case id.SByte:
def.DataType = "int8"
case id.Int16:
def.DataType = "int16"
case id.Int32:
def.DataType = "int32"
case id.Byte:
def.DataType = "byte"
case id.UInt16:
def.DataType = "uint16"
case id.UInt32:
def.DataType = "uint32"
case id.UtcTime:
def.DataType = "time.Time"
case id.String:
def.DataType = "string"
case id.Float:
def.DataType = "float32"
case id.Double:
def.DataType = "float64"
default:
def.DataType = attrs[4].Value.NodeID().String()
}
case uaGopcua.StatusBadAttributeIDInvalid:
// ignore
default:
return nil, err
}
def.Path = join(path, def.BrowseName)
var nodes []NodeDef
if def.NodeClass == uaGopcua.NodeClassVariable {
nodes = append(nodes, def)
}
bc, err := browseChildren(oc, n, def.Path, level, id.HasComponent)
if err != nil {
return nil, err
}
nodes = append(nodes, bc...)
bc, err = browseChildren(oc, n, def.Path, level, id.Organizes)
if err != nil {
return nil, err
}
nodes = append(nodes, bc...)
bc, err = browseChildren(oc, n, def.Path, level, id.HasProperty)
if err != nil {
return nil, err
}
nodes = append(nodes, bc...)
return nodes, nil
}
func browseChildren(c *opcuaGopcua.Client, n *opcuaGopcua.Node, path string, level int, typeDef uint32) ([]NodeDef, error) {
nodes := []NodeDef{}
refs, err := n.ReferencedNodes(typeDef, uaGopcua.BrowseDirectionForward, uaGopcua.NodeClassAll, true)
if err != nil {
return []NodeDef{}, err
}
for _, ref := range refs {
children, err := browse(c, ref.ID.String(), path, level+1)
if err != nil {
return []NodeDef{}, err
}
nodes = append(nodes, children...)
}
return nodes, nil
}
func join(a, b string) string {
if a == "" {
return b
}
return a + "." + b
}