Skip to content

Commit

Permalink
Issue-7: json: cannot unmarshal number (#8)
Browse files Browse the repository at this point in the history
## Issue:
* #7

## Changes
* Replace int with float64
* Replace sweat drop emoji with droplet emoji
* Update screenshot
* Move fetch/unmarshal to dedicated function
* Add tests for Unmarshal API payloads

## TODO
- [x] Add test cases for different payloads
  • Loading branch information
ljagiello committed Oct 10, 2023
1 parent 4a21c7a commit 4573904
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 27 deletions.
50 changes: 33 additions & 17 deletions airgradient.go
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
package main

import (
"encoding/json"
"errors"
"io"
"net/http"
"time"
)

const AIR_GRADIENT_API_URL = "https://api.airgradient.com/public/api/v1/locations/measures/current"

type AirGradientMeasures []struct {
LocationID int `json:"locationId"`
LocationName string `json:"locationName"`
Pm01 any `json:"pm01"`
Pm02 int `json:"pm02"`
Pm10 any `json:"pm10"`
Pm003Count any `json:"pm003Count"`
Pm01 float64 `json:"pm01"`
Pm02 float64 `json:"pm02"`
Pm10 float64 `json:"pm10"`
Pm003Count float64 `json:"pm003Count"`
Atmp float64 `json:"atmp"`
Rhum int `json:"rhum"`
Rco2 int `json:"rco2"`
Rhum float64 `json:"rhum"`
Rco2 float64 `json:"rco2"`
Tvoc float64 `json:"tvoc"`
Wifi int `json:"wifi"`
Wifi float64 `json:"wifi"`
Timestamp time.Time `json:"timestamp"`
LedMode string `json:"ledMode"`
LedCo2Threshold1 int `json:"ledCo2Threshold1"`
LedCo2Threshold2 int `json:"ledCo2Threshold2"`
LedCo2ThresholdEnd int `json:"ledCo2ThresholdEnd"`
LedCo2Threshold1 float64 `json:"ledCo2Threshold1"`
LedCo2Threshold2 float64 `json:"ledCo2Threshold2"`
LedCo2ThresholdEnd float64 `json:"ledCo2ThresholdEnd"`
Serialno string `json:"serialno"`
FirmwareVersion any `json:"firmwareVersion"`
TvocIndex int `json:"tvocIndex"`
NoxIndex int `json:"noxIndex"`
FirmwareVersion string `json:"firmwareVersion"`
TvocIndex float64 `json:"tvocIndex"`
NoxIndex float64 `json:"noxIndex"`
}

func fetchMeasures(token string) ([]byte, error) {
func fetchMeasures(airGradientAPIUrl string, token string) ([]byte, error) {
client := &http.Client{}

req, err := http.NewRequest("GET", AIR_GRADIENT_API_URL, nil)
req, err := http.NewRequest("GET", airGradientAPIUrl, nil)
if err != nil {
logger.Error("Creating HTTP request", "error", err)
return nil, err
Expand All @@ -59,3 +59,19 @@ func fetchMeasures(token string) ([]byte, error) {

return body, nil
}

func getAirGradientMeasures(airGradientAPIUrl string, token string) (AirGradientMeasures, error) {
payload, err := fetchMeasures(airGradientAPIUrl, token)
if err != nil {
return nil, err
}

var airGradientMeasures AirGradientMeasures

err = json.Unmarshal(payload, &airGradientMeasures)
if err != nil {
return nil, errors.New("Error unmarshalling JSON")
}

return airGradientMeasures, nil
}
46 changes: 46 additions & 0 deletions airgradient_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package main

import (
"errors"
"net/http"
"net/http/httptest"
"testing"

"github.com/stretchr/testify/assert"
)

func TestGetAirGradientMeasures(t *testing.T) {
var testCases = []struct {
name string
payloadFile string
err error
}{
{
"correct-response",
"testdata/correct_response1.json",
nil,
},
{
"correct-response2",
"testdata/correct_response2.json",
nil,
},
{
"incorrect-response",
"testdata/incorrect_response1.json",
errors.New("Error unmarshalling JSON"),
},
}

for _, tC := range testCases {
t.Run(tC.name, func(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, tC.payloadFile)
}))
defer server.Close()

_, err := getAirGradientMeasures(server.URL, "SECRET-TOKEN")
assert.Equal(t, tC.err, err)
})
}
}
16 changes: 6 additions & 10 deletions main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"encoding/json"
"fmt"
"os"
"time"
Expand All @@ -12,6 +11,8 @@ import (
"github.com/progrium/macdriver/objc"
)

const AIR_GRADIENT_API_URL = "https://api.airgradient.com/public/api/v1/locations/measures/current"

func main() {
macos.RunApp(launched)
}
Expand Down Expand Up @@ -45,18 +46,13 @@ func launched(app appkit.Application, delegate *appkit.ApplicationDelegate) {
for {
select {
case <-time.After(time.Duration(cfg.Interval) * time.Second):
payload, err := fetchMeasures(cfg.Token)
airGradientMeasures, err = getAirGradientMeasures(AIR_GRADIENT_API_URL, cfg.Token)
if err != nil {
logger.Error("Fetching measures", "error", err)
return
}

err = json.Unmarshal(payload, &airGradientMeasures)
if err != nil {
logger.Error("Parsing JSON payload", "error", err)
return
continue
}
}

if len(airGradientMeasures) == 0 {
logger.Error("No measurements found")
return
Expand All @@ -71,7 +67,7 @@ func launched(app appkit.Application, delegate *appkit.ApplicationDelegate) {

// updates to the ui should happen on the main thread to avoid segfaults
dispatch.MainQueue().DispatchAsync(func() {
item.Button().SetTitle(fmt.Sprintf("🌡️ %.2f 💨 %d 💦 %d 🫧 %d",
item.Button().SetTitle(fmt.Sprintf("🌡️ %.2f 💨 %.0f 💧 %.1f 🫧 %.0f",
temperature,
airGradientMeasures[0].Pm02,
airGradientMeasures[0].Rhum,
Expand Down
Binary file modified screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions testdata/correct_response1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"locationId":12345,"locationName":"Test Loc","pm01":null,"pm02":4,"pm10":null,"pm003Count":null,"atmp":24.3,"rhum":52,"rco2":548,"tvoc":93.979355,"wifi":-58,"timestamp":"2023-10-10T03:42:11.000Z","ledMode":"co2","ledCo2Threshold1":1000,"ledCo2Threshold2":2000,"ledCo2ThresholdEnd":4000,"serialno":"aabb12","firmwareVersion":null,"tvocIndex":100,"noxIndex":1}]
1 change: 1 addition & 0 deletions testdata/correct_response2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"locationId":12345,"locationName":"Test Loc","pm01":null,"pm02":4,"pm10":null,"pm003Count":null,"atmp":24.3,"rhum":53.5,"rco2":548,"tvoc":93.979355,"wifi":-58,"timestamp":"2023-10-10T03:42:11.000Z","ledMode":"co2","ledCo2Threshold1":1000,"ledCo2Threshold2":2000,"ledCo2ThresholdEnd":4000,"serialno":"aabb12","firmwareVersion":null,"tvocIndex":100,"noxIndex":1}]
10 changes: 10 additions & 0 deletions testdata/incorrect_response1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /public/api/v1/locations/measures/current1</pre>
</body>
</html>

0 comments on commit 4573904

Please sign in to comment.