Add Google Health Plugin#96
Conversation
Integrates the Google Health API (v4, successor to the Fitbit Web API) with Google OAuth 2.0 auth-code flow and automatic token refresh. - Imports the authenticated user and paired devices as objects - 13 data streams: daily/intraday activity metrics, nutrition and per-item food log, macro breakdown, sleep sessions, workouts, heart rate (intraday + daily zones), body measurements, profile and devices - Personal goals (steps, calories, macros, sleep, water) set at config level; gauges, monitors, status columns and chart colours all derive from them - 7 single-pane dashboards: Today, Activity, Diet & Nutrition, Trends Over Time, Sleep, plus User and Device perspectives - Sub-24h timeframes snap to the current civil day so "24 hours" means today, matching the app's daily view Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Allow all timeframes (including custom day ranges like Yesterday) on every range-driven data stream; day-length timeframes resolve to the calendar day they end in, handling exclusive-midnight ends correctly - Clamp intraday streams to midnight-to-midnight of the target day so the Today dashboard covers the calendar day, with hour-aligned windows - Plot actual values instead of % of goal on the Sleep Duration, Daily Steps and Active Zone Minutes bar charts, keeping goal-completion colours via hidden computed goal-band columns, with bar labels off - Move the Sleep Stages Breakdown legend to the right - Show time-only x-axis labels on the by-hour Today tiles via a computed HH:mm label column (charts ignore date column formats) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…owns - Order Calories by Meal top-to-bottom as Anytime, Breakfast, Lunch, Dinner by re-ranking the foodLog mealOrder column and sorting the tile by it - Keep Activity tiles tied to the dashboard timeframe (defaulting to last7days) rather than pinning per tile - Unhide Goal, % of Goal and Goal Status columns in dailyMetric and sleepSessions so tile drilldowns show goal context, and drop the stale formatExpressions that rendered the % columns as raw values Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follows the Before you start / OAuth credentials / Configuring the plugin / Troubleshooting structure used by the Google Search Console and Google Sheets plugins, and documents that daily goals cannot be imported from the API and must be entered manually in the config. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI (base), Organization UI (inherited) Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (10)
📝 WalkthroughWalkthroughAdds a complete Google Health v1 plugin with OAuth configuration, health and nutrition data streams, response transformations, indexed user/device objects, default dashboards, and setup documentation. ChangesGoogle Health plugin
Sequence Diagram(s)sequenceDiagram
participant User
participant GoogleHealthOAuth
participant GoogleHealthAPI
participant DataStreamScripts
participant Dashboards
User->>GoogleHealthOAuth: provide client credentials
GoogleHealthOAuth->>GoogleHealthAPI: authorize API access
GoogleHealthAPI->>DataStreamScripts: return health datapoints
DataStreamScripts->>Dashboards: provide normalized metrics
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
Comment |
There was a problem hiding this comment.
Actionable comments posted: 9
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@plugins/GoogleHealth/v1/dataStreams/dailyMetric.json`:
- Line 4: Update the description field in the dailyMetric stream to mention only
the supported metrics: steps, distance, floors, active zone minutes, active
calories, and hydration. Keep it concise, neutral, and as a single sentence
without a final full stop.
In `@plugins/GoogleHealth/v1/dataStreams/scripts/dailyMetric.js`:
- Around line 106-124: Update the empty snapshot record construction in the
daily metric flow to use the snapped day containing timeframe.end minus 1
millisecond, rather than timeframe.end itself. Preserve the existing zero value,
goal, percentage, unit, and metric fields while correcting the date used in the
generated record.
In `@plugins/GoogleHealth/v1/dataStreams/scripts/foodLog.js`:
- Line 30: Update the calories mapping in the food-log transformation so
Math.round is only applied when energy.kcal is present and valid; otherwise emit
undefined instead of NaN. Preserve the existing rounding behavior for valid kcal
values and use the existing N conversion.
In `@plugins/GoogleHealth/v1/dataStreams/scripts/heartRateZonesDaily.js`:
- Around line 5-8: Update durMin to return the finite duration value divided by
60 without rounding, preserving fractional minutes for zone and total
calculations; leave invalid or non-string input handling unchanged and defer
formatting to the later presentation logic.
In `@plugins/GoogleHealth/v1/dataStreams/scripts/sleepSessions.js`:
- Around line 49-52: Update the stage duration mappings in the sleep session
transformation so valid zero-minute values for DEEP, REM, LIGHT, and AWAKE are
preserved rather than converted to undefined. Replace truthiness-based fallbacks
in the affected expressions with nullish handling, while retaining undefined for
genuinely absent stage values and preserving the existing awake fallback
behavior.
In `@plugins/GoogleHealth/v1/dataStreams/scripts/userProfile.js`:
- Around line 29-39: Update the userProfile stream configuration to declare its
single-record output by using httpRequestScopedSingle or setting objectLimit to
1. Keep the transformation in the userProfile script unchanged.
- Line 36: Update the walkingStrideCm assignment to use
autoWalkingStrideLengthMm when userConfiguredWalkingStrideLengthMm is missing,
matching the existing fallback behavior used for the running stride while
preserving manual values when present.
In `@plugins/GoogleHealth/v1/dataStreams/sleepSessions.json`:
- Around line 167-171: Update the sleepStatus metadata in the sleep session data
stream so its displayName capitalization matches the surrounding metadata naming
convention, changing “sleep Status” to the correctly capitalized status label
while leaving the computed expression and shape unchanged.
In `@plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json`:
- Line 443: Normalize the affected dashboard tile titles to title case: update
plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json lines 443-443 to
“Macro Split (Calories)” and 485-485 to “Macros (Grams)”; update
plugins/GoogleHealth/v1/defaultContent/trends.dash.json lines 190-190 to
“Calories Consumed (30 Days)” and 231-231 to “Active Calories Burned (30 Days)”.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro
Run ID: fbf4a34a-cd2c-4717-b113-3e856d87819e
⛔ Files ignored due to path filters (1)
plugins/GoogleHealth/v1/icon.svgis excluded by!**/*.svg
📒 Files selected for processing (41)
plugins/GoogleHealth/v1/configValidation.jsonplugins/GoogleHealth/v1/custom_types.jsonplugins/GoogleHealth/v1/dataStreams/bodyMetric.jsonplugins/GoogleHealth/v1/dataStreams/dailyHealthMetric.jsonplugins/GoogleHealth/v1/dataStreams/dailyMetric.jsonplugins/GoogleHealth/v1/dataStreams/foodLog.jsonplugins/GoogleHealth/v1/dataStreams/heartRateIntraday.jsonplugins/GoogleHealth/v1/dataStreams/heartRateZonesDaily.jsonplugins/GoogleHealth/v1/dataStreams/intradayMetric.jsonplugins/GoogleHealth/v1/dataStreams/macroBreakdown.jsonplugins/GoogleHealth/v1/dataStreams/nutritionDaily.jsonplugins/GoogleHealth/v1/dataStreams/pairedDevices.jsonplugins/GoogleHealth/v1/dataStreams/scripts/bodyMetric.jsplugins/GoogleHealth/v1/dataStreams/scripts/dailyHealthMetric.jsplugins/GoogleHealth/v1/dataStreams/scripts/dailyMetric.jsplugins/GoogleHealth/v1/dataStreams/scripts/foodLog.jsplugins/GoogleHealth/v1/dataStreams/scripts/heartRateIntraday.jsplugins/GoogleHealth/v1/dataStreams/scripts/heartRateZonesDaily.jsplugins/GoogleHealth/v1/dataStreams/scripts/intradayMetric.jsplugins/GoogleHealth/v1/dataStreams/scripts/macroBreakdown.jsplugins/GoogleHealth/v1/dataStreams/scripts/nutritionDaily.jsplugins/GoogleHealth/v1/dataStreams/scripts/pairedDevices.jsplugins/GoogleHealth/v1/dataStreams/scripts/sleepSessions.jsplugins/GoogleHealth/v1/dataStreams/scripts/userProfile.jsplugins/GoogleHealth/v1/dataStreams/scripts/workouts.jsplugins/GoogleHealth/v1/dataStreams/sleepSessions.jsonplugins/GoogleHealth/v1/dataStreams/userProfile.jsonplugins/GoogleHealth/v1/dataStreams/workouts.jsonplugins/GoogleHealth/v1/defaultContent/activity.dash.jsonplugins/GoogleHealth/v1/defaultContent/devicePerspective.dash.jsonplugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.jsonplugins/GoogleHealth/v1/defaultContent/manifest.jsonplugins/GoogleHealth/v1/defaultContent/scopes.jsonplugins/GoogleHealth/v1/defaultContent/sleep.dash.jsonplugins/GoogleHealth/v1/defaultContent/today.dash.jsonplugins/GoogleHealth/v1/defaultContent/trends.dash.jsonplugins/GoogleHealth/v1/defaultContent/userPerspective.dash.jsonplugins/GoogleHealth/v1/docs/README.mdplugins/GoogleHealth/v1/indexDefinitions/default.jsonplugins/GoogleHealth/v1/metadata.jsonplugins/GoogleHealth/v1/ui.json
| "z": 0, | ||
| "config": { | ||
| "_type": "tile/data-stream", | ||
| "title": "Macro Split (calories)", |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Normalize title case across the affected dashboard tiles.
plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json#L443-L443: rename toMacro Split (Calories).plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json#L485-L485: rename toMacros (Grams).plugins/GoogleHealth/v1/defaultContent/trends.dash.json#L190-L190: rename toCalories Consumed (30 Days).plugins/GoogleHealth/v1/defaultContent/trends.dash.json#L231-L231: rename toActive Calories Burned (30 Days).
As per coding guidelines, “Out-of-the-box dashboard and tile names must use title case.”
📍 Affects 2 files
plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json#L443-L443(this comment)plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json#L485-L485plugins/GoogleHealth/v1/defaultContent/trends.dash.json#L190-L190plugins/GoogleHealth/v1/defaultContent/trends.dash.json#L231-L231
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json` at line 443,
Normalize the affected dashboard tile titles to title case: update
plugins/GoogleHealth/v1/defaultContent/dietNutrition.dash.json lines 443-443 to
“Macro Split (Calories)” and 485-485 to “Macros (Grams)”; update
plugins/GoogleHealth/v1/defaultContent/trends.dash.json lines 190-190 to
“Calories Consumed (30 Days)” and 231-231 to “Active Calories Burned (30 Days)”.
Source: Coding guidelines
- Limit the dailyMetric description to the metrics its selector offers - Attribute the empty single-day snapshot to the snapped day (timeframe.end - 1ms) rather than the day containing the raw end - Guard foodLog calories against NaN when energy.kcal is absent - Preserve fractional minutes in heart-rate zone durations so per-zone and total minutes sum accurately (display still rounds) - Keep legitimate zero-minute sleep stages while leaving stages blank for sessions with no stage data at all - Fall back to the auto-calculated walking stride when no manual value is configured, matching the running stride - Capitalize status column display names and tile title case Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🧩 Plugin PR Summary📦 Modified Plugins
📋 Results
🔍 Validation Details✅
|
🔌 Plugin overview
There has been consistent demand from the community for a modern replacement. This plugin brings personal health and fitness data from Google Health (Fitbit / Pixel devices) into SquaredUp, providing dashboards for the complete suite of activity, health and sleep metrics.
data. Anyone using a Fitbit / Pixel device who wants a good quality dashboard.
user-supplied Google Cloud project with the Google Health API enabled
(client ID + client secret, then interactive Google sign-in).
🖼️ Plugin screenshots
Plugin configuration
Default dashboards
Today
Activity
Diet & Nutrition
Trends over time
Sleep
User
Device
⚙️ Configuration
Setup needs a Google Cloud project with the Google Health API enabled and an
OAuth client (client ID + secret), then an interactive Google sign-in — the
docs README walks through this step by step, matching the format of the other
Google plugins.
The config also has a Daily goals section (steps, distance, active
calories, zone minutes, sleep, water, calorie/protein/carb/fat budgets). The
Google Health API does not expose the goals set in the Fitbit app, so they
can't be imported. However, users can enter them manually (as they do in the Google Health app), with sensible defaults
pre-filled.
The default dashboard gauges fill towards these targets, and the goal-based colouring
(green/amber/red) across the dashboards is measured against them (without needing monitoring enabled!).
🧪 Testing
squaredupCLI (squaredup test) across multiple timeframes, verifyingshaped rows, computed columns (goal %, status, goal bands) and formatting.
Trends Over Time, User and Device perspectives) verified in-product against
real Fitbit data, including drilldown tables and goal-based bar colouring.
timeframe ≤ 25 hours resolves to the calendar day it ends in.
squaredup validatepasses.goals set in the Fitbit app, so they're configured in the data source
rather than imported.
(
users/me), so this is a personal dashboard rather than a fleet view.API's civil timestamps are handled); for users far from UTC the "day"
window is offset from local midnight.
streams treat any timeframe ≤ 25 hours as the calendar day it ends in
(midnight-to-midnight) — this is what powers the Today dashboard.
heart-rate–derived metrics); longer trends are viewed month by month.
📚 Checklist
Summary by CodeRabbit