github.com/simpleiot/simpleiot@v0.18.3/docs/ref/client.md (about) 1 # Simple IoT Clients 2 3 **Contents** 4 5 <!-- toc --> 6 7 Most functionality in Simple IoT is implemented in Clients. 8 9  10 11 Each client can be configured by one or more nodes in the SIOT store graph. 12 These nodes may be created by a user, a process that detects new plug and play 13 hardware, or other clients. 14 15 A client interacts with the system by listening for new points it is interested 16 in and sending out points as it acquires new data. 17 18 ## Creating new clients 19 20 See [Development](development.md) for information on how to set up a development 21 system. 22 23 Simple IoT provides utilities that assist in creating new clients. See the 24 [Go package documentation](https://pkg.go.dev/github.com/simpleiot/simpleiot/client) 25 for more information. A client manager is created for each client type. This 26 manager instantiates new client instances when new nodes are detected and then 27 sends point updates to the client. Two levels of nodes are currently supported 28 for client configuration. An example of this would be a Rule node that has 29 Condition and Action child nodes. 30 31 A "disabled" option is useful and should be considered for every new client. 32 33 Creating a new client typically requires the following steps: 34 35 1. add any new node and points types to 36 [`schema.go`](https://github.com/simpleiot/simpleiot/blob/master/data/schema.go), 37 [`Node.elm`](https://github.com/simpleiot/simpleiot/blob/master/frontend/src/Api/Node.elm), 38 and 39 [`Point.elm`](https://github.com/simpleiot/simpleiot/blob/master/frontend/src/Api/Point.elm). 40 Please try to reuse existing point types when possible. 41 1. create a new client in 42 [`client/`](https://github.com/simpleiot/simpleiot/tree/master/client) 43 directory. A client is defined by a type that satisfies the 44 [`Client interface`](https://pkg.go.dev/github.com/simpleiot/simpleiot/client#Client). 45 A constructor must also be defined that is passed to 46 [`NewManager`](https://pkg.go.dev/github.com/simpleiot/simpleiot/client#NewManager) 47 and a struct that represents the client data. The name of the struct must 48 match the node type -- for instance a node of type `canBus` needs to be 49 defined by a struct named `CanBus`. Additionally, each field of the client 50 struct must have point tags. This allows us to automatically create and 51 modify client structs from arrays of node points. 52 1. create a new manager for the client in 53 [`client/client.go`](https://github.com/simpleiot/simpleiot/blob/master/client/client.go) 54 1. Create an Elm UI for the clent in 55 [`frontend/src/Components/`](https://github.com/simpleiot/simpleiot/tree/master/frontend/src/Components) 56 1. Create plumbing for new NodeXYZ in 57 [`frontend/src/Pages/Home_.elm`](https://github.com/simpleiot/simpleiot/blob/master/frontend/src/Pages/Home_.elm). 58 Note, this can likely be improved a lot. 59 60 It is easiest to copy one of the existing clients to start. The NTP client is 61 relatively simple and may be a good example. 62 63 ## Client lifecycle 64 65 It is important the clients cleanly implement the 66 [Run()/Stop() pattern](architecture-app.md#application-lifecycle) and shut down 67 cleanly when Stop() is called releasing all resources. If nodes are added or 68 removed, clients are started/stopped. Additionally if a child node of a client 69 config is added or removed, the entire client is stopped and then restarted. 70 This relieves the burden on the client from managing the addition/removal of 71 client functionality. Thus it is very important that clients stop cleanly and 72 release resources in case they are restarted. 73 74 ## Message echo 75 76 Clients need to be aware of the "echo" problem as they typically subscribe as 77 well as publish to the `points` subject for the nodes they manage. When they 78 publish to these subjects, these messages will be echoed back to them. There are 79 several solutions: 80 81 1. create a new NATS connection for the client with the 82 [NoEcho](https://docs.nats.io/using-nats/developer/connecting/noecho) option 83 set. For this to work, each client will need to establish its own connection 84 to the server. This may not work in cases where subjects are aliased into 85 authenticated subject namespaces. 86 2. inspect the `Point` `Origin` field -- if is blank, then it was generated by 87 the node that owns the point and does not need to be processed by the client 88 generating the data for that node. If is not blank, then the Point was 89 generated by a user, rule, or something other than the client owning the node 90 and must be processed. This may not always work -- example: user is connected 91 to a downstream instance and modifies a point that then propagates upstream 92 -- it may get echo'd back to an authenticated client. 93 3. (investigation stage) A NATS messages header can be populated with the ID of 94 the client that sent the message. If it is an authenticated client, then the 95 message will not be echo'd on the authenticated client subject namespace of 96 the same ID. This information is not stored, so cannot be used for auditing 97 purposes. 98 99 The SIOT client manager filters out points for the following two scenarios: 100 101 1. a point with the same ID as the client and Origin set to a blank string. 102 1. a point received for a client where Origin matches the client root node ID. 103 104 Thus, if you want to set a point in one client and get that point to another 105 node client, you must set the Origin field. This helps ensure that the Origin 106 field is used consistently as otherwise stuff won't work. 107 108 This gets a little tricky for clients that manage a node and its children (for 109 instance the rule client -- it has condition and action child nodes). If we 110 follow the the following rule: 111 112 **Clients must set the point Origin field for any point sent to anything other 113 than than its root node.** 114 115 If we following the above rule, then things should work. We may eventally 116 provide clients with a function to send points that handles this automatically, 117 but for now it is manual. 118 119 See also [tracking who made changes](data.md#tracking-who-made-changes).