Documentation ¶
Overview ¶
Package sense implements a high-level client for the UNSUPPORTED Sense Energy API.
WARNING: Sense does not provide a supported API. This package may stop working without notice.
Example ¶
package main import ( "context" "fmt" "log" "github.com/dnesting/sense" "github.com/dnesting/sense/realtime" ) func main() { ctx := context.Background() client, err := sense.Connect(ctx, sense.PasswordCredentials{ Email: "you@example.com", Password: "secret", }) if err != nil { log.Fatal(err) } fmt.Println("Monitors configured under account", client.AccountID) for _, m := range client.Monitors { fmt.Println("-", m.ID) // Use the realtime Stream API to grab one data point. fn := func(_ context.Context, msg realtime.Message) error { if rt, ok := msg.(*realtime.RealtimeUpdate); ok { fmt.Println(" current power consumption", rt.W, "W") return realtime.Stop } return nil } if err := client.Stream(ctx, m.ID, fn); err != nil { log.Fatal(err) } } }
Output:
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrAuthenticationNeeded = client.ErrAuthenticationNeeded
ErrAuthenticationNeeded is wrapped by errors returned from many functions in this package whenever authentication is needed and the client is unauthenticated or its credentials are no longer valid.
Test for this using errors.Is(err, sense.ErrAuthenticationNeeded).
Functions ¶
Types ¶
type Client ¶
type Client struct { // Account fields are set after successful authentication. UserID int AccountID int Monitors []Monitor // contains filtered or unexported fields }
Client is the primary high-level object used to interact with the Sense API. It represents an "account", which can have some number of Monitors. Instantiate a Client using New or Connect.
func Connect ¶
Connect instantiates a new Sense Client, configured with the provided options.
If credentials are provided, the client will be authenticated using those credentials. Otherwise it will be unauthenticated and will have limited abilities. This function is equivalent to calling New (opts...), possibly followed by Client.Authenticate (ctx).
Example ¶
package main import ( "context" "log" "github.com/dnesting/sense" ) func doSomethingWith(c *sense.Client) {} func main() { client, err := sense.Connect( context.Background(), sense.PasswordCredentials{ Email: "you@example.com", Password: "secret", }) if err != nil { log.Fatal(err) } doSomethingWith(client) }
Output:
Example (WithMFA) ¶
package main import ( "context" "log" "github.com/dnesting/sense" ) func doSomethingWith(c *sense.Client) {} func main() { mfaFunc := func(_ context.Context) (string, error) { // obtain your MFA code somehow, we'll just use a fixed value to demonstrate return "12345", nil } client, err := sense.Connect( context.Background(), sense.PasswordCredentials{ Email: "you@example.com", Password: "secret", MfaFn: mfaFunc, // <-- }) if err != nil { log.Fatal(err) } doSomethingWith(client) }
Output:
func New ¶
New creates a new unauthenticated Sense client, configured according to the provided options.
Most callers will prefer to use Connect instead.
func (*Client) Authenticate ¶
func (s *Client) Authenticate(ctx context.Context, creds Credentials) error
Authenticate authenticates the client using the provided credentials. If the client was previously authenticated (including with Connect), those credentials will be replaced. If creds is nil, the client will be unauthenticated.
See the senseauth package if you need more direct control over how the user is authenticated. This package can generate an HTTP client that you can use here with WithHttpClient.
func (*Client) GetDevices ¶
func (s *Client) GetDevices(ctx context.Context, monitorID int, includeMerged bool) (devs []Device, err error)
GetDevices returns a list of devices known to the given monitor.
func (*Client) Stream ¶
Stream begins streaming real-time data via callback. If the callback returns realtime.Stop, the stream will be closed and this function will return without error. Otherwise, if any other error occurs, it will be returned.
Example ¶
package main import ( "context" "fmt" "io" "net/http" "os" "strings" "github.com/dnesting/sense" "github.com/dnesting/sense/internal/senseutil" "github.com/dnesting/sense/realtime" ) func mockForExample() []sense.Option { type mockMsg = senseutil.RTMsg ch := make(chan mockMsg) go func() { ch <- mockMsg{M: &realtime.Hello{}, E: nil} ch <- mockMsg{M: &realtime.RealtimeUpdate{W: 590.4}, E: nil} ch <- mockMsg{M: &realtime.RealtimeUpdate{W: 591.4}, E: nil} ch <- mockMsg{M: &realtime.RealtimeUpdate{W: 592.4}, E: nil} ch <- mockMsg{M: &realtime.RealtimeUpdate{W: 593.4}, E: nil} close(ch) }() return []sense.Option{ sense.WithInternalClient(nil, &senseutil.MockRTClient{Ch: ch}), sense.WithHttpClient(&http.Client{ Transport: &senseutil.MockTransport{ RT: func(req *http.Request) (*http.Response, error) { fmt.Fprintln(os.Stderr, req.Method, req.URL) return &http.Response{ StatusCode: http.StatusOK, Header: http.Header{"Content-Type": []string{"application/json"}}, Body: io.NopCloser(strings.NewReader(`{"access_token":"fake-token"}`)), }, nil }, }, })} } func main() { // instantiate a Sense client (error checking omitted) client, _ := sense.Connect( context.Background(), sense.PasswordCredentials{ Email: "test@example.com", Password: "pass", }, mockForExample()...) // start a stream and collect 3 data points stopAfter := 3 client.Stream( context.Background(), 123, // monitor ID to stream events from func(_ context.Context, msg realtime.Message) error { switch msg := msg.(type) { case *realtime.Hello: fmt.Println("We're online!") case *realtime.RealtimeUpdate: fmt.Printf("Power consumption is now: %.1f W\n", msg.W) stopAfter-- if stopAfter == 0 { return realtime.Stop } } return nil }) }
Output: We're online! Power consumption is now: 590.4 W Power consumption is now: 591.4 W Power consumption is now: 592.4 W
type Credentials ¶
type Credentials interface {
// contains filtered or unexported methods
}
Credentials holds the credentials used to authenticate to the Sense API. The only implementation of this is PasswordCredentials.
type Monitor ¶
Monitor is a Sense monitor, which is a physical device that measures power usage. One account can have multiple Monitors.
type Option ¶
type Option func(*newOptions)
Option is a function that can be passed to New or Connect to configure the resulting Client.
func WithApiUrl ¶
WithApiUrl sets the base URLs for the Sense API. If this option is not provided, the standard production API URLs will be used (https://api.sense.com/apiservice/api/v1/).
func WithDeviceID ¶
WithDeviceID sets the X-Sense-Device-Id header on requests to the Sense API. This appears to be intended to be a unique identifier for the client installation. If this option is not provided, a random value will be generated and used for all clients for the life of this process. Set this value to "" explicitly to disable this header.
func WithHttpClient ¶
WithHttpClient sets the HTTP client used to make requests to the Sense API. If this option is not provided, http.DefaultClient will be used.
This option can be useful if you need special handling for proxies or TLS certificates, or if you have your own approach to authenticating with Sense.
func WithInternalClient
deprecated
func WithInternalClient(cl internalClient, acl internalRealtimeClient) Option
WithInternalClient is for internal use. All other options will be ignored.
Deprecated: For internal use.
func WithRateLimit ¶
WithRateLimit applies a rate limit to requests made to the Sense API. Without this option, a default rate limit of 10 requests/second will be applied. You can disable rate limiting by providing a limit of 0.
type PasswordCredentials ¶
type PasswordCredentials struct { Email string Password string MfaFn func(ctx context.Context) (string, error) }
PasswordCredentials holds the credentials used to authenticate to the Sense API.
MfaFn is an optional function that will be called (if it is provided) if the Sense API requests an MFA code for the account. It should return the MFA code. If it returns an error, authentication will fail with that error.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
cmd
|
|
dummy
This is a dummy command used to do a basic test that the package is working correctly.
|
This is a dummy command used to do a basic test that the package is working correctly. |
internal
|
|
client
Package client provides primitives to interact with the openapi HTTP API.
|
Package client provides primitives to interact with the openapi HTTP API. |
ratelimited
Package ratelimited provides a rate-limited HTTP client.
|
Package ratelimited provides a rate-limited HTTP client. |
Package realtime implements the unofficial and unsupported Sense real-time API.
|
Package realtime implements the unofficial and unsupported Sense real-time API. |
Package senseauth implements the api.sense.com OAuth flow.
|
Package senseauth implements the api.sense.com OAuth flow. |
Package sensecli just contains some helpers used to set up binaries that need Sense credentials.
|
Package sensecli just contains some helpers used to set up binaries that need Sense credentials. |