Write step count summary to Google Fit.
[kraftakt.git] / gfit / gfit.go
index 028eee0..ed8f7cb 100644 (file)
@@ -4,11 +4,14 @@ import (
        "context"
        "fmt"
        "net/http"
+       "time"
 
        "github.com/octo/gfitsync/app"
        "golang.org/x/oauth2"
        oauth2google "golang.org/x/oauth2/google"
        fitness "google.golang.org/api/fitness/v1"
+       "google.golang.org/appengine"
+       "google.golang.org/appengine/log"
 )
 
 var oauthConfig = &oauth2.Config{
@@ -24,6 +27,14 @@ var oauthConfig = &oauth2.Config{
 
 const csrfToken = "@CSRFTOKEN@"
 
+func Application(ctx context.Context) *fitness.Application {
+       return &fitness.Application{
+               Name:       "Fitbit to Google Fit sync",
+               Version:    appengine.VersionID(ctx),
+               DetailsUrl: "", // optional
+       }
+}
+
 func AuthURL() string {
        return oauthConfig.AuthCodeURL(csrfToken, oauth2.AccessTypeOffline)
 }
@@ -60,3 +71,58 @@ func NewClient(ctx context.Context, u *app.User) (*Client, error) {
                Service: service,
        }, nil
 }
+
+func (c *Client) SetSteps(ctx context.Context, steps int, date time.Time) error {
+       const userID = "me"
+       const dataTypeName = "com.google.step_count.delta"
+       dataSource := &fitness.DataSource{
+               Application:    Application(ctx),
+               DataStreamName: "", // "daily summary"?
+               DataType: &fitness.DataType{
+                       Field: []*fitness.DataTypeField{
+                               &fitness.DataTypeField{
+                                       Format: "integer",
+                                       Name:   "steps",
+                               },
+                       },
+                       Name: dataTypeName,
+               },
+               Name: "Step Count",
+               Type: "raw",
+       }
+
+       dataSource, err := c.Service.Users.DataSources.Create(userID, dataSource).Context(ctx).Do()
+       if err != nil {
+               log.Errorf(ctx, "c.Service.Users.DataSources.Create() = (%+v, %v)", dataSource, err)
+               return err
+       }
+       dataSourceID := dataSource.DataStreamId
+
+       startTimeNanos := date.UnixNano()
+       endTimeNanos := date.Add(86399999999999 * time.Nanosecond).UnixNano()
+       datasetID := fmt.Sprintf("%d-%d", startTimeNanos, endTimeNanos)
+       dataset := &fitness.Dataset{
+               MinStartTimeNs: startTimeNanos,
+               MaxEndTimeNs:   endTimeNanos,
+               Point: []*fitness.DataPoint{
+                       &fitness.DataPoint{
+                               ComputationTimeMillis: time.Now().UnixNano() / 1000000,
+                               DataTypeName:          dataTypeName,
+                               StartTimeNanos:        startTimeNanos,
+                               EndTimeNanos:          endTimeNanos,
+                               Value: []*fitness.Value{
+                                       &fitness.Value{
+                                               IntVal: int64(steps),
+                                       },
+                               },
+                       },
+               },
+       }
+
+       dataset, err = c.Service.Users.DataSources.Datasets.Patch(userID, dataSourceID, datasetID, dataset).Context(ctx).Do()
+       if err != nil {
+               log.Errorf(ctx, "c.Service.Users.DataSources.Datasets.Patch() = (%+v, %v)", dataset, err)
+               return err
+       }
+       return nil
+}