Skip to content

Commit

Permalink
Merge pull request #2 from mctofu/percentage
Browse files Browse the repository at this point in the history
Basic support for PercentageController
  • Loading branch information
mctofu authored Feb 8, 2021
2 parents cc2f77e + e61ca66 commit 2b0999d
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 9 deletions.
14 changes: 14 additions & 0 deletions alexa/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,20 @@ func AuthorizationHandler(clientID, clientSecret string,
}
}

// PercentageControllerHandler routes handling of set & adjust directives
func PercentageControllerHandler(setPct, adjustPct Handler) HandlerFunc {
return func(ctx context.Context, req *Request) (*Response, error) {
switch req.Directive.Header.Name {
case "SetPercentage":
return setPct.HandleRequest(ctx, req)
case "AdjustPercentage":
return adjustPct.HandleRequest(ctx, req)
default:
return nil, fmt.Errorf("PercentageControllerHandler: unexpected name: %s", req.Directive.Header.Name)
}
}
}

// PowerControllerHandler routes turn on & off requests
func PowerControllerHandler(turnOn, turnOff Handler) HandlerFunc {
return func(ctx context.Context, req *Request) (*Response, error) {
Expand Down
30 changes: 21 additions & 9 deletions alexa/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,13 @@ type ResponseContext struct {

// Namespace enums
const (
NamespaceAlexa = "Alexa"
NamespaceAuthorization = "Alexa.Authorization"
NamespaceDiscovery = "Alexa.Discovery"
NamespacePowerController = "Alexa.PowerController"
NamespaceSceneController = "Alexa.SceneController"
NamespaceTemperatureSensor = "Alexa.TemperatureSensor"
NamespaceAlexa = "Alexa"
NamespaceAuthorization = "Alexa.Authorization"
NamespaceDiscovery = "Alexa.Discovery"
NamespacePercentageController = "Alexa.PercentageController"
NamespacePowerController = "Alexa.PowerController"
NamespaceSceneController = "Alexa.SceneController"
NamespaceTemperatureSensor = "Alexa.TemperatureSensor"
)

type ContextProperty struct {
Expand All @@ -83,16 +84,19 @@ type ResponseEndpoint struct {
const (
DisplayCategoryActivityTrigger = "ACTIVITY_TRIGGER"
DisplayCategoryDoor = "DOOR"
DisplayCategoryExteriorBlind = "EXTERIOR_BLIND"
DisplayCategoryInteriorBlind = "INTERIOR_BLIND"
DisplayCategorySwitch = "SWITCH"
DisplayCategoryTemperatureSensor = "TEMPERATURE_SENSOR"
DisplayCategoryOther = "OTHER"
)

// Interface enums
const (
InterfaceTemperatureSensor = NamespaceTemperatureSensor
InterfacePowerController = NamespacePowerController
InterfaceSceneController = NamespaceSceneController
InterfacePercentageController = NamespacePercentageController
InterfacePowerController = NamespacePowerController
InterfaceSceneController = NamespaceSceneController
InterfaceTemperatureSensor = NamespaceTemperatureSensor
)

// EmptyPayload is a payload with no content
Expand Down Expand Up @@ -155,3 +159,11 @@ type TemperatureValue struct {
Value float32 `json:"value"`
Scale string `json:"scale"`
}

type SetPercentagePayload struct {
Percentage uint8 `json:"percentage"`
}

type AdjustPercentagePayload struct {
PercentageDelta int8 `json:"percentageDelta"`
}
24 changes: 24 additions & 0 deletions example/lambda/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ func main() {
userIDReader := &alexa.ProfileUserIDReader{HTTPDoer: http.DefaultClient}

mux := alexa.NewNamespaceMux()
mux.HandleFunc(alexa.NamespacePercentageController, alexa.DeferredRelayHandler(sqsRelay, respBuilder))
mux.HandleFunc(alexa.NamespacePowerController, alexa.DeferredRelayHandler(sqsRelay, respBuilder))
mux.HandleFunc(alexa.NamespaceDiscovery, alexa.StaticDiscoveryHandler(respBuilder, endpoints()...))
mux.HandleFunc(alexa.NamespaceAlexa, tempReader.GetTemperature)
Expand Down Expand Up @@ -116,6 +117,29 @@ func endpoints() []alexa.DiscoverEndpoint {
},
},
},
{
EndpointID: "window-1",
FriendlyName: "Window",
Description: "Window control",
ManufacturerName: "McTofu",
DisplayCategories: []string{alexa.DisplayCategoryOther},
Capabilities: []alexa.DiscoverCapability{
{
Type: "AlexaInterface",
Interface: alexa.InterfacePercentageController,
Version: "3",
Properties: &alexa.DiscoverProperties{
Supported: []alexa.DiscoverProperty{
{
Name: "percentage",
},
},
ProactivelyReported: false,
Retrievable: true,
},
},
},
},
}
}

Expand Down
51 changes: 51 additions & 0 deletions example/sqsagent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
Expand Down Expand Up @@ -47,8 +48,13 @@ func main() {
respBuilder := alexa.NewResponseBuilder()

fanSwitch := fanSwitch{respBuilder}
windowControl := windowControl{respBuilder}

mux := alexa.NewNamespaceMux()
mux.Handle(alexa.NamespacePercentageController,
alexa.PercentageControllerHandler(
alexa.HandlerFunc(windowControl.SetPercentage),
alexa.HandlerFunc(windowControl.AdjustPercentage)))
mux.Handle(alexa.NamespacePowerController,
alexa.PowerControllerHandler(
alexa.HandlerFunc(fanSwitch.TurnOn),
Expand Down Expand Up @@ -139,3 +145,48 @@ func (f fanSwitch) TurnOff(ctx context.Context, req *alexa.Request) (*alexa.Resp
UncertaintyInMilliseconds: 500,
}), nil
}

type windowControl struct {
respBuilder *alexa.ResponseBuilder
}

func (w *windowControl) SetPercentage(ctx context.Context, req *alexa.Request) (*alexa.Response, error) {
var targetPct alexa.SetPercentagePayload
if err := json.Unmarshal(req.Directive.Payload, &targetPct); err != nil {
return nil, fmt.Errorf("windowControl.SetPercentage: invalid payload: %v", err)
}
fmt.Printf("SetPercentage: %d\n", targetPct.Percentage)

return w.respBuilder.BasicResponse(req, alexa.ContextProperty{
Namespace: alexa.NamespacePercentageController,
Name: "percentage",
Value: w.marshalValue(targetPct.Percentage),
TimeOfSample: time.Now(),
UncertaintyInMilliseconds: 500,
}), nil
}

func (w *windowControl) AdjustPercentage(ctx context.Context, req *alexa.Request) (*alexa.Response, error) {
var adjustPct alexa.AdjustPercentagePayload
if err := json.Unmarshal(req.Directive.Payload, &adjustPct); err != nil {
return nil, fmt.Errorf("windowControl.AdjustPercentage: invalid payload: %v", err)
}
fmt.Printf("AdjustPercentage: %d\n", adjustPct.PercentageDelta)

return w.respBuilder.BasicResponse(req, alexa.ContextProperty{
Namespace: alexa.NamespacePercentageController,
Name: "percentage",
Value: w.marshalValue(50),
TimeOfSample: time.Now(),
UncertaintyInMilliseconds: 500,
}), nil
}

func (w *windowControl) marshalValue(val uint8) json.RawMessage {
jsonVal, err := json.Marshal(val)
if err != nil {
panic(fmt.Sprintf("unexpected error: %v", err))
}

return jsonVal
}

0 comments on commit 2b0999d

Please sign in to comment.