Oura Ring 統合
ユーザーのOura Ringに接続し、Oura Cloud API V2を介して睡眠、心拍数、準備度、活動、その他の健康データを取得します。
前提条件
- Oura Ring(Gen3またはRing4)とアクティブなOuraメンバーシップ(APIアクセスには月額6ドル必要)
- Ouraアプリがインストールされ、リングとペアリング済みであること
- https://cloud.ouraring.com のOura Cloudアカウント
セットアップ
1. 開発者アプリケーションの登録
ユーザーに https://developer.ouraring.com/applications にアクセスしてもらい、新しいアプリケーションを作成します:
- 表示名: ユーザーが希望する統合用の名前
- 説明: 統合の簡単な説明
- 連絡先メール: ユーザーのメールアドレス
- ウェブサイト: 有効なURL(個人のウェブサイトなど)
- プライバシーポリシー / 利用規約: 有効なURL(必須項目ですが、個人アプリでは厳密に確認されません)
- リダイレクトURI:
http://localhost:3000/callback - スコープ: 必要なすべてのスコープを有効にします。推奨:
personal,daily,heartrate,sleep,workout,spo2,stress,heart_health,session,ring_configuration
クライアントID と クライアントシークレット を保存します。
2. OAuthフローの実行
クライアントシークレットを assistant credentials prompt で安全に保存し、OAuthヘルパースクリプトを作成してユーザーのマシンで実行します:
#!/usr/bin/env python3
"""Oura Ring OAuth2ヘルパー — 認証コードをキャッチし、即座にトークンに交換します。"""
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs, urlencode
import urllib.request, json, webbrowser, ssl
CLIENT_ID = 'YOUR_CLIENT_ID'
CLIENT_SECRET = 'YOUR_CLIENT_SECRET'
REDIRECT_URI = 'http://localhost:3000/callback'
SCOPES = 'email personal daily heartrate workout tag session spo2 ring_configuration stress heart_health'
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
parsed = urlparse(self.path)
if parsed.path == '/':
params = urlencode({
'response_type': 'code', 'client_id': CLIENT_ID,
'redirect_uri': REDIRECT_URI, 'scope': SCOPES, 'state': 'assistant'
})
self.send_response(302)
self.send_header('Location', f'https://cloud.ouraring.com/oauth/authorize?{params}')
self.end_headers()
elif parsed.path == '/callback':
code = parse_qs(parsed.query).get('code', [''])[0]
if code:
token_data = urlencode({
'grant_type': 'authorization_code', 'code': code,
'redirect_uri': REDIRECT_URI, 'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
}).encode()
try:
req = urllib.request.Request('https://api.ouraring.com/oauth/token',
data=token_data,
headers={'Content-Type': 'application/x-www-form-urlencoded'},
method='POST')
resp = urllib.request.urlopen(req, context=ssl.create_default_context())
result = json.loads(resp.read())
with open('/tmp/oura_tokens.json', 'w') as f:
json.dump(result, f, indent=2)
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.end_headers()
self.wfile.write(b'<html><body><h1>接続完了!このタブは閉じて構いません。</h1></body></html>')
print(f'\nトークンを /tmp/oura_tokens.json に保存しました')
except Exception as e:
self.send_response(500)
self.end_headers()
self.wfile.write(f'トークン交換に失敗しました: {e}'.encode())
def log_message(self, *a): pass
print('Oura認証のためにブラウザを開きます...')
webbrowser.open('http://localhost:3000')
HTTPServer(('localhost', 3000), Handler).serve_forever()
ユーザーのマシンで python3 /path/to/script.py を実行します(host_bash)。ユーザーがブラウザで認証すると、スクリプトがコードをキャッチし、1秒未満でトークンに交換します。
重要: 認証コードは約30秒で期限切れになります。ユーザーに手動でコードを貼り付けさせないでください — このスクリプトを使用して自動的にキャッチし、交換してください。
3. トークンの保存
OAuthフローの後、/tmp/oura_tokens.json からトークンを読み取り、保存します:
access_token—api.ouraring.comのAuthorizationヘッダー(Bearerプレフィックス)および `allowed_tools: [