bridge

package
v0.0.0-...-bb3eb04 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 10, 2021 License: MIT Imports: 15 Imported by: 0

README

bridge

This package offers a unified, gRPC-defined contract to any number of specific home automation technologies. The goal is to be able to interfact with home and building control devices in a consistent, technology-independent way. This is done by defining a few foundational primitives and exposing ways to interact with these primitives. These are:

  • a bridge
  • one or more devices controlled by the bridge The bridge is usually a physical entity which connects to a computer (or network), and acts as a gateway to the device or the home automation network which the devices connect to.

The bridge and device contracts both have distinct 'config' and 'state' elements. The 'config' element contains parameters which can be used to manipulate metadata associated with the parent, while the 'state' element contains parameters which manipulate the state of the parent itself. The intent of each object is that it is self-describing; it is possible for any consumer of the contract to understand what can be done to the device by reading properties directly from the element which describe the possible values of the different state elements.

There exist a number of implementations of this contract today included here. This package includes the contract definition, along with a couple of helper service definitions which can be included by particular implementations as needed.

The bridge contract is designed to support both major protocol approaches:

  1. those technologies and SDKs which expose a synchronous, request/response style interface.
  2. those technologies and SDKs which expose an asynchronous, event style interface.

There are a few foundational principles which implementers of this contract should keep in mind.

  1. performing a set action on an element should cause the resulting state value to be propagated to any subscribed clients via the 'Update' stream. Some protocols (such as ZWave, Deconz, etc.) cause this to happen automatically; while more low-level protocols (such as X10) may require that the implementation perform this manually. Handling of this is provided automatically by the SyncBridgeService.
  2. consumers of the contract should be able to assume the device ID is the one true identity of a device; and should it migrate between bridges the device itself will not change. As a result, clients of the contract will not intrinsically link devices to bridges outside the active connection between the client and the bridge.

Bridges advertise themselves over SSDP, using the falnet_nerves:bridge type. Typically advertisements are sent every 30 seconds.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrBridgeAlreadyAdded is returned if the requested bridge already exists
	ErrBridgeAlreadyAdded = errors.New("bridge already added")
	// ErrBridgeNotFound is returned if the requested bridge ID could not be found
	ErrBridgeNotFound = status.New(codes.NotFound, "bridge not found")
)
View Source
var (
	// ErrMissingParam is returned if a request is missing a required field
	ErrMissingParam = status.New(codes.InvalidArgument, "required param missing")
	// ErrNotSupported is returned if the requested method is not supported.
	ErrNotSupported = status.New(codes.InvalidArgument, "operation not supported")
	// ErrDeviceNotFound is returned if the requested device does not exist.
	ErrDeviceNotFound = status.New(codes.NotFound, "device not found")
	// ErrNotImplemented is returned if the requested method is not yet implemented.
	ErrNotImplemented = status.New(codes.Unimplemented, "not implemented")
	// ErrInternal is returned if the requested method had an error
	ErrInternal = status.New(codes.Internal, "internal error")
)

Functions

This section is empty.

Types

type Advertiser

type Advertiser struct {
	// contains filtered or unexported fields
}

Advertiser encapsulates the logic required to advertise this bridge to the network. The relevant connection info will be supplied during construction. If the 'any' IP is supplied the first global unicast IP of the host will be chosen for advertising. When advertisements should be sent, call Run(); when shutting down simply call Shutdown().

func NewAdvertiser

func NewAdvertiser(logger *zap.Logger, id string, connStr string) *Advertiser

NewAdvertiser sets up a new advertiser. ID will have the 'uuid' prefix added before broadcasting. connStr must be a <host>:<port> formatted string that will be included as the location to advertise to. If an 'any' IP, i.e 0.0.0.0 or [::] is supplied as the host it will be converted to the first global unicast IP address on the system so non-local endpoints can properly locate the endpoint.

func (*Advertiser) Ping

func (a *Advertiser) Ping(context.Context, *PingRequest) (*Pong, error)

Ping satisfies the ping service interface to allow this to respond to health checks.

func (*Advertiser) Run

func (a *Advertiser) Run()

Run begins the advertisement loop. Execute in a goroutine as this will not return.

func (*Advertiser) Shutdown

func (a *Advertiser) Shutdown()

Shutdown shuts this advertiser down.

type Hub

type Hub struct {
	// contains filtered or unexported fields
}

Hub abstracts the management of multiple bridges and their dependent devices. It is designed to simplify the implementation of clients which operate in a multi-bridge environment. The actual bridge a given device is controlled by is abstracted through the Hub API.

The hub may have many consumers interested in its updates - these are managed by the updateSource property. Updates are published to this source by a single goroutine which 'owns' changing the bridge and device maps.

func NewHub

func NewHub(logger *zap.Logger) *Hub

NewHub creates a new hub with the supplied logger.

func (*Hub) AddBridge

func (h *Hub) AddBridge(c BridgeServiceClient) error

AddBridge takes the supplied bridge services client, checks to see if it is already present, and if not adds the bridge client to the set of bridges active.

func (*Hub) Bridge

func (h *Hub) Bridge(id string) (*Bridge, error)

Bridge allows the caller to retrieve the bridge information, if present.

func (*Hub) GetDevice

func (h *Hub) GetDevice(id string) (*Device, error)

GetDevice retrieves the specified device.

func (*Hub) ListDevices

func (h *Hub) ListDevices() ([]*Device, error)

ListDevices returns the set of currently managed devices and their currently known states

func (*Hub) RemoveBridge

func (h *Hub) RemoveBridge(id string) error

RemoveBridge takes the specified bridge ID out of the system. It will not close the socket, if it is still open, but it will cancel any streaming requests. This will trigger a state change for any devices owned by this bridge, marking them as offline. Removing a bridge does not remove the device, as it is expected that a bridge going away is temporary.

func (*Hub) UpdateDeviceConfig

func (h *Hub) UpdateDeviceConfig(ctx context.Context, id string, config *DeviceConfig) (*Device, error)

UpdateDeviceConfig updates the specified device with the provided config.

func (*Hub) UpdateDeviceState

func (h *Hub) UpdateDeviceState(ctx context.Context, id string, state *DeviceState) (*Device, error)

UpdateDeviceState updates the specified device with the provided state.

func (*Hub) Updates

func (h *Hub) Updates() <-chan *Update

Updates exposes the stream of received changes to the underlying bridges and devices.

type Monitor

type Monitor struct {
	// contains filtered or unexported fields
}

Monitor is used to track bridge discovery updates.

func NewMonitor

func NewMonitor(logger *zap.Logger, handler MonitorHandler, types []string) *Monitor

NewMonitor creates a new monitor

func (*Monitor) LogNonRegisteredTypes

func (m *Monitor) LogNonRegisteredTypes()

LogNonRegisteredTypes enables logging of all received SSDP packets, even if they do not match the registered type filter.

func (*Monitor) Run

func (m *Monitor) Run(ctx context.Context)

Run begins the monitor, which will listen until the context is cancelled.

type MonitorHandler

type MonitorHandler interface {
	Alive(string, string, string)
	GoingAway(string)
}

MonitorHandler describes the methods a monitor can invoke when certain conditions are hit. Alive() is called with the server UUID and connection string when a bridge is found Gone() is called with the bridge ID when a bridge announces it is going away.

type SyncBridge

type SyncBridge interface {
	SetDeviceState(context.Context, *Device, *DeviceState) error
}

SyncBridge is a simplified interface for implementing the domotics Bridge gRPC contract. This allows for rapid implementation of bridge capabilities by simplistic, synchronous libraries which don't require advanced features.

type SyncBridgeService

type SyncBridgeService struct {
	// contains filtered or unexported fields
}

SyncBridgeService provides simplistic, synchronous bridges an easy way to integrate functionality without requiring a complete gRPC server implementation of the domotics Bridge contract. The bridge configured here is typically statically defined, with a pre-set number of devices. This service guards against mis-addressed devices, out-of-range options, etc. and only allows for basic state management. This interface is built under the assumption that this service will be the only thing allowing writes to the underlying bridge, providing guards for serialized calls. It caches device profiles and does not actually query the underlying system.

func NewSyncBridgeService

func NewSyncBridgeService(logger *zap.Logger, brInfo *Bridge, devices map[string]*Device, br SyncBridge) *SyncBridgeService

NewSyncBridgeService takes the supplied bridge and device profiles and takes on management of them. The supplied synchronous bridge interface will be used when the service detects an incoming write which requires a state change in the underlying device.

func (*SyncBridgeService) GetBridge

func (s *SyncBridgeService) GetBridge(ctx context.Context, req *GetBridgeRequest) (*Bridge, error)

GetBridge retrieves the bridge info of this service.

func (*SyncBridgeService) GetDevice

func (s *SyncBridgeService) GetDevice(ctx context.Context, req *GetDeviceRequest) (*Device, error)

GetDevice retrieves the specified device.

func (*SyncBridgeService) ListDevices

func (s *SyncBridgeService) ListDevices(ctx context.Context, req *ListDevicesRequest) (*ListDevicesResponse, error)

ListDevices retrieves all registered devices.

func (*SyncBridgeService) StreamBridgeUpdates

func (s *SyncBridgeService) StreamBridgeUpdates(req *StreamBridgeUpdatesRequest, stream BridgeService_StreamBridgeUpdatesServer) error

StreamBridgeUpdates monitors changes for all changes which occur on the This will only pick up successful device writes.

func (*SyncBridgeService) UpdateDeviceConfig

func (s *SyncBridgeService) UpdateDeviceConfig(ctx context.Context, req *UpdateDeviceConfigRequest) (*Device, error)

UpdateDeviceConfig exists to satisfy the domotics Bridge contract, but is not actually supported.

func (*SyncBridgeService) UpdateDeviceState

func (s *SyncBridgeService) UpdateDeviceState(ctx context.Context, req *UpdateDeviceStateRequest) (*Device, error)

UpdateDeviceState updates the specified device with the provided state.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL