A modern Home Assistant custom integration for Oura Ring using the v2 API with OAuth2 authentication.
⚠️ IMPORTANT: v2.0.0 Breaking Changes
If upgrading from v1.x.x, entity IDs changed fromsensor.oura_*tosensor.oura_ring_*
To preserve historical data: Rename your device to "Oura" after upgrading, then use "Rename entities" feature.
Full migration guide: v2.0.0 Release Notes
- OAuth2 Authentication: Secure authentication using Home Assistant's application credentials
- Comprehensive Data: 43 sensors covering all Oura Ring metrics including sleep, readiness, activity, stress, resilience, and more
- HA 2025.11 Compliant: Modern entity naming, translation keys, entity categories, and proper state classes
- Historical Data Loading: Automatically loads 14 days of historical data on first setup (configurable 1-90 days)
- Entity Categories: Diagnostic sensors properly categorized for better UI organization
- Multi-Account Support: Entry-scoped unique IDs allow multiple Oura accounts
- HACS Compatible: Easy installation and updates via HACS
- Modern Architecture: Configuration-driven design following latest Home Assistant standards
- Comprehensive Testing: 39 automated tests ensuring reliability
- Efficient Updates: Uses DataUpdateCoordinator with specialized processing methods
- Sleep Score
- Total Sleep Duration
- Deep Sleep Duration
- REM Sleep Duration
- Light Sleep Duration
- Awake Time
- Sleep Efficiency
- Restfulness
- Sleep Latency
- Sleep Timing
- Deep Sleep Percentage
- REM Sleep Percentage
- Time in Bed
- Readiness Score
- Temperature Deviation
- Resting Heart Rate Score (contribution score, not actual BPM)*
- HRV Balance Score (contribution score, not actual HRV)*
Note: Sensors marked with * may be unavailable if Oura doesn't have sufficient data to calculate the contributor score.
- Activity Score
- Steps
- Active Calories
- Total Calories
- Target Calories
- High Activity Time
- Medium Activity Time
- Low Activity Time
- Current Heart Rate (latest reading)
- Average Heart Rate (from recent readings)
- Minimum Heart Rate (from recent readings)
- Maximum Heart Rate (from recent readings)
- Average Sleep HRV (heart rate variability during sleep)
- Stress High Duration
⚠️ - Recovery High Duration
⚠️ - Stress Day Summary
⚠️
- Resilience Level
- Sleep Recovery Score
⚠️ - Daytime Recovery Score
⚠️ - Stress Resilience Score
⚠️
- SpO2 Average
- Breathing Disturbance Index
- VO2 Max
⚠️ - Cardiovascular Age
⚠️
- Optimal Bedtime Start
⚠️ - Optimal Bedtime End
⚠️
Total: 43 sensors
Important Notes:
- Sensors marked with
⚠️ may be unavailable for new Oura Ring users (typically the first few weeks of usage). The Oura API does not provide data for these sensors until sufficient baseline data has been collected. This is normal behavior and they may become available over time as you continue using your ring. - Some sensors marked with feature requirements may return 401 Unauthorized errors if your Oura account/ring doesn't have access to those features.
- The integration will continue to work with all available sensors - unavailable sensors simply won't display values until Oura provides data for them.
Click the button above to add this repository to HACS, or follow these manual steps:
- Open HACS in your Home Assistant instance
- Click on "Integrations"
- Click the three dots in the top right corner
- Select "Custom repositories"
- Add this repository URL:
https://github.com/louispires/oura-v2-custom-component - Select category: "Integration"
- Click "Add"
- Find "Oura Ring" in the integration list and click "Download"
- Restart Home Assistant
- Copy the
custom_components/ouradirectory to yourconfig/custom_components/directory - Restart Home Assistant
- Go to Oura Cloud
- Sign in with your Oura account
- Click "Create a New Application"
- Fill in the application details:
- Application Name: Home Assistant
- Application Website: Your Home Assistant URL
- Redirect URI:
https://my.home-assistant.io/redirect/oauth
- Save the Client ID and Client Secret
- In Home Assistant, go to Settings → Devices & Services
- Click on Application Credentials (in the top menu)
- Click Add Application Credential
- Note: You may see either a dropdown to select "Oura Ring" OR a generic form - both work!
- Enter your Client ID and Client Secret from Step 1
- Click Create
Important: Application Credentials is just for storing OAuth credentials. You won't see Oura Ring listed as an active integration here.
Now you can add the actual integration:
- In Home Assistant, go to Settings → Devices & Services
- Click Add Integration
- Search for "Oura Ring" - you should see it here!
- Click on it and follow the OAuth2 authentication flow
- You'll be redirected to Oura's website to authorize the integration
- After authorization, you'll be redirected back to Home Assistant
- The integration will be configured and sensors will start appearing
Once configured, sensors will appear under the Oura Ring integration. You can use these sensors in:
- Dashboards: Display your sleep, readiness, and activity data with beautiful charts
- Automations: Trigger actions based on your Oura Ring data
- Scripts: Use sensor values in your scripts
- Templates: Create custom sensors based on Oura data
For dashboard examples using ApexCharts, see the Dashboard Examples section below.
automation:
- alias: "Low Sleep Alert"
trigger:
- platform: numeric_state
entity_id: sensor.oura_sleep_score
below: 70
action:
- service: notify.mobile_app
data:
message: "Your sleep score is low. Consider resting today."The integration polls the Oura API with a configurable update interval (default: 5 minutes). You can configure this interval:
- Go to Settings → Devices & Services
- Find "Oura Ring" and click CONFIGURE
- Set your desired update interval (1-60 minutes)
- Set historical data days (1-90 days) - only loaded on first setup
- Click SUBMIT
The integration will automatically reload with the new interval. The default 5-minute interval is optimized to:
- Provide timely updates
- Minimize API calls
- Respect Oura's rate limits
On first setup, the integration automatically fetches historical data (default: 14 days) to populate your dashboards immediately. This means:
✅ Instant dashboard population - Your charts show data from day one
✅ No waiting period - See trends and patterns immediately
✅ One-time fetch - Historical data is only loaded once during initial setup
✅ Configurable - Choose 1-90 days of history based on your needs
After the initial historical load, the integration fetches only new data during regular updates (every 5 minutes by default), keeping API usage minimal.
The integration uses Home Assistant's Long-Term Statistics system to store historical data:
- Initial Setup: When you first add the integration, it fetches 14 days (or your configured amount) of historical data
- Statistics Import: All historical data points are imported as long-term statistics with proper timestamps
- Database Storage: Data is stored in Home Assistant's statistics database (separate from state history)
- Immediate Availability: All history graphs, ApexCharts, and Energy dashboard cards can access this data immediately
- Daily Updates: Ongoing updates only fetch new data (typically 1 day), which is much more efficient
Benefits of Long-Term Statistics:
- 📊 Works with all history visualization cards (ApexCharts, History Graph, Statistics Graph)
- 💾 Efficient database storage (optimized for long-term data)
- 🔄 Properly timestamped (each data point has the correct historical date)
- ⚡ Fast queries (statistics database is optimized for time-series data)
- 🎯 No fake "state changes" - clean, accurate historical data
The apexcharts-card is a highly customizable graphing card that works great with Oura data. Install it via HACS first.
Track your sleep, readiness, and activity scores over the past week:
yaml
type: custom:apexcharts-card
header:
show: true
title: Oura Scores
show_states: true
colorize_states: true
graph_span: 7d
span:
end: day
all_series_config:
type: column
opacity: 0.7
stroke_width: 8
group_by:
func: last
duration: 1d
series:
- entity: sensor.oura_sleep_score
name: Sleep
color: "#5E97F6"
- entity: sensor.oura_readiness_score
name: Readiness
color: "#FFA600"
- entity: sensor.oura_activity_score
name: Activity
color: "#00D9FF"
yaxis:
- min: 0
max: 100
apex_config:
tickAmount: 5Detailed sleep breakdown with durations:
yaml
type: custom:apexcharts-card
graph_span: 7d
header:
show: true
show_states: true
colorize_states: true
title: Sleep
standard_format: true
yaxis:
- id: left
opposite: false
min: 0
max: 10
apex_config:
title:
text: Total Sleep
- id: right
opposite: true
min: 0
max: 8
apex_config:
title:
text: Breakdown
series:
- entity: sensor.oura_sleep_score
name: Score
show:
in_chart: false
color: white
- entity: sensor.oura_average_heart_rate
name: Avg HR
show:
in_chart: false
- entity: sensor.oura_minimum_heart_rate
name: Lowest HR
show:
in_chart: false
- entity: sensor.oura_time_in_bed
name: In Bed
color: grey
type: area
show:
in_chart: true
in_header: false
yaxis_id: left
group_by:
duration: 1d
func: last
- entity: sensor.oura_total_sleep_duration
name: Total Sleep
color: purple
type: area
show:
in_chart: true
in_header: false
yaxis_id: left
group_by:
duration: 1d
func: last
- entity: sensor.oura_rem_sleep_duration
name: REM
color: "#20bf6b"
type: column
show:
in_chart: true
in_header: false
yaxis_id: right
group_by:
duration: 1d
func: last
- entity: sensor.oura_deep_sleep_duration
name: Deep
color: "#45aaf2"
type: column
show:
in_chart: true
in_header: false
yaxis_id: right
group_by:
duration: 1d
func: last
- entity: sensor.oura_light_sleep_duration
name: Light
color: "#fed330"
type: column
show:
in_chart: true
in_header: false
yaxis_id: right
group_by:
duration: 1d
func: last
- entity: sensor.oura_awake_time
name: Awake
color: "#fc5c65"
type: column
show:
in_chart: true
in_header: false
yaxis_id: right
group_by:
duration: 1d
func: lastMonitor your sleep efficiency over time:
yaml
type: custom:apexcharts-card
header:
show: true
title: Sleep Efficiency
show_states: true
graph_span: 14d
span:
end: day
series:
- entity: sensor.oura_sleep_efficiency
name: Efficiency
color: '#4CAF50'
stroke_width: 3
type: line
curve: smooth
group_by:
func: last
duration: 1d
yaxis:
- min: 0
max: 100
apex_config:
tickAmount: 5Track heart rate scores and HRV:
yaml
type: custom:apexcharts-card
header:
show: true
title: Heart Health
show_states: true
graph_span: 7d
span:
end: day
series:
- entity: sensor.oura_resting_heart_rate
name: Resting HR
color: "#E91E63"
stroke_width: 2
type: line
curve: smooth
group_by:
func: last
duration: 1d
yaxis_id: hr
- entity: sensor.oura_hrv_balance
name: HRV Balance
color: "#00BCD4"
stroke_width: 2
type: line
curve: smooth
group_by:
func: last
duration: 1d
yaxis_id: hrv
- entity: sensor.oura_average_sleep_hrv
name: Sleep HRV
color: "#287233"
stroke_width: 2
type: line
curve: smooth
group_by:
func: last
duration: 1d
yaxis_id: hrv
yaxis:
- id: hr
min: 40
max: 80
apex_config:
tickAmount: 4
title:
text: BPM
- id: hrv
opposite: true
min: 0
max: 100
apex_config:
tickAmount: 4
title:
text: HRVyaml
type: custom:apexcharts-card
header:
show: true
title: Daily Activity
show_states: true
graph_span: 7d
span:
end: day
series:
- entity: sensor.oura_steps
name: Steps
color: '#4CAF50'
stroke_width: 2
type: column
opacity: 0.7
group_by:
func: last
duration: 1d
yaxis_id: steps
- entity: sensor.oura_active_calories
name: Calories
color: '#FF9800'
stroke_width: 2
type: line
curve: smooth
group_by:
func: last
duration: 1d
yaxis_id: calories
yaxis:
- id: steps
apex_config:
tickAmount: 4
title:
text: Steps
- id: calories
opposite: true
apex_config:
tickAmount: 4
title:
text: CaloriesTrack body temperature trends:
yaml
type: custom:apexcharts-card
header:
show: true
title: Temperature Deviation
show_states: true
graph_span: 30d
span:
end: day
series:
- entity: sensor.oura_temperature_deviation
name: Deviation
color: '#FF5722'
stroke_width: 2
type: line
curve: smooth
group_by:
func: last
duration: 1d
yaxis:
- min: -2
max: 2
apex_config:
tickAmount: 4
decimalsInFloat: 1For a quick overview without ApexCharts:
yaml
type: entities
title: Oura Ring Summary
entities:
- entity: sensor.oura_sleep_score
secondary_info: last-changed
name: Sleep Score
- entity: sensor.oura_readiness_score
secondary_info: last-changed
name: Readiness Score
- entity: sensor.oura_activity_score
secondary_info: last-changed
name: Activity Score
- type: divider
- entity: sensor.oura_total_sleep_duration
secondary_info: last-changed
name: Total Sleep
- entity: sensor.oura_time_in_bed
name: Time in Bed
secondary_info: last-changed
- entity: sensor.oura_deep_sleep_duration
secondary_info: last-changed
name: Deep Sleep
- entity: sensor.oura_rem_sleep_duration
secondary_info: last-changed
name: REM Sleep
- type: divider
- entity: sensor.oura_steps
secondary_info: last-changed
name: Steps Today
- entity: sensor.oura_active_calories
secondary_info: last-changed
name: Active Calories
- entity: sensor.oura_current_heart_rate
secondary_info: last-changed
- entity: sensor.oura_average_heart_rate
secondary_info: last-changed
- entity: sensor.oura_minimum_heart_rate
secondary_info: last-changed
- entity: sensor.oura_maximum_heart_rate
secondary_info: last-changedVisual representation of your scores:
yaml
type: horizontal-stack
cards:
- type: gauge
entity: sensor.oura_sleep_score
name: Sleep
needle: true
min: 0
max: 100
severity:
green: 85
yellow: 70
red: 0
- type: gauge
entity: sensor.oura_readiness_score
name: Readiness
needle: true
min: 0
max: 100
severity:
green: 85
yellow: 70
red: 0
- type: gauge
entity: sensor.oura_activity_score
name: Activity
needle: true
min: 0
max: 100
severity:
green: 85
yellow: 70
red: 0If you encounter authentication issues:
- Verify your Client ID and Client Secret are correct
- Ensure the Redirect URI matches exactly in both Oura Cloud and Home Assistant
- Check Home Assistant logs for specific error messages
- Try removing and re-adding the integration
If some sensors are not appearing:
- Ensure your Oura Ring is synced with the Oura app
- Check that you have recent data in the Oura app
- Wait for the next update cycle (default: 5 minutes)
- Check Home Assistant logs for errors
Some sensors may show as "unavailable" when Oura doesn't have sufficient data or hasn't established baseline measurements:
Common for all users (temporary unavailability):
- Resting Heart Rate Score: Requires sufficient heart rate measurements during rest periods
- HRV Balance Score: Requires sufficient HRV data collection (usually from sleep)
Common for new ring users (may take weeks to become available):
- Cardiovascular Age: Requires extended baseline data collection
- VO2 Max: Requires sufficient activity and cardiovascular data
- Stress/Recovery Metrics: Stress High Duration, Recovery High Duration, Stress Day Summary
- Resilience Scores: Sleep Recovery Score, Daytime Recovery Score, Stress Resilience Score
- Sleep Optimization: Optimal Bedtime Start, Optimal Bedtime End
This is normal behavior, especially:
- In the first few weeks of wearing your ring - Most advanced metrics require baseline establishment
- After periods of not wearing the ring
- If you haven't had sufficient sleep for HRV measurements
- During data processing delays
These sensors will automatically become available once Oura collects and processes the necessary baseline data. The Oura API simply does not provide values for these sensors until sufficient data history exists.
If you see rate limiting errors:
- The integration is designed to respect Oura's API limits
- Avoid manually triggering updates too frequently
- Check if you have other integrations also accessing the Oura API
This integration is built using modern Home Assistant patterns:
- OAuth2 Flow: Uses Home Assistant's built-in OAuth2 implementation
- DataUpdateCoordinator: Efficient data fetching with 12 specialized processing methods
- Configuration-Driven Design: Maintainable, declarative structures throughout
- Modern Entity Standards:
has_entity_name=True, translation keys, entity categories - Entry-Scoped IDs: Multi-account support with proper unique ID scoping
- Type Hints: Full type hint coverage for better code quality
- Async: All operations are asynchronous
- Error Handling: Comprehensive error handling and clean logging
- Test Coverage: 39 automated tests with comprehensive fixtures
- Code Efficiency: 51.5% code reduction in statistics module through refactoring
Contributions are welcome! Please read our Contributing Guide for details on our code of conduct and the process for submitting pull requests.
- Installation Guide - Detailed setup instructions
- Quick Reference - Quick reference for common tasks
- Troubleshooting - Common issues and solutions
- Redirect URI Fix - OAuth redirect URI troubleshooting
- Project Summary - Technical overview and architecture
This project is licensed under the MIT License.
- Original Oura Component: nitobuendia/oura-custom-component
- Oura Ring API: Oura Cloud API Documentation
- v2.0.0 Modernization: Comprehensive refactoring to HA 2025.11 standards
- Test Infrastructure: Docker-based testing with 39 automated tests
- Development assisted by: Claude Sonnet 4.5 (Anthropic AI)
If this integration is helpful, feel free to Buy Me a Coffee; or check other options on the Github ❤️ Sponsor link on the top of this page.
If you encounter any issues or have questions:
- Check the Issues page
- Create a new issue with detailed information
- Include relevant logs from Home Assistant
This is an unofficial integration and is not affiliated with or endorsed by Oura Health Oy.