Skip to content

Commit

Permalink
Refactored CoAP/DTLS into own package and changed some endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
eriklupander committed Mar 8, 2019
1 parent b2cae89 commit 30b84cd
Show file tree
Hide file tree
Showing 6 changed files with 368 additions and 243 deletions.
129 changes: 129 additions & 0 deletions dtlscoap/dtlscoap-client.go
@@ -0,0 +1,129 @@
package dtlscoap

import (
"fmt"
"github.com/dustin/go-coap"
"github.com/eriklupander/dtls"
"github.com/spf13/viper"
"time"
)

// DtlsClient provides an domain-agnostic CoAP-client with DTLS transport.
type DtlsClient struct {
peer *dtls.Peer
msgId uint16
}

// NewDtlsClient acts as factory function, returns a pointer to a connected (or will panic) DtlsClient.
func NewDtlsClient() *DtlsClient {
client := &DtlsClient{}
client.connect()
return client
}

func (dc *DtlsClient) connect() {
setupKeystore()

listener, err := dtls.NewUdpListener(":0", time.Second*900)
if err != nil {
panic(err.Error())
}

gatewayIp := viper.GetString("GATEWAY_IP") + ":5684"

peerParams := &dtls.PeerParams{
Addr: gatewayIp,
Identity: viper.GetString("CLIENT_ID"),
HandshakeTimeout: time.Second * 30}
fmt.Printf("Connecting to peer at %v\n", gatewayIp)

dc.peer, err = listener.AddPeerWithParams(peerParams)
if err != nil {
panic("Unable to connect to Gateway at " + gatewayIp + ": " + err.Error())
}
dc.peer.UseQueue(true)
fmt.Printf("DTLS connection established to %v\n", gatewayIp)
}

// Call writes the supplied coap.Message to the peer
func (dc *DtlsClient) Call(req coap.Message) (coap.Message, error) {
fmt.Printf("Calling %v %v", req.Code.String(), req.PathString())
data, err := req.MarshalBinary()
if err != nil {
return coap.Message{}, err
}
err = dc.peer.Write(data)

if err != nil {
return coap.Message{}, err
}

respData, err := dc.peer.Read(time.Second)
if err != nil {
return coap.Message{}, err
}

msg, err := coap.ParseMessage(respData)
if err != nil {
return coap.Message{}, err
}

fmt.Printf("\nMessageID: %v\n", msg.MessageID)
fmt.Printf("Type: %v\n", msg.Type)
fmt.Printf("Code: %v\n", msg.Code)
fmt.Printf("Token: %v\n", msg.Token)
fmt.Printf("Payload: %v\n", string(msg.Payload))

return msg, nil
}

// BuildGETMessage produces a CoAP GET message with the next msgId set.
func (dc *DtlsClient) BuildGETMessage(path string) coap.Message {
dc.msgId++
req := coap.Message{
Type: coap.Confirmable,
Code: coap.GET,
MessageID: dc.msgId,
}
req.SetPathString(path)
return req
}

//req.SetOption(coap.ETag, "weetag")
//req.SetOption(coap.MaxAge, 3)

// BuildPUTMessage produces a CoAP PUT message with the next msgId set.
func (dc *DtlsClient) BuildPUTMessage(path string, payload string) coap.Message {
dc.msgId++

req := coap.Message{
Type: coap.Confirmable,
Code: coap.PUT,
MessageID: dc.msgId,
Payload: []byte(payload),
}
req.SetPathString(path)

return req
}

// BuildPOSTMessage produces a CoAP POST message with the next msgId set.
func (dc *DtlsClient) BuildPOSTMessage(path string, payload string) coap.Message {
dc.msgId++

req := coap.Message{
Type: coap.Confirmable,
Code: coap.POST,
MessageID: dc.msgId,
Payload: []byte(payload),
}
req.SetPathString(path)

return req
}

func setupKeystore() {
mks := dtls.NewKeystoreInMemory()
dtls.SetKeyStores([]dtls.Keystore{mks})
mks.AddKey(viper.GetString("CLIENT_ID"), []byte(viper.GetString("PRE_SHARED_KEY")))
}
11 changes: 5 additions & 6 deletions main.go
Expand Up @@ -3,7 +3,6 @@ package main
import (
"flag"
"fmt"
"github.com/eriklupander/dtls"
"github.com/eriklupander/tradfri-go/router"
"github.com/eriklupander/tradfri-go/tradfri"
"github.com/spf13/viper"
Expand All @@ -18,7 +17,7 @@ import (
var serverMode, authenticate *bool

func init() {
dtls.SetLogLevel("debug")
// dtls.SetLogLevel("debug")

// read clientId / PSK from file if possible
ok := resolveClientIdAndPSKFromFile()
Expand Down Expand Up @@ -71,7 +70,7 @@ func main() {
handleSigterm(nil)
if *serverMode {
fmt.Println("Running in server mode on :8080")
go router.SetupChi(tradfri.NewDtlsClient())
go router.SetupChi(tradfri.NewTradfriClient())

wg := sync.WaitGroup{}
wg.Add(1)
Expand All @@ -81,10 +80,10 @@ func main() {
if *authenticate {
performTokenExchange(clientId, psk)
} else if *get != "" {
resp, _ := tradfri.NewDtlsClient().Get(*get)
resp, _ := tradfri.NewTradfriClient().Get(*get)
fmt.Printf("%v", string(resp.Payload))
} else if *put != "" {
resp, _ := tradfri.NewDtlsClient().Put(*put, *payload)
resp, _ := tradfri.NewTradfriClient().Put(*put, *payload)
fmt.Printf("%v", string(resp.Payload))
} else {
fmt.Println("No client operation was specified, supported one(s) are: authenticate")
Expand Down Expand Up @@ -112,7 +111,7 @@ func performTokenExchange(clientId *string, psk *string) {
// required when performing token exchange
viper.Set("CLIENT_ID", "Client_identity")
viper.Set("PRE_SHARED_KEY", *psk)
dtlsClient := tradfri.NewDtlsClient()
dtlsClient := tradfri.NewTradfriClient()

authToken, err := dtlsClient.AuthExchange(*clientId)
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions model/models.go
Expand Up @@ -110,3 +110,7 @@ type BulbResponse struct {
RGB string `json:"rgbcolor"`
Powered bool `json:"powered"`
}

type Result struct {
Msg string
}
73 changes: 54 additions & 19 deletions router/router.go
Expand Up @@ -14,10 +14,10 @@ import (
"time"
)

var dtlsClient *tradfri.DtlsClient
var tradfriClient *tradfri.TradfriClient

func SetupChi(client *tradfri.DtlsClient) {
dtlsClient = client
func SetupChi(client *tradfri.TradfriClient) {
tradfriClient = client

r := chi.NewRouter()

Expand All @@ -44,9 +44,11 @@ func SetupChi(client *tradfri.DtlsClient) {
r.Get("/groups/{groupId}/deviceIds", getDeviceIdsOnGroup)
r.Get("/groups/{groupId}/devices", getDevicesOnGroup)
r.Get("/device/{deviceId}", getDevice)
r.Put("/device/{deviceId}/color/{x}/{y}", setColorXY)
r.Put("/device/{deviceId}/color", setColorXY)
r.Put("/device/{deviceId}/rgb", setColorRGBHex)
r.Put("/device/{deviceId}/dimmer/{dimming}", setDimming)
r.Put("/device/{deviceId}/dimmer", setDimming)
r.Put("/device/{deviceId}/power", setPowered)
r.Put("/device/{deviceId}", setState)

})
http.ListenAndServe(":8080", r)
Expand All @@ -59,55 +61,88 @@ func setColorXY(w http.ResponseWriter, r *http.Request) {
yStr := chi.URLParam(r, "y")
x, _ := strconv.Atoi(xStr)
y, _ := strconv.Atoi(yStr)
err := dtlsClient.PutDeviceColor(deviceId, x, y)
respond(w, "{}", err)
res, err := tradfriClient.PutDeviceColor(deviceId, x, y)
respond(w, res, err)
}

type RgbColorRequest struct {
RGBcolor string `json:"rgbcolor"`
}
type DimmingRequest struct {
Dimming int `json:"dimming"`
}
type PowerRequest struct {
Power int `json:"power"`
}

type StateRequest struct {
RGBcolor string `json:"rgbcolor"`
Dimmer int `json:"dimmer"`
Power int `json:"power"`
}

func setColorRGBHex(w http.ResponseWriter, r *http.Request) {
deviceId := chi.URLParam(r, "deviceId")
body, _ := ioutil.ReadAll(r.Body)

rgbColorRequest := RgbColorRequest{}
err := json.Unmarshal(body, &rgbColorRequest)
err = dtlsClient.PutDeviceColorRGB(deviceId, rgbColorRequest.RGBcolor)
respond(w, "{}", err)
result, err := tradfriClient.PutDeviceColorRGB(deviceId, rgbColorRequest.RGBcolor)
respond(w, result, err)
}

func setDimming(w http.ResponseWriter, r *http.Request) {
deviceId := chi.URLParam(r, "deviceId")
dimmingStr := chi.URLParam(r, "dimming")
dimming, _ := strconv.Atoi(dimmingStr)
body, _ := ioutil.ReadAll(r.Body)

dimmingRequest := DimmingRequest{}
err := json.Unmarshal(body, &dimmingRequest)
res, err := tradfriClient.PutDeviceDimming(deviceId, dimmingRequest.Dimming)
respond(w, res, err)
}

func setPowered(w http.ResponseWriter, r *http.Request) {
deviceId := chi.URLParam(r, "deviceId")
body, _ := ioutil.ReadAll(r.Body)

powerRequest := PowerRequest{}
err := json.Unmarshal(body, &powerRequest)
res, err := tradfriClient.PutDevicePower(deviceId, powerRequest.Power)
respond(w, res, err)
}

func setState(w http.ResponseWriter, r *http.Request) {
deviceId := chi.URLParam(r, "deviceId")
body, _ := ioutil.ReadAll(r.Body)

err := dtlsClient.PutDeviceDimming(deviceId, dimming)
respond(w, "{}", err)
stateReq := StateRequest{}
err := json.Unmarshal(body, &stateReq)
res, err := tradfriClient.PutDeviceState(deviceId, stateReq.Power, stateReq.Dimmer, stateReq.RGBcolor)
respond(w, res, err)
}

func listGroups(w http.ResponseWriter, r *http.Request) {
groups, err := dtlsClient.ListGroups()
groups, err := tradfriClient.ListGroups()
respond(w, groups, err)
}

func getGroup(w http.ResponseWriter, r *http.Request) {
group, err := dtlsClient.GetGroup(chi.URLParam(r, "groupId"))
group, err := tradfriClient.GetGroup(chi.URLParam(r, "groupId"))
respond(w, group, err)
}

func getDevicesOnGroup(w http.ResponseWriter, r *http.Request) {
group, _ := dtlsClient.GetGroup(chi.URLParam(r, "groupId"))
group, _ := tradfriClient.GetGroup(chi.URLParam(r, "groupId"))
devices := make([]model.BulbResponse, 0)
for _, deviceID := range group.Content.DeviceList.DeviceIds {
device, _ := dtlsClient.GetDevice(strconv.Itoa(deviceID))
device, _ := tradfriClient.GetDevice(strconv.Itoa(deviceID))
devices = append(devices, model.ToDeviceResponse(device))
}
respondWithJSON(w, 200, devices)
}

func getDeviceIdsOnGroup(w http.ResponseWriter, r *http.Request) {
group, _ := dtlsClient.GetGroup(chi.URLParam(r, "groupId"))
group, _ := tradfriClient.GetGroup(chi.URLParam(r, "groupId"))
deviceIds := make([]int, 0)
for _, deviceID := range group.Content.DeviceList.DeviceIds {
deviceIds = append(deviceIds, deviceID)
Expand All @@ -124,7 +159,7 @@ func respond(w http.ResponseWriter, payload interface{}, err error) {
}

func getDevice(w http.ResponseWriter, r *http.Request) {
device, _ := dtlsClient.GetDevice(chi.URLParam(r, "deviceId"))
device, _ := tradfriClient.GetDevice(chi.URLParam(r, "deviceId"))
respondWithJSON(w, 200, model.ToDeviceResponse(device))
}

Expand Down

0 comments on commit 30b84cd

Please sign in to comment.