mirror of
https://github.com/sstent/go-garth-cli.git
synced 2025-12-06 08:02:01 +00:00
190 lines
9.2 KiB
Go
190 lines
9.2 KiB
Go
package connect
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// DateValue is a numeric value recorded on a given date.
|
|
type DateValue struct {
|
|
Date Date `json:"calendarDate"`
|
|
Value float64 `json:"value"`
|
|
}
|
|
|
|
// DailySummaries provides a daily summary of various statistics for multiple
|
|
// days.
|
|
type DailySummaries struct {
|
|
Start time.Time `json:"statisticsStartDate"`
|
|
End time.Time `json:"statisticsEndDate"`
|
|
TotalSteps []DateValue `json:"WELLNESS_TOTAL_STEPS"`
|
|
ActiveCalories []DateValue `json:"COMMON_ACTIVE_CALORIES"`
|
|
FloorsAscended []DateValue `json:"WELLNESS_FLOORS_ASCENDED"`
|
|
IntensityMinutes []DateValue `json:"WELLNESS_USER_INTENSITY_MINUTES_GOAL"`
|
|
MaxHeartRate []DateValue `json:"WELLNESS_MAX_HEART_RATE"`
|
|
MinimumAverageHeartRate []DateValue `json:"WELLNESS_MIN_AVG_HEART_RATE"`
|
|
MinimumHeartrate []DateValue `json:"WELLNESS_MIN_HEART_RATE"`
|
|
AverageStress []DateValue `json:"WELLNESS_AVERAGE_STRESS"`
|
|
RestingHeartRate []DateValue `json:"WELLNESS_RESTING_HEART_RATE"`
|
|
MaxStress []DateValue `json:"WELLNESS_MAX_STRESS"`
|
|
AbnormalHeartRateAlers []DateValue `json:"WELLNESS_ABNORMALHR_ALERTS_COUNT"`
|
|
MaximumAverageHeartRate []DateValue `json:"WELLNESS_MAX_AVG_HEART_RATE"`
|
|
StepGoal []DateValue `json:"WELLNESS_TOTAL_STEP_GOAL"`
|
|
FlorsAscendedGoal []DateValue `json:"WELLNESS_USER_FLOORS_ASCENDED_GOAL"`
|
|
ModerateIntensityMinutes []DateValue `json:"WELLNESS_MODERATE_INTENSITY_MINUTES"`
|
|
TotalColaries []DateValue `json:"WELLNESS_TOTAL_CALORIES"`
|
|
BodyBatteryCharged []DateValue `json:"WELLNESS_BODYBATTERY_CHARGED"`
|
|
FloorsDescended []DateValue `json:"WELLNESS_FLOORS_DESCENDED"`
|
|
BMRCalories []DateValue `json:"WELLNESS_BMR_CALORIES"`
|
|
FoodCaloriesRemainin []DateValue `json:"FOOD_CALORIES_REMAINING"`
|
|
TotalCalories []DateValue `json:"COMMON_TOTAL_CALORIES"`
|
|
BodyBatteryDrained []DateValue `json:"WELLNESS_BODYBATTERY_DRAINED"`
|
|
AverageSteps []DateValue `json:"WELLNESS_AVERAGE_STEPS"`
|
|
VigorousIntensifyMinutes []DateValue `json:"WELLNESS_VIGOROUS_INTENSITY_MINUTES"`
|
|
WellnessDistance []DateValue `json:"WELLNESS_TOTAL_DISTANCE"`
|
|
Distance []DateValue `json:"COMMON_TOTAL_DISTANCE"`
|
|
WellnessActiveCalories []DateValue `json:"WELLNESS_ACTIVE_CALORIES"`
|
|
}
|
|
|
|
// DailySummary is an extensive summary for a single day.
|
|
type DailySummary struct {
|
|
ProfileID int64 `json:"userProfileId"`
|
|
TotalKilocalories float64 `json:"totalKilocalories"`
|
|
ActiveKilocalories float64 `json:"activeKilocalories"`
|
|
BMRKilocalories float64 `json:"bmrKilocalories"`
|
|
WellnessKilocalories float64 `json:"wellnessKilocalories"`
|
|
BurnedKilocalories float64 `json:"burnedKilocalories"`
|
|
ConsumedKilocalories float64 `json:"consumedKilocalories"`
|
|
RemainingKilocalories float64 `json:"remainingKilocalories"`
|
|
TotalSteps int `json:"totalSteps"`
|
|
NetCalorieGoal float64 `json:"netCalorieGoal"`
|
|
TotalDistanceMeters int `json:"totalDistanceMeters"`
|
|
WellnessDistanceMeters int `json:"wellnessDistanceMeters"`
|
|
WellnessActiveKilocalories float64 `json:"wellnessActiveKilocalories"`
|
|
NetRemainingKilocalories float64 `json:"netRemainingKilocalories"`
|
|
UserID int64 `json:"userDailySummaryId"`
|
|
Date Date `json:"calendarDate"`
|
|
UUID string `json:"uuid"`
|
|
StepGoal int `json:"dailyStepGoal"`
|
|
StartTimeGMT Time `json:"wellnessStartTimeGmt"`
|
|
EndTimeGMT Time `json:"wellnessEndTimeGmt"`
|
|
StartLocal Time `json:"wellnessStartTimeLocal"`
|
|
EndLocal Time `json:"wellnessEndTimeLocal"`
|
|
Duration time.Duration `json:"durationInMilliseconds"`
|
|
Description string `json:"wellnessDescription"`
|
|
HighlyActive time.Duration `json:"highlyActiveSeconds"`
|
|
Active time.Duration `json:"activeSeconds"`
|
|
Sedentary time.Duration `json:"sedentarySeconds"`
|
|
Sleeping time.Duration `json:"sleepingSeconds"`
|
|
IncludesWellnessData bool `json:"includesWellnessData"`
|
|
IncludesActivityData bool `json:"includesActivityData"`
|
|
IncludesCalorieConsumedData bool `json:"includesCalorieConsumedData"`
|
|
PrivacyProtected bool `json:"privacyProtected"`
|
|
ModerateIntensity time.Duration `json:"moderateIntensityMinutes"`
|
|
VigorousIntensity time.Duration `json:"vigorousIntensityMinutes"`
|
|
FloorsAscendedInMeters float64 `json:"floorsAscendedInMeters"`
|
|
FloorsDescendedInMeters float64 `json:"floorsDescendedInMeters"`
|
|
FloorsAscended float64 `json:"floorsAscended"`
|
|
FloorsDescended float64 `json:"floorsDescended"`
|
|
IntensityGoal time.Duration `json:"intensityMinutesGoal"`
|
|
FloorsAscendedGoal int `json:"userFloorsAscendedGoal"`
|
|
MinHeartRate int `json:"minHeartRate"`
|
|
MaxHeartRate int `json:"maxHeartRate"`
|
|
RestingHeartRate int `json:"restingHeartRate"`
|
|
LastSevenDaysAvgRestingHeartRate int `json:"lastSevenDaysAvgRestingHeartRate"`
|
|
Source string `json:"source"`
|
|
AverageStress int `json:"averageStressLevel"`
|
|
MaxStress int `json:"maxStressLevel"`
|
|
Stress time.Duration `json:"stressDuration"`
|
|
RestStress time.Duration `json:"restStressDuration"`
|
|
ActivityStress time.Duration `json:"activityStressDuration"`
|
|
UncategorizedStress time.Duration `json:"uncategorizedStressDuration"`
|
|
TotalStress time.Duration `json:"totalStressDuration"`
|
|
LowStress time.Duration `json:"lowStressDuration"`
|
|
MediumStress time.Duration `json:"mediumStressDuration"`
|
|
HighStress time.Duration `json:"highStressDuration"`
|
|
StressQualifier string `json:"stressQualifier"`
|
|
MeasurableAwake time.Duration `json:"measurableAwakeDuration"`
|
|
MeasurableAsleep time.Duration `json:"measurableAsleepDuration"`
|
|
LastSyncGMT Time `json:"lastSyncTimestampGMT"`
|
|
MinAverageHeartRate int `json:"minAvgHeartRate"`
|
|
MaxAverageHeartRate int `json:"maxAvgHeartRate"`
|
|
}
|
|
|
|
// DailySummary will retrieve a detailed daily summary for date. If
|
|
// displayName is empty, the currently authenticated user will be used.
|
|
func (c *Client) DailySummary(displayName string, date time.Time) (*DailySummary, error) {
|
|
if displayName == "" && c.Profile == nil {
|
|
return nil, ErrNotAuthenticated
|
|
}
|
|
|
|
if displayName == "" && c.Profile != nil {
|
|
displayName = c.Profile.DisplayName
|
|
}
|
|
|
|
URL := fmt.Sprintf("https://connect.garmin.com/modern/proxy/usersummary-service/usersummary/daily/%s?calendarDate=%s",
|
|
displayName,
|
|
formatDate(date),
|
|
)
|
|
|
|
summary := new(DailySummary)
|
|
|
|
err := c.getJSON(URL, summary)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
summary.Duration *= time.Millisecond
|
|
summary.HighlyActive *= time.Second
|
|
summary.Active *= time.Second
|
|
summary.Sedentary *= time.Second
|
|
summary.Sleeping *= time.Second
|
|
summary.ModerateIntensity *= time.Minute
|
|
summary.VigorousIntensity *= time.Minute
|
|
summary.IntensityGoal *= time.Minute
|
|
summary.Stress *= time.Second
|
|
summary.RestStress *= time.Second
|
|
summary.ActivityStress *= time.Second
|
|
summary.UncategorizedStress *= time.Second
|
|
summary.TotalStress *= time.Second
|
|
summary.LowStress *= time.Second
|
|
summary.MediumStress *= time.Second
|
|
summary.HighStress *= time.Second
|
|
summary.MeasurableAwake *= time.Second
|
|
summary.MeasurableAsleep *= time.Second
|
|
|
|
return summary, nil
|
|
}
|
|
|
|
// DailySummaries will retrieve a daily summary for userID.
|
|
func (c *Client) DailySummaries(userID string, from time.Time, until time.Time) (*DailySummaries, error) {
|
|
URL := fmt.Sprintf("https://connect.garmin.com/modern/proxy/userstats-service/wellness/daily/%s?fromDate=%s&untilDate=%s",
|
|
userID,
|
|
formatDate(from),
|
|
formatDate(until),
|
|
)
|
|
|
|
if !c.authenticated() {
|
|
return nil, ErrNotAuthenticated
|
|
}
|
|
|
|
// We use a proxy object to deserialize the values to proper Go types.
|
|
var proxy struct {
|
|
Start Date `json:"statisticsStartDate"`
|
|
End Date `json:"statisticsEndDate"`
|
|
AllMetrics struct {
|
|
Summary DailySummaries `json:"metricsMap"`
|
|
} `json:"allMetrics"`
|
|
}
|
|
|
|
err := c.getJSON(URL, &proxy)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ret := &proxy.AllMetrics.Summary
|
|
ret.Start = proxy.Start.Time()
|
|
ret.End = proxy.End.Time()
|
|
|
|
return ret, nil
|
|
}
|