Garmin 连接
这是叉子 https://github.com/Pythe1337N/garmin-connect (中文(简体) ) 灵感来自 https://github.com/matin/garth (中文(简体) )。非常感谢捐助者.
一个 JavaScript 库,用于访问和管理您的 Garmin 连接数据 。 它有方法 获取和设置信息 在您的 Garmin 账户, 也支持 自定义请求 使用 GET, (中文(简体) ), POST,以及 PUT 这样你就可以满足额外的需要.
该文件详细介绍了《公约》第19条第1款(a)项和(b)项所规定的公共公共宣传工具 @flow-js/garmin-connect 图书馆.
目录
认证
构造器
创建 Garmin 连接客户端的新实例 .
const { GarminConnect } = require('@flow-js/garmin-connect');
// Create a new Garmin Connect Client with credentials
const GCClient = new GarminConnect({
username: '[email protected]',
password: 'MySecretPassword'
});
// Alternatively, create a client using credentials from garmin.config.json
const GCClient = new GarminConnect();
您也可以提供名为配置文件 garmin.config.json 在您的工程根 :
{
"username": "[email protected]",
"password": "MySecretPassword"
}
登录
/**
* Login to Garmin Connect with provided credentials or those set during construction
* @param username - Optional username to override the one in credentials
* @param password - Optional password to override the one in credentials
* @param options - Optional login options (see MFA below)
* @returns The GarminConnect instance for chaining
*/
async
login(
username ? : string,
password ? : string,
options ? : LoginOptions
)
:
Promise < GarminConnect >
示例
await GCClient.login();
// Or with specific credentials
await GCClient.login('[email protected]', 'MySecretPassword');
完整实例 : examples/example.js
多功能认证( MFA)
如果您的 Garmin 账户已启用 2FA / MFA , 登录将会失败, 除非您提供
mfaHandler 调用。 当加明回应 MFA_REQUIRED图书馆给你的管理员打电话,等着
验证码(email或认证器app),并完成登录.
/**
* @property mfaHandler - Async function that resolves to the MFA verification code.
* Required for accounts with 2FA enabled. If MFA is required and this is omitted,
* login throws: "MFA required but no mfaHandler provided".
*/
interface LoginOptions {
mfaHandler?: () => Promise<string>;
}
示例( 在节点. js CLI 中的代码提示):
const readline = require('readline');
const { GarminConnect } = require('@flow-js/garmin-connect');
const promptMfaCode = () =>
new Promise((resolve) => {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Enter MFA code: ', (code) => {
rl.close();
resolve(code);
});
});
const GCClient = new GarminConnect({
username: '[email protected]',
password: 'MySecretPassword'
});
await GCClient.login(undefined, undefined, {
mfaHandler: promptMfaCode
});
您也可通过全权证书和外交部主管:
await GCClient.login('[email protected]', 'MySecretPassword', {
mfaHandler: async () => {
// Fetch or prompt for the code (email / authenticator app)
return '123456';
}
});
在外交部成功登录后,导出 OAuth 令牌(见 会话管理(中文(简体) )
并重新使用它们 loadToken 编号 : loadTokenByFile 以后的运行,所以你不需要每次输入 MFA 代码.
通过外交部获得的托币可包括: mfa_token 财务报告和审定财务报表
mfa_expiration_timestamp 在 OAuth1 标记上; 这些保存到
exportToken() 编号 : loadToken() 圆通相通.
会话管理
导出托肯
/**
* Exports OAuth tokens to files in the specified directory
* @param dirPath - Directory path where token files will be saved
*/
exportTokenToFile(dirPath: string): void
示例
GCClient.exportTokenToFile('/path/to/save/tokens');
// Creates oauth1_token.json and oauth2_token.json in the specified directory
从文件装入鼠标
/**
* Loads OAuth tokens from files in the specified directory
* @param dirPath - Directory path where token files are stored
* @throws Error if directory not found
*/
loadTokenByFile(dirPath: string): void
示例
GCClient.loadTokenByFile('/path/to/save/tokens');
导出托肯为对象
/**
* Exports OAuth tokens as an object
* @returns Object containing OAuth1 and OAuth2 tokens
* @throws Error if tokens are not found
*/
exportToken(): IGarminTokens
从对象装入托盘
/**
* Loads OAuth tokens from provided token objects (e.g., from DB or localStorage)
* @param oauth1 - OAuth1 token object
* @param oauth2 - OAuth2 token object
*/
loadToken(oauth1: IOauth1Token, oauth2: IOauth2Token): void
示例
const oauth1 = GCClient.client.oauth1Token;
const oauth2 = GCClient.client.oauth2Token;
// Later, use these to restore the session
GCClient.loadToken(oauth1, oauth2);
用户数据
用户配置
/**
* Retrieves the user's social profile from Garmin Connect
* @returns User's social profile data
*/
async getUserProfile(): Promise<ISocialProfile>
示例
const userProfile = await GCClient.getUserProfile();
console.log(userProfile.userName); // Verify login was successful
用户设置
/**
* Retrieves the user's settings from Garmin Connect
* @returns User settings data
*/
async getUserSettings(): Promise<IUserSettings>
完整实例 : examples/example.js
活 动
获取活动
/**
* Retrieves a list of activities matching the specified criteria
* @param start - Optional starting index for pagination
* @param limit - Optional limit for pagination
* @param activityType - Optional activity type filter
* @param subActivityType - Optional activity subtype filter
* @returns Array of activities matching the criteria
*/
async getActivities(
start?: number,
limit?: number,
activityType?: ActivityType,
subActivityType?: ActivitySubType
): Promise<IActivity[]>
示例
const activities = await GCClient.getActivities(
0,
10,
ActivityType.Running,
ActivitySubType.Outdoor
);
/**
* Counts lifetime activities
* @returns Activity statistics including counts by type
*/
async countActivities(): Promise<ICountActivities>
个人活动业务
/**
* Retrieves a specific activity by its ID
* @param activity - Object containing activityId
* @returns Details of the specified activity
* @throws Error if activityId is missing
*/
async getActivity(activity: {
activityId: GCActivityId;
}): Promise<IActivity>
示例
const activityDetails = await GCClient.getActivity({
activityId: 'exampleActivityId'
});
/**
* Deletes an activity by activityId
* @param activity - with activityId
* @returns void
*
*/
async deleteActivity(activity: {
activityId: GCActivityId;
}): Promise<void>
/**
* Renames an activity with the given activityId to the newName.
* @param activityId
* @param newName
*/
async renameActivity(
activityId: GCActivityId,
newName: string
): Promise<void>
活动文件
/**
* Download activity original data file
*
* Use the activityId to download the original activity data. Usually this is supplied as a .zip file.
*
* @example
* ```js
* const [activity] = await GCClient.getActivities(0, 1);
* // Directory path is optional and defaults to the current working directory.
* // Downloads filename will be supplied by Garmin.
* GCClient.downloadOriginalActivityData(activity, './some/path/that/exists');
* ```
*
* @param activity - with activityId
* @param dir - directory to save the file
* @param type - 'zip' | 'gpx' | 'tcx' | 'kml' (default: 'zip')
*/
async downloadOriginalActivityData(
activity: { activityId: GCActivityId },
dir: string,
type: ExportFileTypeValue = 'zip'
): Promise<void>
/**
* Uploads an activity file
*
* Uploads an activity file as a new Activity. The file can be a 'gpx', 'tcx', or 'fit' file.
* If the activity already exists, the result will have a status code of 409.
* Note: Garmin changed the upload API in v1.4.4, the response `detailedImportResult` no longer contains the new activityId.
*
* @param file - Path to the activity file
* @param format - 'fit' | 'gpx' | 'tcx'
* @returns Response from the upload operation
*/
async uploadActivity(
file: string,
format: UploadFileTypeTypeValue = 'fit'
)
示例
const upload = await GCClient.uploadActivity('./some/path/to/file.fit');
// Note: Garmin changed the upload API in v1.4.4
// const activityId = upload.detailedImportResult.successes[0].internalId; // Not working
// const uploadId = upload.detailedImportResult.uploadId;
/**
* Uploads a photo to an activity
* @param activityId - The ID of the activity to attach the photo to
* @param filePath - Path to the image file to upload
* @returns Response from the photo upload operation
*/
async uploadActivityPhoto(
activityId: GCActivityId,
filePath: string
): Promise<unknown>
示例
await GCClient.uploadActivityPhoto(12345678, './my-run-photo.jpg');
完整实例 : examples/example-image.js
劳动
管理工作
/**
* Gets the list of workouts
* @param start
* @param limit
*/
async getWorkouts(start: number, limit: number): Promise<IWorkout[]>
完整实例 : examples/example-intervals-icu.js
/**
* Gets the workout detail by workoutId
* @param workout
* @returns workout detail - IWorkoutDetail
*/
async getWorkoutDetail(workout: {
workoutId: string;
}): Promise<IWorkoutDetail>
完整实例 : examples/example-intervals-icu.js
/**
* Creates a new workout
*
* Use workoutBuilder to create the workout object. See the example in [examples/example-workout.js](examples/example-workout.js) for more complex workouts.
*
* @param workout - workout detail
* @returns Response from the workout creation operation
*
* @example
* ```js
* const wb = new WorkoutBuilder(
* WorkoutType.Running,
* 'Workout running ' + new Date().toISOString()
* );
*
* wb.addStep(
* new Step(
* StepType.Run,
* TimeDuration.fromSeconds(45),
* new NoTarget(),
* 'Comment for the step: Run for 45 seconds'
* )
* );
*
* GCClient.createWorkout(wb.build());
* ```
*/
async createWorkout(workout: IWorkoutDetail)
完整实例 : examples/example-workout.js, (中文(简体) ), examples/example-strength-workout.js
/**
* Deletes a workout by workoutId
* @param workout - with workoutId
*
* @example
* ```js
* const workouts = await GCClient.getWorkouts();
* const id = workouts[0].workoutId;
* GCClient.deleteWorkout({ workoutId: id });
* ```
*/
async deleteWorkout(workout: { workoutId: string })
/**
* Retrieves all workouts
* @returns List of workouts
*/
async workouts(): Promise<Workout[]>
工作时间安排
/**
* Schedule a workout by workoutId to a specific date
*
* To add a workout to your calendar, provide the workout id and the date to schedule it on.
*
* @param workout - with workoutId
* @param scheduleDate - 'YYYY-MM-DD' format date string
*
* @example
* ```js
* const workouts = await GCClient.getWorkouts();
* const id = workouts[0].workoutId;
* GCClient.scheduleWorkout({ workoutId: id }, new Date('2025-12-01'));
* ```
*/
async scheduleWorkout(
workout: { workoutId: string },
scheduleDate: string
)
导出为间隔. icu
将 Garmin 解决细节转换成一个与 页:1 间隔. icu 解决构建器中省略了 您可以在间隔上单独设置 。 icu事件.
/**
* Convert a Garmin workout detail into an intervals.icu workout description string.
* @param workout - workout detail from getWorkoutDetail() or WorkoutBuilder.build()
* @returns intervals.icu description (sections, steps, targets, repeats)
*/
toIntervalsIcuDescription(workout
:
IWorkoutDetail
):
string
示例
const {
GarminConnect,
toIntervalsIcuDescription
} = require('@flow-js/garmin-connect');
const detail = await GCClient.getWorkoutDetail({ workoutId });
const description = toIntervalsIcuDescription(detail);
console.log(description);
// Warmup
// - Easy 10m Z2 HR
//
// Main Set 4x
// - 800mtr 5:00/km Pace
// - 400mtr Z1 HR
//
// Cooldown
// - 10m Z1 HR
见 examples/example-intervals-icu.js 对于一个完整的取而代之的例子.
支持的映射包括时间和距离持续时间,圈压,速度/HR/功率/cadence目标,区头
(单位:千美元)Warmup, (中文(简体) ), Main Set, (中文(简体) ), Cooldown)和重复组(Main Set Nx) (中文(简体) ). 强步和不支持的结束条件
(日历、人力资源阈值、代表)作为说明性提示文本发布.
卫生数据
步骤
/**
* Retrieves step count for a specific date
* @param date - The date to get step count for, defaults to current date
* @returns Total step count for the specified date
* @throws Error if steps data not found for the date
*/
async getSteps(date = new Date()): Promise<number>
示例
const totalSteps = await GCClient.getSteps(new Date('2020-03-24'));
睡觉
/**
* Retrieves sleep data for a specific date
* @param date - The date to get sleep data for, defaults to current date
* @returns Sleep data for the specified date
* @throws Error if sleep data is invalid or empty
*/
async getSleepData(date = new Date()): Promise<SleepData>
/**
* Calculates sleep duration for a specific date
*
* Retrieves hours and minutes slept for a given date.
*
* @param date - The date to get sleep duration for, defaults to current date
* @returns Object with hours and minutes of sleep
* @throws Error if sleep data is missing or invalid
*
* @example
* ```js
* const detailedSleep = await GCClient.getSleepDuration(new Date('2020-03-24'));
* console.log(`Hours: ${detailedSleep.hours}, Minutes: ${detailedSleep.minutes}`);
* ```
*/
async getSleepDuration(
date = new Date()
): Promise<{ hours: number; minutes: number }>
重量
/**
* Retrieves weight data for a specific date
* @param date - The date to get weight data for, defaults to current date
* @returns Weight data for the specified date
* @throws Error if weight data is invalid or empty
*/
async getDailyWeightData(date = new Date()): Promise<WeightData>
/**
* Retrieves weight data in pounds for a specific date
* @param date - The date to get weight data for, defaults to current date
* @returns Weight in pounds for the specified date
* @throws Error if valid weight data not found for the date
*/
async getDailyWeightInPounds(date = new Date()): Promise<number>
/**
* Updates weight data for a specific date
*
* Updates weight information for the specified date.
*
* @param date - The date for the weight data, defaults to current date
* @param lbs - Weight value in pounds
* @param timezone - Timezone string for correct timestamp conversion
* @returns Response from the weight update operation
* @throws Error if update fails
*
* @example
* ```js
* await GCClient.updateWeight(undefined, 202.9, 'America/Los_Angeles');
* ```
*/
async updateWeight(
date = new Date(),
lbs: number,
timezone: string
): Promise<UpdateWeight>
水分
/**
* Retrieves hydration data in fluid ounces for a specific date
* @param date - The date to get hydration data for, defaults to current date
* @returns Hydration value in fluid ounces for the specified date
* @throws Error if hydration data is invalid or empty
*/
async getDailyHydration(date = new Date()): Promise<number>
/**
* Updates hydration log with fluid ounces for a specific date
*
* Adds a hydration log entry in ounces for a given date.
*
* @param date - The date for the hydration data, defaults to current date
* @param valueInOz - Hydration value in fluid ounces. Accepts negative number.
* @returns Response from the hydration update operation
* @throws Error if update fails
*
* @example
* ```js
* const hydrationLogEntry = await GCClient.updateHydrationLogOunces(
* new Date('2020-03-24'),
* 16
* );
* ```
*/
async updateHydrationLogOunces(
date = new Date(),
valueInOz: number
): Promise<WaterIntake>
心率
/**
* Retrieves heart rate data for a specific date
*
* Retrieves daily heart rate data for a given date.
*
* @param date - The date to get heart rate data for, defaults to current date
* @returns Heart rate data for the specified date
* @throws Error if the operation fails
*
* @example
* ```js
* const heartRateData = await GCClient.getHeartRate(new Date('2020-03-24'));
* ```
*/
async getHeartRate(date = new Date()): Promise<HeartRate>
高尔夫
/**
* Retrieves golf summary data
* @returns Summary of golf activities
* @throws Error if golf summary data is invalid or empty
*/
async getGolfSummary(): Promise<GolfSummary>
/**
* Retrieves golf scorecard for a specific round
* @param scorecardId - ID of the scorecard to retrieve
* @returns Golf scorecard data
* @throws Error if golf scorecard data is invalid or empty
*/
async getGolfScorecard(scorecardId: number): Promise<GolfScorecard>
齿轮
/**
* Returns the gear data for the user.
* @param availableGearDate - Optional date to filter the gear available at the date (format: 'YYYY-MM-DD').
*/
async getGear(availableGearDate?: string): Promise<GearData[]>
/**
* Returns the gear data assigned with a specific activity.
* @param activityId
*/
async getGearsForActivity(activityId: GCActivityId): Promise<GearData[]>
/**
* Links a gear item to an activity.
* @param activityId
* @param gearId - uuid field from GearData
* @return GearData - the linked gear item data
*/
async linkGearToActivity(
activityId: GCActivityId,
gearId: GCGearId
): Promise<GearData>
/**
* Unlinks a gear item from an activity.
* @param activityId
* @param gearId - uuid field from GearData
* @return GearData - the unlinked gear item data
*/
async unlinkGearFromActivity(
activityId: GCActivityId,
gearId: GCGearId
): Promise<GearData>
GPX 和课程
/**
* Imports GPX file content
*
* @example ./examples/example-gpx-file.js
* @param fileName - Name of the GPX file
* @param fileContent - Content of the GPX file as string
* @returns Response from the GPX import operation containing courseName, geoPoints, and coursePoints
*
* @example
* ```js
* const fileContent = await fs.readFile('paris-marathon.gpx', 'utf8');
* const response = await GCClient.importGpx('paris-marathon.gpx', fileContent);
* // The response contains courseName, geoPoints, and coursePoints that can be used with createCourse
* ```
*/
async importGpx(
fileName: string,
fileContent: string
): Promise<ImportedGpxResponse>
完整实例 : examples/example-gpx-file.js
/**
* Creates a course from GPX data
* You can get geoPoints and coursePoints from the imported GPX file response.
*
* @example ./examples/example-gpx-file.js
* @param activityType - Type of activity for the course
* @param courseName - Name of the course
* @param geoPoints - Array of geographical points making up the course
* @param coursePoints - Optional array of course points (waypoints)
* @returns Response from the course creation operation containing the courseId
*
* @example
* ```js
* // First import GPX to get geoPoints and coursePoints
* const response = await GCClient.importGpx('course.gpx', gpxFileContent);
*
* // Then create the course
* const createCourseResponse = await GCClient.createCourse(
* 1, // activityType (1 = running)
* response.courseName,
* response.geoPoints,
* response.coursePoints
* );
*
* console.log('Course created with id:', createCourseResponse.courseId);
* ```
*/
async createCourse(
activityType: GpxActivityType,
courseName: string,
geoPoints: GeoPoint[],
coursePoints: CoursePoint[] = []
)
完整实例 : examples/example-gpx-file.js
/**
* Lists all courses
* @returns List of courses in ListCoursesResponse format
*
* @example
* ```js
* const listCourses = await GCClient.listCourses();
* console.log(
* 'Last course:',
* listCourses.coursesForUser[0].courseId,
* listCourses.coursesForUser[0].courseName
* );
* ```
*/
async listCourses(): Promise<ListCoursesResponse>
完整实例 : examples/example-gpx-file.js
/**
* Get the details of a course
* @param courseId - Course id
* @returns Course details
*
* @example
* ```js
* const course = await GCClient.getCourseDetails(123456789);
* console.log('Course name', course.courseName);
* ```
*/
async getCourseDetails(
courseId: string | number
): Promise<CourseDetailsResponse>
完整实例 : examples/example-gpx-file.js
/**
* Edit course privacy
* @param courseId - Course Id
* @param privacy - Privacy setting for the course, use CoursePrivacyRule.PUBLIC (1) for public courses
* or CoursePrivacyRule.PRIVATE (2) for private courses. Defaults to PRIVATE.
* @returns Course details
*
* @example
* ```js
* // Make a course public
* await GCClient.updateCoursePrivacy(courseId, 1);
* ```
*/
async updateCoursePrivacy(
courseId: string | number,
privacy: CoursePrivacyRule = CoursePrivacyRule.PRIVATE
): Promise<CourseDetailsResponse>
完整实例 : examples/example-gpx-file.js
/**
* Rename a course
* @param courseId - Course Id
* @param courseName - The new course name
* @returns Course details
*
* @example
* ```js
* await GCClient.renameCourse(courseId, 'My new course name');
* ```
*/
async renameCourse(
courseId: string | number,
courseName: string
): Promise<CourseDetailsResponse>
/**
* Complete update of a course
* @param courseRequest - the full data of the course. Use getCourseDetails to get the existing set
* @returns Course details updated
*
* @example
* ```js
* const course = await GCClient.getCourseDetails(courseId);
* await GCClient.updateCourse({ ...course, description: 'Updated description' });
* ```
*/
async updateCourse(
courseRequest: CourseDetailsRequest
): Promise<CourseDetailsResponse>
/**
* Exports a course as GPX file content
* @param courseId - ID of the course to export
* @returns GPX file content as string
*
* @example
* ```js
* const downloadGpx = await GCClient.exportCourseAsGpx(courseId);
* console.log('Downloaded GPX size:', downloadGpx.length);
* ```
*/
async exportCourseAsGpx(courseId: number): Promise<string>
完整实例 : examples/example-gpx-file.js
日历
/**
* Retrieves calendar events for a specific year.
* @param year {number} - The year for which to retrieve calendar events.
*/
async getYearCalendarEvents(year: number): Promise<YearCalendar>
/**
* Retrieves calendar events for a specific month and year.
* @param year {number} - The year for which to retrieve calendar events.
* @param month {number} - The month (0-11) for which to retrieve calendar events.
*/
async getMonthCalendarEvents(
year: number,
month: number
): Promise<MonthCalendar>
/**
* Retrieves calendar events for a specific week containing the given date.
* @param year {number} - The year of the date.
* @param month {number} - The month (0-11) of the date.
* @param day {number} - The day of the first day of the week.
* @param firstDayOfWeek {number} - Optional first day of the week, default is 1
*/
async getWeekCalendarEvents(
year: number,
month: number,
day: number,
firstDayOfWeek?: number
): Promise<any>
自定义请求
库为 Garmin 连接 API 提供自定义请求的方法 :
/**
* Performs a GET request to the specified URL
* @param url - URL to send the request to
* @param data - Optional query parameters or request configuration
* @returns Response data of type T
*/
async get<T>(url: string, data?: any)
/**
* Performs a POST request to the specified URL
* @param url - URL to send the request to
* @param data - Data to send in the request body
* @returns Response data of type T
*/
async post<T>(url: string, data: any)
/**
* Performs a PUT request to the specified URL
* @param url - URL to send the request to
* @param data - Data to send in the request body
* @returns Response data of type T
*/
async put<T>(url: string, data: any)