Fix body battery and intensity minutes Garmin API endpoints
All checks were successful
Deploy / deploy (push) Successful in 2m27s
All checks were successful
Deploy / deploy (push) Successful in 2m27s
Body Battery: - Change endpoint from /usersummary-service/stats/bodyBattery/dates/ to /wellness-service/wellness/bodyBattery/reports/daily - Parse new response format: array with bodyBatteryValuesArray time series - Current value = last entry's level (index 2) - YesterdayLow = min level from yesterday's data Intensity Minutes: - Change endpoint from /fitnessstats-service/activity to /usersummary-service/stats/im/weekly - Add date parameter to function signature - Parse new response format: array with moderateValue/vigorousValue Endpoints verified against python-garminconnect source code. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -109,8 +109,13 @@ export async function fetchBodyBattery(
|
||||
oauth2Token: string,
|
||||
): Promise<BodyBatteryData> {
|
||||
try {
|
||||
// Calculate yesterday's date for the API request
|
||||
const dateObj = new Date(date);
|
||||
dateObj.setDate(dateObj.getDate() - 1);
|
||||
const yesterday = dateObj.toISOString().split("T")[0];
|
||||
|
||||
const response = await fetch(
|
||||
`${GARMIN_API_URL}/usersummary-service/stats/bodyBattery/dates/${date}`,
|
||||
`${GARMIN_API_URL}/wellness-service/wellness/bodyBattery/reports/daily?startDate=${yesterday}&endDate=${date}`,
|
||||
{
|
||||
headers: getGarminHeaders(oauth2Token),
|
||||
},
|
||||
@@ -132,20 +137,33 @@ export async function fetchBodyBattery(
|
||||
);
|
||||
return { current: null, yesterdayLow: null };
|
||||
}
|
||||
const data = JSON.parse(text);
|
||||
const data = JSON.parse(text) as Array<{
|
||||
date: string;
|
||||
bodyBatteryValuesArray?: Array<[number, string, number, number]>;
|
||||
}>;
|
||||
|
||||
const currentData = data?.bodyBatteryValuesArray?.[0];
|
||||
const current = currentData?.charged ?? null;
|
||||
// Find today's and yesterday's data from the response array
|
||||
const todayData = data?.find((d) => d.date === date);
|
||||
const yesterdayData = data?.find((d) => d.date === yesterday);
|
||||
|
||||
const yesterdayStats = data?.bodyBatteryStatList?.[0];
|
||||
const yesterdayLow = yesterdayStats?.min ?? null;
|
||||
// Current = last value in today's bodyBatteryValuesArray (index 2 is the level)
|
||||
const todayValues = todayData?.bodyBatteryValuesArray ?? [];
|
||||
const current =
|
||||
todayValues.length > 0 ? todayValues[todayValues.length - 1][2] : null;
|
||||
|
||||
// Yesterday low = minimum level in yesterday's bodyBatteryValuesArray
|
||||
const yesterdayValues = yesterdayData?.bodyBatteryValuesArray ?? [];
|
||||
const yesterdayLow =
|
||||
yesterdayValues.length > 0
|
||||
? Math.min(...yesterdayValues.map((v) => v[2]))
|
||||
: null;
|
||||
|
||||
logger.info(
|
||||
{
|
||||
current,
|
||||
yesterdayLow,
|
||||
hasCurrentData: !!currentData,
|
||||
hasYesterdayData: !!yesterdayStats,
|
||||
hasCurrentData: todayValues.length > 0,
|
||||
hasYesterdayData: yesterdayValues.length > 0,
|
||||
},
|
||||
"Garmin body battery data received",
|
||||
);
|
||||
@@ -161,11 +179,18 @@ export async function fetchBodyBattery(
|
||||
}
|
||||
|
||||
export async function fetchIntensityMinutes(
|
||||
date: string,
|
||||
oauth2Token: string,
|
||||
): Promise<number> {
|
||||
try {
|
||||
// Calculate 7 days before the date for weekly range
|
||||
const endDate = date;
|
||||
const startDateObj = new Date(date);
|
||||
startDateObj.setDate(startDateObj.getDate() - 7);
|
||||
const startDate = startDateObj.toISOString().split("T")[0];
|
||||
|
||||
const response = await fetch(
|
||||
`${GARMIN_API_URL}/fitnessstats-service/activity`,
|
||||
`${GARMIN_API_URL}/usersummary-service/stats/im/weekly?start=${startDate}&end=${endDate}`,
|
||||
{
|
||||
headers: getGarminHeaders(oauth2Token),
|
||||
},
|
||||
@@ -173,7 +198,7 @@ export async function fetchIntensityMinutes(
|
||||
|
||||
if (!response.ok) {
|
||||
logger.warn(
|
||||
{ status: response.status, endpoint: "fitnessstats" },
|
||||
{ status: response.status, endpoint: "intensityMinutes" },
|
||||
"Garmin intensity minutes API error",
|
||||
);
|
||||
return 0;
|
||||
@@ -182,24 +207,28 @@ export async function fetchIntensityMinutes(
|
||||
const text = await response.text();
|
||||
if (!text.startsWith("{") && !text.startsWith("[")) {
|
||||
logger.error(
|
||||
{ endpoint: "fitnessstats", responseBody: text.slice(0, 1000) },
|
||||
{ endpoint: "intensityMinutes", responseBody: text.slice(0, 1000) },
|
||||
"Garmin returned non-JSON response",
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
const data = JSON.parse(text);
|
||||
const weeklyTotal = data?.weeklyTotal;
|
||||
const data = JSON.parse(text) as Array<{
|
||||
calendarDate: string;
|
||||
moderateValue?: number;
|
||||
vigorousValue?: number;
|
||||
}>;
|
||||
|
||||
if (!weeklyTotal) {
|
||||
const entry = data?.[0];
|
||||
if (!entry) {
|
||||
logger.info(
|
||||
{ hasWeeklyTotal: false },
|
||||
{ hasData: false },
|
||||
"Garmin intensity minutes: no weekly data",
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const moderate = weeklyTotal.moderateIntensityMinutes ?? 0;
|
||||
const vigorous = weeklyTotal.vigorousIntensityMinutes ?? 0;
|
||||
const moderate = entry.moderateValue ?? 0;
|
||||
const vigorous = entry.vigorousValue ?? 0;
|
||||
const total = moderate + vigorous;
|
||||
|
||||
logger.info(
|
||||
@@ -210,7 +239,7 @@ export async function fetchIntensityMinutes(
|
||||
return total;
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
{ err: error, endpoint: "fitnessstats" },
|
||||
{ err: error, endpoint: "intensityMinutes" },
|
||||
"Garmin intensity minutes fetch failed",
|
||||
);
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user