Documentation
¶
Overview ¶
Package client contains utilties for creating Simple IoT clients.
A Simple IoT Client contains the logic for nodes described in the Simple IoT graph store. Examples of built in clients include: Modbus, 1-wire, Upstream, etc.
A client Manager is used to watch the Simple IoT store and create and update new clients as they are created and modified.
See Client and NewManager for ideas on how to get started with your own client.
This package also contains a number of utility functions for interacting with the Simple IoT NATS API.
Index ¶
- func DecodeEdgePointsMsg(msg *nats.Msg) (string, string, []data.Point, error)
- func DecodeNodePointsMsg(msg *nats.Msg) (string, []data.Point, error)
- func DeleteNode(nc *nats.Conn, id, parent string) error
- func Dump(nc *nats.Conn, msg *nats.Msg) error
- func DuplicateNode(nc *nats.Conn, id, newParent string) error
- func EdgeConnect(eo EdgeOptions) (*nats.Conn, error)
- func ExpBackoff(attempts int, max time.Duration) time.Duration
- func GetNode(nc *nats.Conn, id, parent string) ([]data.NodeEdge, error)
- func GetNodeChildren(nc *nats.Conn, id, typ string, includeDel bool, recursive bool) ([]data.NodeEdge, error)
- func GetNodesForUser(nc *nats.Conn, userID string) ([]data.NodeEdge, error)
- func ListenForFile(nc *nats.Conn, dir, deviceID string, callback func(path string)) error
- func MirrorNode(nc *nats.Conn, id, newParent string) error
- func MoveNode(nc *nats.Conn, id, oldParent, newParent string) error
- func SendEdgePoint(nc *nats.Conn, nodeID, parentID string, point data.Point, ack bool) error
- func SendEdgePoints(nc *nats.Conn, nodeID, parentID string, points data.Points, ack bool) error
- func SendFile(nc *nats.Conn, deviceID string, reader io.Reader, name string, ...) error
- func SendNode(nc *nats.Conn, node data.NodeEdge) error
- func SendNodePoint(nc *nats.Conn, nodeID string, point data.Point, ack bool) error
- func SendNodePointCreate(nc *nats.Conn, nodeID string, point data.Point, ack bool) error
- func SendNodePoints(nc *nats.Conn, nodeID string, points data.Points, ack bool) error
- func SendNodePointsCreate(nc *nats.Conn, nodeID string, points data.Points, ack bool) error
- func String(nc *nats.Conn, msg *nats.Msg) (string, error)
- func SubjectEdgeAllPoints() string
- func SubjectEdgePoints(nodeID, parentID string) string
- func SubjectNodeAllPoints() string
- func SubjectNodePoints(nodeID string) string
- func UserCheck(nc *nats.Conn, email, pass string) ([]data.NodeEdge, error)
- type Client
- type EdgeOptions
- type Manager
- type Metric
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DecodeEdgePointsMsg ¶
DecodeEdgePointsMsg decodes NATS message into node ID and points
func DecodeNodePointsMsg ¶
DecodeNodePointsMsg decodes NATS message into node ID and points
func DeleteNode ¶
DeleteNode removes a node from the specified parent node
func DuplicateNode ¶
DuplicateNode is used to Duplicate a node and all its children
func EdgeConnect ¶
func EdgeConnect(eo EdgeOptions) (*nats.Conn, error)
EdgeConnect is a function that attempts connections for edge devices with appropriate timeouts, backups, etc. Currently set to disconnect if we don't have a connection after 6m, and then exp backup to try to connect every 6m after that.
func ExpBackoff ¶
ExpBackoff calculates an exponential time backup to max duration + a random fraction of 1s
func GetNode ¶
GetNode over NATS. If id is "root", the root node is fetched. If parent is set to "none", the edge details are not included and the hash is calculated without the edge points. returns data.ErrDocumentNotFound if node is not found. If parent is set to "all", then all living instances of the node are returned.
func GetNodeChildren ¶
func GetNodeChildren(nc *nats.Conn, id, typ string, includeDel bool, recursive bool) ([]data.NodeEdge, error)
GetNodeChildren over NATS (immediate children only, not recursive) deleted nodes are skipped unless includeDel is set to true. typ can be used to limit nodes to a particular type, otherwise, all nodes are returned.
func GetNodesForUser ¶
GetNodesForUser gets all nodes for a user
func ListenForFile ¶
ListenForFile listens for a file sent from server. dir is the directly to place downloaded files.
func MirrorNode ¶
MirrorNode adds a an existing node to a new parent. A node can have multiple parents.
func SendEdgePoint ¶
SendEdgePoint sends a edge point using the nats protocol
func SendEdgePoints ¶
SendEdgePoints sends points using the nats protocol
func SendFile ¶
func SendFile(nc *nats.Conn, deviceID string, reader io.Reader, name string, callback func(int)) error
SendFile can be used to send a file to a device. Callback provides bytes transfered.
func SendNodePoint ¶
SendNodePoint sends a node point using the nats protocol
func SendNodePointCreate ¶
SendNodePointCreate sends a node point using the nats protocol and creates the node if it does not already exist
func SendNodePoints ¶
SendNodePoints sends node points using the nats protocol
func SendNodePointsCreate ¶
SendNodePointsCreate sends a node point using the nats protocol and creates the node if it does not already exist
func SubjectEdgeAllPoints ¶
func SubjectEdgeAllPoints() string
SubjectEdgeAllPoints provides subject for all edge points for any node
func SubjectEdgePoints ¶
SubjectEdgePoints constructs a NATS subject for edge points
func SubjectNodeAllPoints ¶
func SubjectNodeAllPoints() string
SubjectNodeAllPoints provides subject for all points for any node
func SubjectNodePoints ¶
SubjectNodePoints constructs a NATS subject for node points
Types ¶
type Client ¶
Client interface describes methods a Simple Iot client must implement. This is to be kept as simple as possible, and the ClientManager does all the heavy lifting of interacting with the rest of the SIOT system. Start should block until Stop is called. Start MUST return when Stop is called. Stop does not block -- wait until Start returns if you need to know the client is stopped. Points and EdgePoints are called when there are updates to the client node.
type EdgeOptions ¶
type EdgeOptions struct {
URI string
AuthToken string
NoEcho bool
Disconnected func()
Reconnected func()
Closed func()
}
EdgeOptions describes options for connecting edge devices
type Manager ¶
type Manager[T any] struct { // contains filtered or unexported fields }
Manager manages a node type, watches for changes, adds/removes instances that get added/deleted
func NewManager ¶
func NewManager[T any](nc *nats.Conn, root string, construct func(nc *nats.Conn, config T) Client) *Manager[T]
NewManager takes constructor for a node client and returns a Manager for that client The Node Type is inferred from the Go type passed in, so you must name Go client Types to manage the node type definitions.
Example ¶
package main
import (
"log"
"github.com/nats-io/nats.go"
"github.com/simpleiot/simpleiot/client"
"github.com/simpleiot/simpleiot/data"
"github.com/simpleiot/simpleiot/test"
)
// exNode is decoded data from the client node
type exNode struct {
ID string `node:"id"`
Parent string `node:"parent"`
Description string `point:"description"`
Port int `point:"port"`
Role string `edgepoint:"role"`
}
// exNodeClient contains the logic for this client
type exNodeClient struct {
nc *nats.Conn
config testNode
stop chan struct{}
stopped chan struct{}
newPoints chan []data.Point
newEdgePoints chan []data.Point
chGetConfig chan chan testNode
}
// newExNodeClient is passed to the NewManager() function call -- when
// a new node is detected, the Manager will call this function to construct
// a new client.
func newExNodeClient(nc *nats.Conn, config testNode) client.Client {
return &testNodeClient{
nc: nc,
config: config,
stop: make(chan struct{}),
newPoints: make(chan []data.Point),
newEdgePoints: make(chan []data.Point),
}
}
// Start runs the main logic for this client and blocks until stopped
func (tnc *exNodeClient) Start() error {
for {
select {
case <-tnc.stop:
close(tnc.stopped)
return nil
case pts := <-tnc.newPoints:
err := data.MergePoints(pts, &tnc.config)
if err != nil {
log.Println("error merging new points: ", err)
}
log.Printf("New config: %+v\n", tnc.config)
case pts := <-tnc.newEdgePoints:
err := data.MergeEdgePoints(pts, &tnc.config)
if err != nil {
log.Println("error merging new points: ", err)
}
case ch := <-tnc.chGetConfig:
ch <- tnc.config
}
}
}
// Stop sends a signal to the Start function to exit
func (tnc *exNodeClient) Stop(err error) {
close(tnc.stop)
}
// Points is called by the Manager when new points for this
// node are received.
func (tnc *exNodeClient) Points(points []data.Point) {
tnc.newPoints <- points
}
// EdgePoints is called by the Manager when new edge points for this
// node are received.
func (tnc *exNodeClient) EdgePoints(points []data.Point) {
tnc.newEdgePoints <- points
}
func main() {
nc, root, stop, err := test.Server()
if err != nil {
log.Println("Error starting test server: ", err)
}
defer stop()
testConfig := testNode{"", "", "fancy test node", 8080, "admin"}
// Convert our custom struct to a data.NodeEdge struct
ne, err := data.Encode(testConfig)
if err != nil {
log.Println("Error encoding node: ", err)
}
ne.Parent = root.ID
// hydrate database with test node
err = client.SendNode(nc, ne)
if err != nil {
log.Println("Error sending node: ", err)
}
// Create a new manager for nodes of type "testNode". The manager looks for new nodes under the
// root and if it finds any, it instantiates a new client, and sends point updates to it
m := client.NewManager(nc, root.ID, newExNodeClient)
m.Start()
// Now any updates to the node will tigger Points/EdgePoints callbacks in the above client
}
type Metric ¶
type Metric struct {
// contains filtered or unexported fields
}
Metric is a type that can be used to track metrics and periodically report them to a node point. Data is queued and averaged and then the average is sent out as a point.