Skip to content

Fix sleep data parsing to match actual API response#11

Open
talison wants to merge 1 commit intosteipete:mainfrom
talison:fix-sleep-data-parsing
Open

Fix sleep data parsing to match actual API response#11
talison wants to merge 1 commit intosteipete:mainfrom
talison:fix-sleep-data-parsing

Conversation

@talison
Copy link
Copy Markdown

@talison talison commented Jan 31, 2026

Summary

This PR addresses two issues with the sleep commands:

  1. Range command flag parsing (sleep_range.go): The --from and --to flags were being read via viper.GetString() which wasn't receiving the flag values properly. Changed to read directly from cobra's cmd.Flags().GetString().

  2. SleepDay struct field mapping (eightsleep.go): The struct fields didn't match the actual API response structure. The API returns:

    • sleepDuration (not sleepDurationSeconds)
    • deepDuration, remDuration, lightDuration for sleep stages
    • sleepStart, sleepEnd timestamps
    • Nested sleepQualityScore with hrv.current, heartRate.current, etc.

Changes

Updated the struct and commands to properly parse and display:

  • Sleep duration in hours (more readable than seconds)
  • Deep/REM/Light sleep durations
  • Sleep start/end times
  • RHR (resting heart rate)
  • HRV
  • Respiratory rate

Before/After

Before:

date        score  duration  tnt  resp_rate  heart_rate  hrv_score
2026-01-30  94     0         9    0          0           0

After:

date        score  duration_hrs  deep_hrs  rem_hrs  light_hrs  rhr  hrv   resp_rate  tnt
2026-01-30  94     7.1           1.5       1.9      3.5        57   54.9  15.3       9

Test plan

  • Tested eightctl sleep day against live API
  • Tested eightctl sleep range --from X --to Y against live API
  • Verified JSON output format

🤖 Generated with Claude Code

This PR addresses two issues with the sleep commands:

1. **Range command flag parsing** (`sleep_range.go`): The `--from` and `--to`
   flags were being read via `viper.GetString()` which wasn't receiving the
   flag values properly. Changed to read directly from cobra's
   `cmd.Flags().GetString()`.

2. **SleepDay struct field mapping** (`eightsleep.go`): The struct fields
   didn't match the actual API response structure. The API returns:
   - `sleepDuration` (not `sleepDurationSeconds`)
   - `deepDuration`, `remDuration`, `lightDuration` for sleep stages
   - `sleepStart`, `sleepEnd` timestamps
   - Nested `sleepQualityScore` with `hrv.current`, `heartRate.current`, etc.

Updated the struct and commands to properly parse and display:
- Sleep duration in hours
- Deep/REM/Light sleep durations
- Sleep start/end times
- RHR (resting heart rate)
- HRV
- Respiratory rate

Tested against live Eight Sleep API.
davidfencik pushed a commit to davidfencik/eightctl that referenced this pull request Feb 20, 2026
Corrects field mappings for sleep data parsing:
- sleepDuration (not sleepDurationSeconds)
- Adds deepDuration, remDuration, lightDuration, sleepStart/End
- Properly nests sleepQualityScore with hrv, heartRate, respiratoryRate
- Fixes sleep range --from/--to flag parsing (read from cobra, not viper)
- Displays durations in hours for readability

Inspired by talison's analysis in steipete#11.
@omarshahine
Copy link
Copy Markdown
Collaborator

Hey @talison — thanks for digging into the actual API response structure and testing against the live API. The before/after comparison really shows the problem clearly.

A few things I'd like to see before we merge:

  1. Could you split this into two PRs? The --from/--to flag fix (viper → cobra) is a straightforward bug fix for metrics trends --from/--to flags are ignored (empty query values) #20, while the SleepDay struct overhaul is a larger change. Separating them makes each easier to review and land.

  2. Breaking output changes — column renames (durationduration_hrs, heart_raterhr, dropping latency_asleep/latency_out) will break anyone scripting against the CLI output. We should be intentional about that.

  3. Indentation — there's a stray indentation issue in sleep_range.go (the "Convert durations" comment has an extra tab).

  4. Rebase needed — main has moved significantly since this was opened, so you'll need to rebase. The eightsleep.go client file changed quite a bit in the recent auth fixes.

The struct changes themselves look correct based on your live API testing. Happy to help if you have questions about rebasing. Thanks!

@omarshahine
Copy link
Copy Markdown
Collaborator

Update: PR #31 just merged and addresses the --from/--to flag parsing issue (#20) by reading directly from cmd.Flags() and removing the global Viper bindings. It also removed metrics summary and metrics aggregate (those endpoints are dead).

The remaining value in this PR is the SleepDay struct overhaul to match the actual API response. If you'd like to continue with that, you'd need to:

  1. Rebase onto current main (significant changes to the client layer)
  2. Drop the --from/--to flag fix (already landed)
  3. Drop the sleep_range.go changes to from/to (already landed)
  4. Focus on just the struct changes + display updates in sleep.go and sleep_range.go

Happy to help if you want to pick this back up. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants