Files
go-garth/pkg/garmin/health.go
2025-09-22 16:41:49 -07:00

94 lines
3.3 KiB
Go

package garmin
import (
"encoding/json"
"fmt"
"time"
internalClient "github.com/sstent/go-garth/pkg/garth/client"
"github.com/sstent/go-garth/internal/models/types"
)
// GetDailyHRVData retrieves comprehensive daily HRV data for the given date.
// It returns nil when no HRV data is available for the specified day.
func (c *Client) GetDailyHRVData(date time.Time) (*types.DailyHRVData, error) {
return getDailyHRVData(date, c.Client)
}
func getDailyHRVData(day time.Time, client *internalClient.Client) (*types.DailyHRVData, error) {
dateStr := day.Format("2006-01-02")
path := fmt.Sprintf("/wellness-service/wellness/dailyHrvData/%s?date=%s",
client.Username, dateStr)
data, err := client.ConnectAPI(path, "GET", nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to get HRV data: %w", err)
}
if len(data) == 0 {
return nil, nil
}
var response struct {
HRVSummary types.DailyHRVData `json:"hrvSummary"`
HRVReadings []types.HRVReading `json:"hrvReadings"`
}
if err := json.Unmarshal(data, &response); err != nil {
return nil, fmt.Errorf("failed to parse HRV response: %w", err)
}
// Combine summary and readings
response.HRVSummary.HRVReadings = response.HRVReadings
return &response.HRVSummary, nil
}
// GetDetailedSleepData retrieves comprehensive sleep data for the given date,
// including sleep stages and movement where available. It returns nil when no
// sleep data is available for the specified day.
func (c *Client) GetDetailedSleepData(date time.Time) (*types.DetailedSleepData, error) {
return getDetailedSleepData(date, c.Client)
}
func getDetailedSleepData(day time.Time, client *internalClient.Client) (*types.DetailedSleepData, error) {
dateStr := day.Format("2006-01-02")
path := fmt.Sprintf("/wellness-service/wellness/dailySleepData/%s?date=%s&nonSleepBufferMinutes=60",
client.Username, dateStr)
data, err := client.ConnectAPI(path, "GET", nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to get detailed sleep data: %w", err)
}
if len(data) == 0 {
return nil, nil
}
var response struct {
DailySleepDTO *types.DetailedSleepData `json:"dailySleepDTO"`
SleepMovement []types.SleepMovement `json:"sleepMovement"`
RemSleepData bool `json:"remSleepData"`
SleepLevels []types.SleepLevel `json:"sleepLevels"`
SleepRestlessMoments []interface{} `json:"sleepRestlessMoments"`
RestlessMomentsCount int `json:"restlessMomentsCount"`
WellnessSpO2SleepSummaryDTO interface{} `json:"wellnessSpO2SleepSummaryDTO"`
WellnessEpochSPO2DataDTOList []interface{} `json:"wellnessEpochSPO2DataDTOList"`
WellnessEpochRespirationDataDTOList []interface{} `json:"wellnessEpochRespirationDataDTOList"`
SleepStress interface{} `json:"sleepStress"`
}
if err := json.Unmarshal(data, &response); err != nil {
return nil, fmt.Errorf("failed to parse detailed sleep response: %w", err)
}
if response.DailySleepDTO == nil {
return nil, nil
}
// Populate additional data
response.DailySleepDTO.SleepMovement = response.SleepMovement
response.DailySleepDTO.SleepLevels = response.SleepLevels
return response.DailySleepDTO, nil
}