X-Git-Url: https://git.octo.it/?p=kraftakt.git;a=blobdiff_plain;f=fitbit%2Fsleep.go;h=a9129386ac93df960e7e048363c2957cf6555e1c;hp=76fc197d528171bc213d12b32d50ac63b9bb80c2;hb=HEAD;hpb=0760c07303a8b8a78a4858e7331d3189f3d83af3 diff --git a/fitbit/sleep.go b/fitbit/sleep.go index 76fc197..a912938 100644 --- a/fitbit/sleep.go +++ b/fitbit/sleep.go @@ -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 = 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,17 +108,19 @@ 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 } -// Sleep returns the sleep log for date. Times are parsed in the user's timeozne, loc. -func (c *Client) Sleep(ctx context.Context, date string, loc *time.Location) (*Sleep, error) { +// Sleep returns the sleep log for date t. Times are parsed in the same timezone as t. +func (c *Client) Sleep(ctx context.Context, t time.Time) (*Sleep, error) { url := fmt.Sprintf("https://api.fitbit.com/1.2/user/%s/sleep/date/%s.json", - c.fitbitUserID, date) + c.fitbitUserID, t.Format("2006-01-02")) res, err := c.client.Get(url) if err != nil { @@ -118,5 +134,5 @@ func (c *Client) Sleep(ctx context.Context, date string, loc *time.Location) (*S } log.Debugf(ctx, "GET %s -> %s", url, data) - return parseSleep(ctx, data, loc) + return parseSleep(ctx, data, t.Location()) }