mirror of
https://github.com/sstent/go-garth.git
synced 2026-01-26 00:52:40 +00:00
168 lines
4.4 KiB
Go
168 lines
4.4 KiB
Go
package connect
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// Weightin is a single weight event.
|
|
type Weightin struct {
|
|
Date Date `json:"date"`
|
|
Version int `json:"version"`
|
|
Weight float64 `json:"weight"` // gram
|
|
BMI float64 `json:"bmi"` // weight / height²
|
|
BodyFatPercentage float64 `json:"bodyFat"` // percent
|
|
BodyWater float64 `json:"bodyWater"` // kilogram
|
|
BoneMass int `json:"boneMass"` // gram
|
|
MuscleMass int `json:"muscleMass"` // gram
|
|
SourceType string `json:"sourceType"`
|
|
}
|
|
|
|
// WeightAverage is aggregated weight data for a specific period.
|
|
type WeightAverage struct {
|
|
Weightin
|
|
From int `json:"from"`
|
|
Until int `json:"until"`
|
|
}
|
|
|
|
// LatestWeight will retrieve the latest weight by date.
|
|
func (c *Client) LatestWeight(date time.Time) (*Weightin, error) {
|
|
URL := fmt.Sprintf("https://connect.garmin.com/modern/proxy/weight-service/weight/latest?date=%04d-%02d-%02d",
|
|
date.Year(),
|
|
date.Month(),
|
|
date.Day())
|
|
|
|
wi := new(Weightin)
|
|
|
|
err := c.getJSON(URL, wi)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return wi, nil
|
|
}
|
|
|
|
// Weightins will retrieve all weight ins between startDate and endDate. A
|
|
// summary is provided as well. This summary is calculated by Garmin Connect.
|
|
func (c *Client) Weightins(startDate time.Time, endDate time.Time) (*WeightAverage, []Weightin, error) {
|
|
URL := fmt.Sprintf("https://connect.garmin.com/modern/proxy/weight-service/weight/dateRange?startDate=%s&endDate=%s",
|
|
formatDate(startDate),
|
|
formatDate(endDate))
|
|
|
|
// An alternative endpoint for weight info this can be found here:
|
|
// https://connect.garmin.com/modern/proxy/userprofile-service/userprofile/personal-information/weightWithOutbound?from=1556359100000&until=1556611800000
|
|
|
|
if !c.authenticated() {
|
|
return nil, nil, ErrNotAuthenticated
|
|
}
|
|
|
|
var proxy struct {
|
|
DateWeightList []Weightin `json:"dateWeightList"`
|
|
TotalAverage *WeightAverage `json:"totalAverage"`
|
|
}
|
|
|
|
err := c.getJSON(URL, &proxy)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
return proxy.TotalAverage, proxy.DateWeightList, nil
|
|
}
|
|
|
|
// DeleteWeightin will delete all biometric data for date.
|
|
func (c *Client) DeleteWeightin(date time.Time) error {
|
|
URL := fmt.Sprintf("https://connect.garmin.com/modern/proxy/biometric-service/biometric/%s", formatDate(date))
|
|
|
|
if !c.authenticated() {
|
|
return ErrNotAuthenticated
|
|
}
|
|
|
|
return c.write("DELETE", URL, nil, 204)
|
|
}
|
|
|
|
// AddUserWeight will add a manual weight in. weight is in grams to match
|
|
// Weightin.
|
|
func (c *Client) AddUserWeight(date time.Time, weight float64) error {
|
|
URL := "https://connect.garmin.com/modern/proxy/weight-service/user-weight"
|
|
payload := struct {
|
|
Date string `json:"date"`
|
|
UnitKey string `json:"unitKey"`
|
|
Value float64 `json:"value"`
|
|
}{
|
|
Date: formatDate(date),
|
|
UnitKey: "kg",
|
|
Value: weight / 1000.0,
|
|
}
|
|
|
|
return c.write("POST", URL, payload, 204)
|
|
}
|
|
|
|
// WeightByDate retrieves the weight of date if available. If no weight data
|
|
// for date exists, it will return ErrNotFound.
|
|
func (c *Client) WeightByDate(date time.Time) (Time, float64, error) {
|
|
URL := fmt.Sprintf("https://connect.garmin.com/modern/proxy/biometric-service/biometric/weightByDate?date=%s",
|
|
formatDate(date))
|
|
|
|
if !c.authenticated() {
|
|
return Time{}, 0.0, ErrNotAuthenticated
|
|
}
|
|
|
|
var proxy []struct {
|
|
TimeStamp Time `json:"weightDate"`
|
|
Weight float64 `json:"weight"` // gram
|
|
}
|
|
|
|
err := c.getJSON(URL, &proxy)
|
|
if err != nil {
|
|
return Time{}, 0.0, err
|
|
}
|
|
|
|
if len(proxy) < 1 {
|
|
return Time{}, 0.0, ErrNotFound
|
|
}
|
|
|
|
return proxy[0].TimeStamp, proxy[0].Weight, nil
|
|
}
|
|
|
|
// WeightGoal will list the users weight goal if any. If displayName is empty,
|
|
// the currently authenticated user will be used.
|
|
func (c *Client) WeightGoal(displayName string) (*Goal, error) {
|
|
goals, err := c.Goals(displayName, 4)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(goals) < 1 {
|
|
return nil, ErrNotFound
|
|
}
|
|
|
|
return &goals[0], nil
|
|
}
|
|
|
|
// SetWeightGoal will set a new weight goal.
|
|
func (c *Client) SetWeightGoal(goal int) error {
|
|
if !c.authenticated() || c.Profile == nil {
|
|
return ErrNotAuthenticated
|
|
}
|
|
|
|
g := Goal{
|
|
Created: Today(),
|
|
Start: Today(),
|
|
GoalType: 4,
|
|
ProfileID: c.Profile.ProfileID,
|
|
Value: goal,
|
|
}
|
|
|
|
goals, err := c.Goals("", 4)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if len(goals) >= 1 {
|
|
g.ID = goals[0].ID
|
|
return c.UpdateGoal("", g)
|
|
}
|
|
|
|
return c.AddGoal(c.Profile.DisplayName, g)
|
|
}
|