Skip to content

Commit

Permalink
Merge pull request hybridgroup#161 from hybridgroup/variables-and-fun…
Browse files Browse the repository at this point in the history
…ctions

Variables and functions for spark adaptor
  • Loading branch information
zankich committed Dec 28, 2014
2 parents 944b878 + 51feaa9 commit 1b57112
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 19 deletions.
31 changes: 31 additions & 0 deletions examples/spark_core_function.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package main

import (
"fmt"

"github.com/hybridgroup/gobot"
"github.com/hybridgroup/gobot/platforms/spark"
)

func main() {
gbot := gobot.NewGobot()

sparkCore := spark.NewSparkCoreAdaptor("spark", "DEVICE_ID", "ACCESS_TOKEN")

work := func() {
if result, err := sparkCore.Function("brew", "202,230"); err != nil {
fmt.Println(err)
} else {
fmt.Println("result from \"brew\":", result)
}
}

robot := gobot.NewRobot("spark",
[]gobot.Connection{sparkCore},
work,
)

gbot.AddRobot(robot)

gbot.Start()
}
34 changes: 34 additions & 0 deletions examples/spark_core_variable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main

import (
"fmt"
"time"

"github.com/hybridgroup/gobot"
"github.com/hybridgroup/gobot/platforms/spark"
)

func main() {
gbot := gobot.NewGobot()

sparkCore := spark.NewSparkCoreAdaptor("spark", "DEVICE_ID", "ACCESS_TOKEN")

work := func() {
gobot.Every(1*time.Second, func() {
if temp, err := sparkCore.Variable("temperature"); err != nil {
fmt.Println(err)
} else {
fmt.Println("result from \"temperature\" is:", temp)
}
})
}

robot := gobot.NewRobot("spark",
[]gobot.Connection{sparkCore},
work,
)

gbot.AddRobot(robot)

gbot.Start()
}
74 changes: 61 additions & 13 deletions platforms/spark/spark_core_adaptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io/ioutil"
"net/http"
"net/url"
"strconv"

"github.com/hybridgroup/gobot"
"github.com/hybridgroup/gobot/platforms/gpio"
Expand Down Expand Up @@ -57,7 +58,7 @@ func (s *SparkCoreAdaptor) AnalogRead(pin string) (val int, err error) {

url := fmt.Sprintf("%v/analogread", s.deviceURL())

resp, err := s.postToSpark(url, params)
resp, err := s.requestToSpark("POST", url, params)
if err == nil {
val = int(resp["return_value"].(float64))
return
Expand All @@ -78,7 +79,7 @@ func (s *SparkCoreAdaptor) AnalogWrite(pin string, level byte) (err error) {
"access_token": {s.AccessToken},
}
url := fmt.Sprintf("%v/analogwrite", s.deviceURL())
_, err = s.postToSpark(url, params)
_, err = s.requestToSpark("POST", url, params)
return
}

Expand All @@ -89,7 +90,7 @@ func (s *SparkCoreAdaptor) DigitalWrite(pin string, level byte) (err error) {
"access_token": {s.AccessToken},
}
url := fmt.Sprintf("%v/digitalwrite", s.deviceURL())
_, err = s.postToSpark(url, params)
_, err = s.requestToSpark("POST", url, params)
return err
}

Expand All @@ -100,14 +101,57 @@ func (s *SparkCoreAdaptor) DigitalRead(pin string) (val int, err error) {
"access_token": {s.AccessToken},
}
url := fmt.Sprintf("%v/digitalread", s.deviceURL())
resp, err := s.postToSpark(url, params)
resp, err := s.requestToSpark("POST", url, params)
if err == nil {
val = int(resp["return_value"].(float64))
return
}
return -1, err
}

// Variable returns a core variable value as a string
func (s *SparkCoreAdaptor) Variable(name string) (result string, err error) {
url := fmt.Sprintf("%v/%s?access_token=%s", s.deviceURL(), name, s.AccessToken)
resp, err := s.requestToSpark("GET", url, nil)

if err != nil {
return
}

val := resp["result"]
switch val.(type) {
case bool:
result = strconv.FormatBool(val.(bool))
case float64:
result = strconv.FormatFloat(val.(float64), 'f', -1, 64)
case string:
result = val.(string)
}

return
}

// Function executes a core function and
// returns value from request.
// Takes a String as the only argument and returns an Int.
// If function is not defined in core, it will time out
func (s *SparkCoreAdaptor) Function(name string, args string) (val int, err error) {
params := url.Values{
"args": {args},
"access_token": {s.AccessToken},
}

url := fmt.Sprintf("%s/%s", s.deviceURL(), name)
resp, err := s.requestToSpark("POST", url, params)

if err != nil {
return -1, err
}

val = int(resp["return_value"].(float64))
return
}

// setAPIServer sets spark cloud api server, this can be used to change from default api.spark.io
func (s *SparkCoreAdaptor) setAPIServer(server string) {
s.APIServer = server
Expand All @@ -129,10 +173,17 @@ func (s *SparkCoreAdaptor) pinLevel(level byte) string {
return "LOW"
}

// postToSpark makes POST request to spark cloud server, return err != nil if there is
// requestToSpark makes request to spark cloud server, return err != nil if there is
// any issue with the request.
func (s *SparkCoreAdaptor) postToSpark(url string, params url.Values) (m map[string]interface{}, err error) {
resp, err := http.PostForm(url, params)
func (s *SparkCoreAdaptor) requestToSpark(method string, url string, params url.Values) (m map[string]interface{}, err error) {
var resp *http.Response

if method == "POST" {
resp, err = http.PostForm(url, params)
} else if method == "GET" {
resp, err = http.Get(url)
}

if err != nil {
return
}
Expand All @@ -146,12 +197,9 @@ func (s *SparkCoreAdaptor) postToSpark(url string, params url.Values) (m map[str
json.Unmarshal(buf, &m)

if resp.Status != "200 OK" {
if _, ok := m["error"]; ok {
err = errors.New(m["error"].(string))
} else {
err = errors.New(fmt.Sprintf("&v: error communicating to the spark cloud", resp.Status))
}
return
err = errors.New(fmt.Sprintf("&v: error communicating to the spark cloud", resp.Status))
} else if _, ok := m["error"]; ok {
err = errors.New(m["error"].(string))
}

return
Expand Down
90 changes: 84 additions & 6 deletions platforms/spark/spark_core_adaptor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func TestNewSparkCoreAdaptor(t *testing.T) {
}

gobot.Assert(t, spark.APIServer, "https://api.spark.io")
gobot.Assert(t, spark.Name(), "bot")
}

func TestSparkCoreAdaptorConnect(t *testing.T) {
Expand Down Expand Up @@ -110,7 +111,6 @@ func TestSparkCoreAdaptorAnalogRead(t *testing.T) {

val, _ = a.AnalogRead("A1")
gobot.Assert(t, val, 0)

}

func TestSparkCoreAdaptorPwmWrite(t *testing.T) {
Expand Down Expand Up @@ -195,8 +195,86 @@ func TestSparkCoreAdaptorDigitalRead(t *testing.T) {
gobot.Assert(t, val, -1)
}

func TestSparkCoreAdaptorSetAPIServer(t *testing.T) {
func TestSparkCoreAdaptorFunction(t *testing.T) {
response := `{"return_value": 1}`

a := initTestSparkCoreAdaptor()
testServer := getDummyResponseForPath("/"+a.DeviceID+"/hello", response, t)

a.setAPIServer(testServer.URL)

val, _ := a.Function("hello", "100,200")
gobot.Assert(t, val, 1)
testServer.Close()

// When not existent
response = `{"ok": false, "error": "timeout"}`
testServer = getDummyResponseForPath("/"+a.DeviceID+"/hello", response, t)

a.setAPIServer(testServer.URL)

_, err := a.Function("hello", "")
gobot.Assert(t, err.Error(), "timeout")

testServer.Close()
}

func TestSparkCoreAdaptorVariable(t *testing.T) {
// When String
response := `{"result": "1"}`

a := initTestSparkCoreAdaptor()
testServer := getDummyResponseForPath("/"+a.DeviceID+"/variable_name", response, t)

a.setAPIServer(testServer.URL)

val, _ := a.Variable("variable_name")
gobot.Assert(t, val, "1")
testServer.Close()

// When float
response = `{"result": 1.1}`
testServer = getDummyResponseForPath("/"+a.DeviceID+"/variable_name", response, t)

a.setAPIServer(testServer.URL)

val, _ = a.Variable("variable_name")
gobot.Assert(t, val, "1.1")
testServer.Close()

// When int
response = `{"result": 1}`
testServer = getDummyResponseForPath("/"+a.DeviceID+"/variable_name", response, t)

a.setAPIServer(testServer.URL)

val, _ = a.Variable("variable_name")
gobot.Assert(t, val, "1")
testServer.Close()

// When bool
response = `{"result": true}`
testServer = getDummyResponseForPath("/"+a.DeviceID+"/variable_name", response, t)

a.setAPIServer(testServer.URL)

val, _ = a.Variable("variable_name")
gobot.Assert(t, val, "true")
testServer.Close()

// When not existent
response = `{"ok": false, "error": "Variable not found"}`
testServer = getDummyResponseForPath("/"+a.DeviceID+"/not_existent", response, t)

a.setAPIServer(testServer.URL)

_, err := a.Variable("not_existent")
gobot.Assert(t, err.Error(), "Variable not found")

testServer.Close()
}

func TestSparkCoreAdaptorSetAPIServer(t *testing.T) {
a := initTestSparkCoreAdaptor()
apiServer := "new_api_server"
gobot.Refute(t, a.APIServer, apiServer)
Expand Down Expand Up @@ -234,9 +312,9 @@ func TestSparkCoreAdaptorPostToSpark(t *testing.T) {
// When error on request
vals := url.Values{}
vals.Add("error", "error")
resp, err := a.postToSpark("http://invalid%20host.com", vals)
resp, err := a.requestToSpark("POST", "http://invalid%20host.com", vals)
if err == nil {
t.Errorf("postToSpark() should return an error when request was unsuccessful but returned", resp)
t.Errorf("requestToSpark() should return an error when request was unsuccessful but returned", resp)
}

// When error reading body
Expand All @@ -248,9 +326,9 @@ func TestSparkCoreAdaptorPostToSpark(t *testing.T) {
})
defer testServer.Close()

resp, err = a.postToSpark(testServer.URL+"/existent", vals)
resp, err = a.requestToSpark("POST", testServer.URL+"/existent", vals)
if err == nil {
t.Errorf("postToSpark() should return an error when status is not 200 but returned", resp)
t.Errorf("requestToSpark() should return an error when status is not 200 but returned", resp)
}

}

0 comments on commit 1b57112

Please sign in to comment.