Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .coveralls.yml

This file was deleted.

6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
WITHINGS_CLIENT_ID=
WITHINGS_CLIENT_SECRET=
WITHINGS_CALLBACK_URL=http://localhost:8585/callback
WITHINGS_API_ENDPOINT=https://wbsapi.withings.net
WITHINGS_REFRESH_TOKEN=
WITHINGS_USER_ID=
29 changes: 29 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Test Suite

on:
pull_request:
branches: [master]

jobs:
test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
9.0.x
10.0.x

- name: Restore dependencies
run: dotnet restore

- name: Build
run: dotnet build --no-restore

- name: Test
run: dotnet test --no-build --verbosity normal --filter "TestCategory!=E2E"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,4 @@ NancyExample/Web.config
*.dotCover

**/CLAUDE.md
.env
7 changes: 4 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
FROM mcr.microsoft.com/dotnet/sdk:8.0
FROM mcr.microsoft.com/dotnet/sdk:10.0

WORKDIR /app

COPY . .

RUN chmod +x run_tests.sh
RUN dotnet restore Withings.NET.sln
RUN dotnet build Withings.NET.sln --no-restore

CMD ["./run_tests.sh"]
CMD ["dotnet", "test", "Withings.NET.sln", "--no-build", "--verbosity", "normal", "--filter", "TestCategory!=E2E"]
173 changes: 117 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,65 +1,126 @@
# Withings.NET

.NET Client for interacting with Withing OAuth1 Api
.NET client for the [Withings Health Data API](https://developer.withings.com/) (OAuth 2.0).

[![Build status](https://ci.appveyor.com/api/projects/status/lw9pd7gbdjgck3sq?svg=true)](https://ci.appveyor.com/project/atbyrd/withings-net)
[![Coverage Status](https://coveralls.io/repos/github/atbyrd/Withings.NET/badge.svg?branch=master)](https://coveralls.io/github/atbyrd/Withings.NET?branch=master)
[![codecov](https://codecov.io/gh/atbyrd/Withings.NET/branch/master/graph/badge.svg)](https://codecov.io/gh/atbyrd/Withings.NET)
[![Documentation Status](https://readthedocs.org/projects/withingsnet/badge/?version=latest)](http://withingsnet.readthedocs.io/en/latest/?badge=latest)
[![NuGet](https://img.shields.io/nuget/v/Withings.NET.svg)](https://www.nuget.org/packages/Withings.NET)

[![NuGet](https://img.shields.io/nuget/v/Nuget.Core.svg?style=plastic)](https://www.nuget.org/packages/Withings.NET)
## Requirements

## USAGE
Due to external dependencies, your callback url should include a username param i.e. http://localhost:49294/api/oauth/callback/{username}
- .NET 8.0, 9.0, or 10.0

### All examples will use the Nancy Framework
## Installation

#### Authorization - Getting user authorization url
```
Get["api/oauth/authorize", true] = async (nothing, ct) =>
{
var url = await authenticator.UserRequstUrl(requestToken).ConfigureAwait(true);
new JsonRespons(url, new DefaultJsonSerializer());
}
dotnet add package Withings.NET
```

## CHANGE LOG

Version: 2.1.0 |
Release Date: April 03, 2017 |
New Features |
Get Ability To Get Body Measures

Version: 2.0.0 |
Release Date: April 03, 2017 |
Breaking API Change |
GetActivityMeasures Now Accepts DateTimes Instead of Strings for Dates

Version: 1.1.29 |
Release Date:April 02, 2017 |
New Features |
Add Abiltity To Get Sleep Measures

Version: 1.1.27 |
Release Date:April 02, 2017 |
New Features |
Add Abiltity To Get Workout Data

Version: 1.1.26 |
Release Date:April 02, 2017 |
New Features |
Add Abiltity To Get Sleep Summary Over A Range Of Days

Version: 1.1.23 |
Release Date:April 01, 2017 |
New Features |
Add Abiltity To Get Activity Measures For A Specific Day

Version: 1.1.0 |
Release Date:April 01, 2017 |
New Features |
Add Abiltity To Get Activity Measures For A Date Range

Version: 1.0.0 |
Release Date:March 06, 2017 |
New Features |
Complete Authorization Process
## Quick Start

### 1. Configure Credentials

```csharp
var credentials = new WithingsCredentials();
credentials.SetClientProperties("your_client_id", "your_client_secret");
credentials.SetCallbackUrl("http://localhost:8585/callback");
```

### 2. OAuth 2.0 Authorization

```csharp
var authenticator = new Authenticator(credentials);

// Generate the authorization URL and redirect the user
var url = authenticator.GetAuthCodeUrl("user.info,user.metrics,user.activity", state);

// After the user authorizes, exchange the code for tokens
var token = await authenticator.GetAccessToken(authorizationCode);

// Refresh tokens when they expire
var newToken = await authenticator.RefreshAccessToken(token.RefreshToken);
```

### 3. Fetch Health Data

```csharp
var client = new WithingsClient(credentials);

// Activity measures
var activity = await client.GetActivityMeasures(startDate, endDate, userId, accessToken);

// Body measures
var body = await client.GetBodyMeasures(userId, startDate, endDate, accessToken);

// Sleep summary
var sleep = await client.GetSleepSummary("2024-01-01", "2024-01-31", accessToken);

// Sleep measures
var sleepData = await client.GetSleepMeasures(userId, startDate, endDate, accessToken);

// Workouts
var workouts = await client.GetWorkouts("2024-01-01", "2024-01-31", accessToken);

// Intraday activity
var intraday = await client.GetIntraDayActivity(userId, startDate, endDate, accessToken);

// Heart
var heartList = await client.GetHeartList(startDate, endDate, accessToken);
var recording = await client.GetHeartRecording(signalId, accessToken);

// User
var devices = await client.GetDevices(accessToken);
var goals = await client.GetGoals(accessToken);

// Webhook subscriptions
await client.Subscribe(callbackUrl, appli, accessToken);
var subscriptions = await client.ListSubscriptions(appli, accessToken);
await client.RevokeSubscription(callbackUrl, appli, accessToken);
```

## Development

### Running Unit Tests

```bash
dotnet test --filter "TestCategory!=E2E"
```

### Running E2E Tests

E2E tests run against the live Withings API. You need to bootstrap OAuth tokens first.

1. Create a `.env` file in the project root:

```
WITHINGS_CLIENT_ID=your_client_id
WITHINGS_CLIENT_SECRET=your_client_secret
WITHINGS_CALLBACK_URL=http://localhost:8585/callback
WITHINGS_REFRESH_TOKEN=
WITHINGS_USER_ID=
```

2. Run the bootstrap script to obtain tokens:

```bash
./scripts/bootstrap-token.sh
```

3. Run E2E tests:

```bash
dotnet test --filter "TestCategory=E2E" -f net10.0
```

The E2E test suite automatically saves new refresh tokens back to `.env` after each run (Withings refresh tokens are single-use).

## API Reference

| Class | Description |
|-------|-------------|
| `Authenticator` | OAuth 2.0 authorization and token management |
| `WithingsClient` | API client for health data endpoints |
| `OAuthToken` | Token response with access token, refresh token, and user ID |
| `WithingsApiException` | Exception thrown for non-zero API status codes |

## License

See [LICENSE](LICENSE) for details.
9 changes: 4 additions & 5 deletions Withings.Example/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text.Json;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
Expand Down Expand Up @@ -27,10 +26,10 @@
});

var credentials = new WithingsCredentials();
credentials.SetCallbackUrl(Environment.GetEnvironmentVariable("WithingsCallbackUrl"));
credentials.SetConsumerProperties(
Environment.GetEnvironmentVariable("WithingsConsumerKey"),
Environment.GetEnvironmentVariable("WithingsConsumerSecret"));
credentials.SetCallbackUrl(Environment.GetEnvironmentVariable("WITHINGS_CALLBACK_URL"));
credentials.SetClientProperties(
Environment.GetEnvironmentVariable("WITHINGS_CLIENT_ID"),
Environment.GetEnvironmentVariable("WITHINGS_CLIENT_SECRET"));

builder.Services.AddSingleton(credentials);
builder.Services.AddSingleton<Authenticator>();
Expand Down
2 changes: 1 addition & 1 deletion Withings.Example/Withings.Example.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
Expand Down
Loading
Loading