Package fitbit: Fix parsing of sleep data.
[kraftakt.git] / fitbit / sleep.go
index d7da138..a912938 100644 (file)
@@ -5,6 +5,7 @@ import (
        "encoding/json"
        "fmt"
        "io/ioutil"
+       "sort"
        "time"
 
        "google.golang.org/appengine/log"
@@ -43,29 +44,42 @@ type Sleep struct {
        Stages []SleepStage
 }
 
+type byTime []SleepStage
+
+func (t byTime) Len() int           { return len(t) }
+func (t byTime) Less(i, j int) bool { return t[i].StartTime.Before(t[j].StartTime) }
+func (t byTime) Swap(i, j int)      { t[i], t[j] = t[j], t[i] }
+
 func parseSleep(ctx context.Context, data []byte, loc *time.Location) (*Sleep, error) {
        type rawData struct {
                DateTime string
                Level    string
                Seconds  int64
        }
-       var jsonSleep struct {
-               Levels struct {
-                       Data      []rawData
-                       ShortData []rawData
+       var parsed struct {
+               Sleep []struct {
+                       Levels struct {
+                               Data      []rawData
+                               ShortData []rawData
+                       }
                }
        }
-       if err := json.Unmarshal(data, &jsonSleep); err != nil {
+       if err := json.Unmarshal(data, &parsed); err != nil {
                return nil, err
        }
 
-       rawStages := jsonSleep.Levels.Data
-       if len(jsonSleep.Levels.ShortData) != 0 {
-               rawStages = append(rawStages, jsonSleep.Levels.ShortData...)
+       var allStages []rawData
+       for _, s := range parsed.Sleep {
+               if len(s.Levels.Data) != 0 {
+                       allStages = append(allStages, s.Levels.Data...)
+               }
+               if len(s.Levels.ShortData) != 0 {
+                       allStages = append(allStages, s.Levels.ShortData...)
+               }
        }
 
        var ret Sleep
-       for _, stg := range rawStages {
+       for _, stg := range allStages {
                tm, err := time.ParseInLocation("2006-01-02T15:04:05.999", stg.DateTime, loc)
                if err != nil {
                        log.Warningf(ctx, "unable to parse time: %q", stg.DateTime)
@@ -94,10 +108,12 @@ func parseSleep(ctx context.Context, data []byte, loc *time.Location) (*Sleep, e
                })
        }
 
-       if len(ret.Stages) == 0 && len(jsonSleep.Levels.Data) != 0 {
+       if len(ret.Stages) == 0 && len(allStages) != 0 {
                return nil, fmt.Errorf("parsing sleep stages failed")
        }
 
+       sort.Sort(byTime(ret.Stages))
+
        return &ret, nil
 }