Documentation ¶
Overview ¶
Package sdk enables the development of plugins for the Synse Platform.
The Synse SDK implements the core plugin logic and makes it easy to create new plugins. These plugins form the backbone of the Synse platform, interfacing with devices and exposing them to Synse Server so all devices can be managed and controlled though a simple HTTP interface, regardless of backend protocol.
For more information, see: https://synse.readthedocs.io/en/latest/sdk/intro/
Index ¶
- Constants
- Variables
- func SetPluginInfo(name, maintainer, desc, vcs string)
- type AliasCache
- type AliasContext
- type ApplyTransformer
- type Device
- func (device *Device) GetContext(key string) string
- func (device *Device) GetHandler() *DeviceHandler
- func (device *Device) GetID() string
- func (device *Device) IsReadable() bool
- func (device *Device) IsWritable() bool
- func (device *Device) Read() (*ReadContext, error)
- func (device *Device) Write(data *WriteData) error
- type DeviceAction
- type DeviceDataValidator
- type DeviceHandler
- type DeviceIdentifier
- type DynamicDeviceConfigRegistrar
- type DynamicDeviceRegistrar
- type ListenerCtx
- type Plugin
- func (plugin *Plugin) AddDevice(device *Device) error
- func (plugin *Plugin) GenerateDeviceID(device *Device) string
- func (plugin *Plugin) GetDevice(id string) *Device
- func (plugin *Plugin) NewDevice(proto *config.DeviceProto, instance *config.DeviceInstance) (*Device, error)
- func (plugin *Plugin) RegisterDeviceHandlers(handlers ...*DeviceHandler) error
- func (plugin *Plugin) RegisterDeviceSetupActions(actions ...*DeviceAction) error
- func (plugin *Plugin) RegisterHealthChecks(checks ...health.Check) error
- func (plugin *Plugin) RegisterOutputs(outputs ...*output.Output) error
- func (plugin *Plugin) RegisterPostRunActions(actions ...*PluginAction)
- func (plugin *Plugin) RegisterPreRunActions(actions ...*PluginAction)
- func (plugin *Plugin) Run() error
- type PluginAction
- type PluginHandlers
- type PluginMetadata
- type PluginOption
- func CustomDeviceDataValidator(validator DeviceDataValidator) PluginOption
- func CustomDeviceIdentifier(identifier DeviceIdentifier) PluginOption
- func CustomDynamicDeviceConfigRegistration(registrar DynamicDeviceConfigRegistrar) PluginOption
- func CustomDynamicDeviceRegistration(registrar DynamicDeviceRegistrar) PluginOption
- func DeviceConfigOptional() PluginOption
- func DynamicConfigRequired() PluginOption
- func PluginConfigRequired() PluginOption
- type ReadContext
- type ReadStream
- type ScaleTransformer
- type Tag
- type TagCache
- type Transformer
- type WriteContext
- type WriteData
Constants ¶
const ( // Tag namespace constants TagNamespaceDefault = "default" TagNamespaceSystem = "system" // Tag annotation constants TagAnnotationID = "id" TagAnnotationType = "type" // Special tag components TagLabelAll = "**" )
Tag component constants.
const ( // DeviceEnvOverride defines the environment variable that can be used to // set an override config location for device configuration files. DeviceEnvOverride = "PLUGIN_DEVICE_CONFIG" )
const ( // PluginEnvOverride defines the environment variable that can be used to // set an override config location for the Plugin configuration file. PluginEnvOverride = "PLUGIN_CONFIG" )
const Version = "v2.1.2"
Version specifies the version of the Synse Plugin SDK.
Variables ¶
var ( ErrDeviceNotWritable = errors.New("writing is not enabled for the device") ErrDeviceWriteTimeout = errors.New("device write timed out") ErrNilDevice = errors.New("cannot perform action on nil device") ErrNilData = errors.New("cannot write nil data to device") )
Scheduler error definitions.
var ( ErrServerNeedsConfig = errors.New("server requires configuration to initialize") ErrServerNotInitialized = errors.New("unable to run: server not initialized") ErrSelectorRequiresID = sdkError.InvalidArgumentErr("selector must specify device id") ErrNoDeviceForSelector = sdkError.NotFoundErr("no device found for specified selector") ErrTransactionNotFound = sdkError.NotFoundErr("transaction not found") )
Server error definitions.
var ( ErrNilTransformConfig = errors.New("cannot create transformer: nil config") ErrUnknownTransformFn = errors.New("unknown transform apply function specified") )
Errors relating to Transformer creation and application.
var ( // BuildDate is the timestamp for when the build happened. BuildDate string // GitCommit is the commit hash at which the plugin was built. GitCommit string // GitTag is the git tag at which the plugin was built. GitTag string // GoVersion is the version of Go used to build the plugin. GoVersion string // PluginVersion is the canonical version string for the plugin. PluginVersion string )
var (
ErrDeviceIDExists = errors.New("conflict: device id already exists")
)
Device manager error definitions.
Functions ¶
func SetPluginInfo ¶
func SetPluginInfo(name, maintainer, desc, vcs string)
SetPluginInfo sets the meta-information for a Plugin. This should be this first step in creating a new plugin.
Types ¶
type AliasCache ¶
type AliasCache struct {
// contains filtered or unexported fields
}
AliasCache is a cache which is used to lookup devices based on any aliases registered by the device.
func NewAliasCache ¶
func NewAliasCache() *AliasCache
NewAliasCache creates a new AliasCache instance.
func (*AliasCache) Add ¶
func (cache *AliasCache) Add(alias string, device *Device) error
Add adds a device alias mapping to the cache.
func (*AliasCache) Get ¶
func (cache *AliasCache) Get(alias string) *Device
Get gets the device associated with the specified alias. If the given alias is not associated with a device, this returns nil.
type AliasContext ¶
type AliasContext struct { Meta *PluginMetadata Device *Device }
AliasContext is the context that is used to render alias templates.
type ApplyTransformer ¶
ApplyTransformer is a device reading Transformer which applies pre-defined functions to a device's reading(s).
func NewApplyTransformer ¶
func NewApplyTransformer(fn string) (*ApplyTransformer, error)
NewApplyTransformer creates a new device reading Transformer which is used to apply pre-defined functions to a device's reading(s). The SDK has some built-in functions in the 'funcs' package. A plugin may also register its own. Functions are referenced by name.
func (*ApplyTransformer) Apply ¶
func (t *ApplyTransformer) Apply(reading *output.Reading) error
Apply the transformer function to the given reading value.
func (*ApplyTransformer) Name ¶
func (t *ApplyTransformer) Name() string
Name returns a human-readable name for the apply transformer.
type Device ¶
type Device struct { // Type is the type of the device. This is largely metadata that can // be used upstream to categorize the device. Type string // Info is a human-readable string that provides a summary of what // the device is or what it does. Info string // Tags is the set of tags that are associated with the device. Tags []*Tag // Data contains any plugin-specific configuration data for the device. Data map[string]interface{} // Context contains any contextual information which should be associated // with the device's reading(s). Context map[string]string // Handler is the name of the device's handler. Handler string // SortIndex is an optional 1-based index sort ordinal that is used upstream // (by Synse Server) to sort the device in Scan output. This can be set to // give devices custom ordering. If not set, they will be sorted based on // default sorting parameters. SortIndex int32 // Alias is a human-readable alias for the device which can be used to // to reference it as well. Alias string // Transforms is a collection of the device reading transformers that are to // be applied to the device's reading(s). These are generally (but not limited) // to scale or convert the device reading(s). Typically, these will be defined // for general-purpose plugins where the device handler is not specific enough // to know the desired output of a device reading. // // Transformations are applied in the order in which they are defined. // // See the TransformConfig and Transformer godoc for more details. Transforms []Transformer // WriteTimeout defines the time within which a write action (transaction) // will remain valid for this device. WriteTimeout time.Duration // Output is the name of the Output that this device instance will use. This // is not needed for all devices/plugins, as many DeviceHandlers will already // know which output to use. This field is used in cases of generalized plugins, // such as Modbus-IP, where a generalized handler will need to map something // (like a set of registers) to a reading output. Output string // contains filtered or unexported fields }
Device is a single physical or virtual device which the Plugin manages.
It defines all of the information known about the device, which typically comes from configuration file. A Device's supported actions are determined by the DeviceHandler which it is configured to use.
func NewDeviceFromConfig ¶
func NewDeviceFromConfig( proto *config.DeviceProto, instance *config.DeviceInstance, handlers map[string]*DeviceHandler, ) (*Device, error)
NewDeviceFromConfig creates a new instance of a Device from its device prototype and device instance configuration. This is the primary and recommended way of building devices.
These configuration components are loaded from config file.
The device instance and prototype may specify a device handler name in their Handler field. This is only the name of the Handler, not a reference to the device Handler itself. A map[string]*DeviceHandler must be passed to this function to register the device handler with the device (in the private `handler` field, looking up the appropriate handler from the map using the `Handler` name.
If no handler is found in the map for the device, an error is returned.
func (*Device) GetContext ¶
GetContext gets a value out of the device's context map.
func (*Device) GetHandler ¶
func (device *Device) GetHandler() *DeviceHandler
GetHandler gets the DeviceHandler of the device.
func (*Device) IsReadable ¶
IsReadable checks if the Device is readable based on the presence/absence of a Read/BulkRead action defined in its DeviceHandler.
func (*Device) IsWritable ¶
IsWritable checks if the Device is writable based on the presence/absence of a Write action defined in its DeviceHandler.
func (*Device) Read ¶
func (device *Device) Read() (*ReadContext, error)
Read performs the read action for the device, as set by its DeviceHandler.
If reading is not supported on the device, an UnsupportedCommandError is returned.
type DeviceAction ¶
type DeviceAction struct { // Name is the name of the action. This is used to identify the action. Name string // Filter is the device filter that scopes which devices this action // should apply to. This filter is run on the entire set of registered // devices and is additive (e.g. a device does not need to match all // filters to be included, it just needs to match one). // // The filter provided should be a map, where the key is the field to filter // on and the value are the allowable values for that field. The currently // supported filters include: // * "type" : the device type Filter map[string][]string // The action to execute for the device. Action func(p *Plugin, d *Device) error }
DeviceAction defines an action that can be run before the main Plugin run logic. This is generally used for doing device-specific setup actions.
type DeviceDataValidator ¶
DeviceDataValidator is a handler function that takes the `Data` field of a device config and performs some validation on it. This allows users to provide validation on the plugin-specific config fields.
type DeviceHandler ¶
type DeviceHandler struct { // Name is the name of the handler. This is how the handler will be referenced // and associated with Device instances via their configuration. This name should // match with the "Handler" configuration field. Name string // Write is a function that handles Write requests for the handler's devices. If // the devices do not support writing, this can be left unspecified. Write func(*Device, *WriteData) error // Read is a function that handles Read requests for the handler's devices. If the // devices do not support reading, this can be left unspecified. Read func(*Device) ([]*output.Reading, error) // BulkRead is a function that handles bulk read operations for the handler's devices. // A bulk read is where all devices of a given kind are read at once, instead of individually. // If a device does not support bulk read, this can be left as nil. Additionally, // a device can only be bulk read if there is no Read handler set. BulkRead func([]*Device) ([]*ReadContext, error) // Listen is a function that will listen for push-based data from the device. // This function is called one per device using the handler, even if there are // other handler functions (e.g. read, write) defined. The listener function // will run in a separate goroutine for each device. The goroutines are started // before the read/write loops. // // NOTE: The Listen function is deprecated and will be removed in a future version // of the SDK. Listen func(*Device, chan *ReadContext) error // Actions specifies a list of the supported write actions for the handler. // This is optional and is just used as metadata surfaced by the SDK to the // client via the gRPC API. Actions []string }
DeviceHandler specifies the read and write handlers for a Device based on its type and model.
func (*DeviceHandler) CanBulkRead ¶
func (handler *DeviceHandler) CanBulkRead() bool
CanBulkRead returns true if the handler has a bulk read function defined and no regular read function defined (both cannot coexist); false otherwise.
func (*DeviceHandler) CanListen ¶
func (handler *DeviceHandler) CanListen() bool
CanListen returns true if the handler has a listen function defined; false otherwise.
func (*DeviceHandler) CanRead ¶
func (handler *DeviceHandler) CanRead() bool
CanRead returns true if the handler has a read function defined; false otherwise.
func (*DeviceHandler) CanWrite ¶
func (handler *DeviceHandler) CanWrite() bool
CanWrite returns true if the handler has a write function defined; false otherwise.
func (*DeviceHandler) GetCapabilitiesMode ¶
func (handler *DeviceHandler) GetCapabilitiesMode() string
GetCapabilitiesMode gets the capabilities mode string representation for a device based on its device handler. This will be one of: "r" (read-only), "w" (write-only), or "rw" (read-write).
Note that a device is considered readable here if it can supply reading data. Currently, Read, BulkRead, and Listen can all supply reading data, so if any one of those are defined for the handler, the capabilities string will reflect that.
type DeviceIdentifier ¶
DeviceIdentifier is a handler function that produces a string that can be used to identify a device deterministically. The returned string should be a composite from the Device's config data.
type DynamicDeviceConfigRegistrar ¶
type DynamicDeviceConfigRegistrar func(map[string]interface{}) ([]*config.DeviceProto, error)
DynamicDeviceConfigRegistrar is a handler function that takes a Plugin config's "dynamic registration" data and generates Devices config instances from it. How this is done is specific to the plugin/protocol.
type DynamicDeviceRegistrar ¶
DynamicDeviceRegistrar is a handler function that takes a Plugin config's "dynamic registration" data and generates Device instances from it. How this is done is specific to the plugin/protocol.
type ListenerCtx ¶
type ListenerCtx struct {
// contains filtered or unexported fields
}
ListenerCtx is the context needed for a listener function to be called and retried at a later time if it errors out after the listener goroutine is initially dispatched.
func NewListenerCtx ¶
func NewListenerCtx(handler *DeviceHandler, device *Device) *ListenerCtx
NewListenerCtx creates a new ListenerCtx for the given handler and device.
type Plugin ¶
type Plugin struct {
// contains filtered or unexported fields
}
Plugin is a Synse Plugin.
func NewPlugin ¶
func NewPlugin(options ...PluginOption) (*Plugin, error)
NewPlugin creates a new instance of a Plugin. This should be the only way that a Plugin is initialized.
This constructor will load the plugin configuration; if it is not present or invalid, this will fail. All other Plugin component initialization is deferred until Run is called.
func (*Plugin) GenerateDeviceID ¶
GenerateDeviceID generates the deterministic ID for a device using the data contained within a Device definition as well as the DeviceIdentifier function, whether custom or default.
func (*Plugin) NewDevice ¶
func (plugin *Plugin) NewDevice(proto *config.DeviceProto, instance *config.DeviceInstance) (*Device, error)
NewDevice creates a new device, using the Device handlers registered with the plugin.
Note that this does not add the new device to the plugin.
func (*Plugin) RegisterDeviceHandlers ¶
func (plugin *Plugin) RegisterDeviceHandlers(handlers ...*DeviceHandler) error
RegisterDeviceHandlers adds DeviceHandlers to the Plugin.
These DeviceHandlers are matched with the Device instances by their name and provide the read/write functionality for Devices. If a DeviceHandler is not registered for a Device, the Device will not be usable by the plugin.
func (*Plugin) RegisterDeviceSetupActions ¶
func (plugin *Plugin) RegisterDeviceSetupActions(actions ...*DeviceAction) error
RegisterDeviceSetupActions registers actions with the device manager which will be executed on start. These actions are used for device-specific setup.
func (*Plugin) RegisterHealthChecks ¶
RegisterHealthChecks registers custom health checks with the plugin.
func (*Plugin) RegisterOutputs ¶
RegisterOutputs registers new Outputs with the plugin. A plugin will automatically register the built-in SDK outputs. This function allows a plugin do augment that set of outputs with its own custom outputs.
If any registered output names conflict with those of built-in or other custom outputs, an error is returned.
func (*Plugin) RegisterPostRunActions ¶
func (plugin *Plugin) RegisterPostRunActions(actions ...*PluginAction)
RegisterPostRunActions registers actions with the Plugin which will be called after it terminates.
These actions are generally cleanup and teardown actions.
func (*Plugin) RegisterPreRunActions ¶
func (plugin *Plugin) RegisterPreRunActions(actions ...*PluginAction)
RegisterPreRunActions registers actions with the Plugin which will be called prior to the business logic of the Plugin.
Pre-run actions are considered setup/validator actions and as such, they are included in the Plugin dry-run.
func (*Plugin) Run ¶
Run starts the plugin.
This is the functional starting point for all plugins. Once this is called, the plugin will initialize all of its components and validate its state. Once everything is ready, it will run each of its components. The gRPC server is run in the foreground; all other components are run as goroutines.
type PluginAction ¶
PluginAction defines an action that can be run before or after the main Plugin run logic. This is generally used for setup/teardown.
type PluginHandlers ¶
type PluginHandlers struct { // DeviceIdentifier is a plugin-defined function for uniquely identifying devices. DeviceIdentifier DeviceIdentifier // DynamicRegistrar is a plugin-defined function which generates devices dynamically. DynamicRegistrar DynamicDeviceRegistrar // DynamicConfigRegistrar is a plugin-defined function which generates device configs dynamically. DynamicConfigRegistrar DynamicDeviceConfigRegistrar // DeviceDataValidator is a plugin-defined function that can be used to validate a // Device's Data field. DeviceDataValidator DeviceDataValidator }
PluginHandlers defines the set of handler functions that a Plugin instance may use.
func NewDefaultPluginHandlers ¶
func NewDefaultPluginHandlers() *PluginHandlers
NewDefaultPluginHandlers returns the default set of plugin handlers.
type PluginMetadata ¶
PluginMetadata is the metadata associated with a Plugin.
func (*PluginMetadata) Tag ¶
func (info *PluginMetadata) Tag() string
Tag creates the tag used in the plugin meta information.
type PluginOption ¶
type PluginOption func(*Plugin)
A PluginOption sets optional configurations or functional capabilities for a plugin. This includes things like device identification and device registration behaviors.
func CustomDeviceDataValidator ¶
func CustomDeviceDataValidator(validator DeviceDataValidator) PluginOption
CustomDeviceDataValidator lets you set a custom function for validating the Data field of a device's config. By default, this data is not validated by the SDK, since it is plugin-specific.
func CustomDeviceIdentifier ¶
func CustomDeviceIdentifier(identifier DeviceIdentifier) PluginOption
CustomDeviceIdentifier lets you set a custom function for creating a deterministic identifier for a device using the config data for the device.
func CustomDynamicDeviceConfigRegistration ¶
func CustomDynamicDeviceConfigRegistration(registrar DynamicDeviceConfigRegistrar) PluginOption
CustomDynamicDeviceConfigRegistration lets you set a custom function for dynamically registering DeviceConfig instances using the data from the "dynamic registration" field in the Plugin config.
func CustomDynamicDeviceRegistration ¶
func CustomDynamicDeviceRegistration(registrar DynamicDeviceRegistrar) PluginOption
CustomDynamicDeviceRegistration lets you set a custom function for dynamically registering Device instances using the data from the "dynamic registration" field in the Plugin config.
func DeviceConfigOptional ¶
func DeviceConfigOptional() PluginOption
DeviceConfigOptional is a PluginOption which designates that a Plugin should not require device configurations to be required, as they are by default. This can be the case when a plugin may support dynamic device configuration, so pre-defined device configs may not be specified.
func DynamicConfigRequired ¶
func DynamicConfigRequired() PluginOption
DynamicConfigRequired is a PluginOption which designates that a Plugin requires dynamic device configuration. By default, dynamic device configuration is optional. This can be set if a plugin is designed to only load devices in a dynamic fashion, and not through pre-defined config files.
func PluginConfigRequired ¶
func PluginConfigRequired() PluginOption
PluginConfigRequired is a PluginOption which designates that a Plugin should require a plugin config and will fail if it does not detect one. By default, a Plugin considers them optional and will use a set of default configurations if no config is found.
type ReadContext ¶
ReadContext provides the context for a device reading. This context identifies the device being read and associates it with a set of readings at a given time.
A single device can provide more than one reading (e.g. a humidity sensor could provide both a humidity and temperature reading). To accommodate, the ReadContext allows for multiple readings to be associated with the device. Note that the collection of readings in a single ReadContext would correspond to a single Read request.
func NewReadContext ¶
func NewReadContext(device *Device, readings []*output.Reading) *ReadContext
NewReadContext creates a new instance of a ReadContext from the given device and corresponding readings.
type ReadStream ¶
type ReadStream struct {
// contains filtered or unexported fields
}
ReadStream encapsulates a channel which is used to stream data to a client.
type ScaleTransformer ¶
type ScaleTransformer struct {
Factor float64
}
ScaleTransformer is a device reading transformer which scales a device's reading(s) by a multiplicative factor.
func NewScaleTransformer ¶
func NewScaleTransformer(factor string) (*ScaleTransformer, error)
NewScaleTransformer creates a new device reading Transformer which is used to scale readings by a multiplicative factor.
The scaling factor is specified as a string, but should resolve to a numeric. By default, it will have a value of 1 (e.g. no-op). Negative values and fractional values are supported. This can be the value itself, e.g. "0.01", or a mathematical representation of the value, e.g. "1e-2". Dividing is the same as multiplying by a fraction (e.g. "/ 2" == "* 0.5").
func (*ScaleTransformer) Apply ¶
func (t *ScaleTransformer) Apply(reading *output.Reading) error
Apply the transformer scaling factor to the given reading value.
func (*ScaleTransformer) Name ¶
func (t *ScaleTransformer) Name() string
Name returns a human-readable name for the scale transformer.
type Tag ¶
type Tag struct { Namespace string Annotation string Label string // contains filtered or unexported fields }
Tag represents a group identifier which a Synse device can belong to.
func DeviceSelectorToID ¶
func DeviceSelectorToID(selector *synse.V3DeviceSelector) *Tag
DeviceSelectorToID is a utility which converts a gRPC device selector message into a corresponding ID tag. If the selector has no value in the Id field, this will return nil.
func DeviceSelectorToTags ¶
func DeviceSelectorToTags(selector *synse.V3DeviceSelector) []*Tag
DeviceSelectorToTags is a utility that converts a gRPC device selector message into its corresponding tags.
func NewTagFromGRPC ¶
NewTagFromGRPC creates a new Tag from the gRPC tag message.
func (*Tag) HasAnnotation ¶
HasAnnotation checks whether the tag has an annotation defined.
func (*Tag) HasNamespace ¶
HasNamespace checks whether the tag has a namespace defined.
type TagCache ¶
type TagCache struct {
// contains filtered or unexported fields
}
TagCache is a cache which can be used for looking up devices based on their tags.
func (*TagCache) GetDevicesFromNamespace ¶
GetDevicesFromNamespace gets the devices for the specified namespaces.
func (*TagCache) GetDevicesFromStrings ¶
GetDevicesFromStrings gets the list of Devices which match the given set of tag strings.
func (*TagCache) GetDevicesFromTags ¶
GetDevicesFromTags gets the list of Devices which match the given set of tags.
type Transformer ¶
type Transformer interface { // Apply the transformation to the given reading value. Apply(reading *output.Reading) error // Get the name of the transformer. Name() string }
A Transformer is something which transforms a device's raw reading value(s). This transformation is typically a scaling or type conversion. This is generally used more for general-purpose plugins where the device handler is not specific to the device/output and the reading value may need to be coerced into a desired output.
func NewTransformer ¶
func NewTransformer(cfg *config.TransformConfig) (Transformer, error)
NewTransformer creates a new device reading Transformer from the provided TransformConfig. If the configuration is incorrect or specifies unsupported values, an error is returned.
type WriteContext ¶
type WriteContext struct {
// contains filtered or unexported fields
}
WriteContext describes a single write transaction.
type WriteData ¶
type WriteData synse.V3WriteData
WriteData is an SDK alias for the Synse gRPC WriteData. This is done to make writing new plugins easier.