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  ![app-arch](images/arch-app.png)
    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).