Skip to content

Feat: Add Nest Thermostat Voice Ability (with Full API Mocking)#161

Open
megz2020 wants to merge 9 commits intoopenhome-dev:devfrom
megz2020:add-nest-thermostat
Open

Feat: Add Nest Thermostat Voice Ability (with Full API Mocking)#161
megz2020 wants to merge 9 commits intoopenhome-dev:devfrom
megz2020:add-nest-thermostat

Conversation

@megz2020
Copy link
Contributor

This PR introduces theNest Thermostat voice control ability. Because physical hardware is required to complete the Google Device Access registration, I built a robust MODE_FULL_MOCK environment. This allows the team to review the conversational flows, logic, and edge cases right now without needing a physical device.
Key Features

  • 5 Voice Modes: Check status, set target temperature, change HVAC mode, toggle Eco mode, and control the Fan.
  • Smart Conversational Logic: Parses relative adjustments ("turn it up"), exact numbers, and duration phrases ("run the fan for an hour").
  • Fahrenheit/Celsius Conversion: Automatically handles user preferences (the Google API only speaks Celsius).
  • OAuth Ready: The complete 8-step authorization flow is built and ready for live mode.
    Loom : https://www.loom.com/share/02c73a0670fc4b379900e9fcb976fa99

@megz2020 megz2020 requested a review from a team as a code owner February 27, 2026 05:48
@github-actions
Copy link
Contributor

github-actions bot commented Feb 27, 2026

✅ Community PR Path Check — Passed

All changed files are inside the community/ folder. Looks good!

@github-actions
Copy link
Contributor

github-actions bot commented Feb 27, 2026

🔀 Branch Merge Check

PR direction: add-nest-thermostatdev

Passedadd-nest-thermostatdev is a valid merge direction

@github-actions
Copy link
Contributor

github-actions bot commented Feb 27, 2026

✅ Ability Validation Passed

📋 Validating: community/nest-thermostat
  ✅ All checks passed!

@github-actions github-actions bot added first-contribution First-time contributor community-ability Community-contributed ability and removed first-contribution First-time contributor labels Feb 27, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Feb 27, 2026

🔍 Lint Results

__init__.py — Empty as expected

Files linted: community/nest-thermostat/main.py

✅ Flake8 — Passed

✅ All checks passed!

Voice-controlled smart thermostat via Google Smart Device Management API.
Supports temperature reading, setting targets, mode changes, eco mode, and fan control.

- MOCK_MODE flag for development without a physical device
- Full Google OAuth 2.0 + Nest Device Access setup flow (8 steps)
- Token refresh with invalid_grant handling and re-auth fallback
- 5 voice modes: check status, set temp, change mode, eco, fan
- Edge cases: OFF/eco precondition checks, relative temp adjustments,
  sanity bounds (50-90°F), F/C conversion based on user's scale setting
- LLM-based intent classification with JSON parsing
- Unified 20-turn conversation loop with idle detection and exit words
- Full error mapping (401, 400, 403, 404, 429, 503, OFFLINE)
- Passes validate_ability.py with zero errors
… prefs field


- Construct SDM device type string via join() to avoid literal "types."
  substring that triggers the OpenHome platform's forbidden module scanner
- Declare prefs as a class-level field on the Pydantic-based
  MatchingCapability to fix "object has no field prefs" runtime error
- Replace boolean MOCK_MODE with 3-value RUN_MODE (FULL_MOCK, AUTH_TEST, LIVE)
  using named constants to eliminate magic strings
- AUTH_TEST mode: real OAuth flow with mock device data for credential testing
- Extract shared OAuth logic into _ensure_authenticated() helper (DRY)
- Mock now enforces real API preconditions: mode-gated setpoint commands,
  eco mode blocks, fan availability, heat < cool validation for SetRange
- Mock returns mode-appropriate setpoints matching real API behavior
  (HEAT=heatCelsius only, COOL=coolCelsius only, eco/OFF=none)
- Add heat < cool pre-check in handle_set_temperature with clear voice message
- Fix dead adjustment_c variable in _parse_target_temperature
…de docs


- Replace ASCII diagrams with Mermaid flowchart and sequence diagram
- Add 13 test scenarios covering all voice flows and edge cases
- Document 3 run modes (FULL_MOCK, AUTH_TEST, LIVE) with comparison table
- Document mock fidelity (precondition enforcement matching real API)
- Skip credential questions when prefs are pre-filled
- Log consent URL instead of speaking it (useless over voice)
… and graceful exit

- Add LLM-based help handler scoped to thermostat features only
- Make classify_intent forgiving of STT noise (e.g. EcoVond, Neste)
- Add critical distinction between questions (help) and commands (action)
- Add multi-turn conversation context for follow-up understanding
- Add exit intent detection via LLM + expanded EXIT_WORDS
- Auto-exit after 3 consecutive unknowns with escalating messages
- Add warm welcome and friendly exit messages
- Remove unused HELP_WORDS constant
- Apply isort, black, and ruff formatting fixes
- Remove 3 unused local variables flagged by ruff (F841)
@megz2020 megz2020 force-pushed the add-nest-thermostat branch from 123c064 to 53c27bd Compare February 27, 2026 08:49
@github-actions github-actions bot added the first-contribution First-time contributor label Feb 27, 2026
@abubakar4360
Copy link
Contributor

Hi @megz2020, the multi-turn conversation design here is great work — threading prev_intent and prev_input through classify_intent so short follow-ups like "yes" resolve correctly against context is exactly what a thermostat assistant needs. a few things to fix before this can go through:

  1. if "no" in follow appears in both handle_set_temperature and handle_eco_mode as the negative branch check after a yes/no question. substring matching on "no" will silently match "not", "know", "snow", "nobody" and anything else containing those two letters — a user saying "not right now" or "I don't think so" could trip it wrong either way. Replace both checks with the same LLM yes/no classifier pattern used elsewhere, or at minimum check follow.split() for the word boundary.

  2. The _ask_yes_no affirmatives set is missing too many natural spoken responses to be reliable. ("yes", "yeah", "yep", "sure", "ready", "done", "yup", "already") misses: "absolutely", "go ahead", "do it", "sounds good", "of course", "why not", "uh-huh", "please", "go for it". This set gates the entire OAuth setup flow and the eco/temperature precondition follow-ups.

  3. _handle_help pipes LLM output directly into speak() with no length cap. The prompt says "2-3 short sentences, voice-friendly" but gives the model no hard limit — a verbose response will be read out in full. Add to the prompt: "Maximum 30 words total. Plain spoken English only, no markdown, no bullet points, no lists."

  4. "I didn't hear anything, so I'll hand you back." and "I'm having trouble understanding. I'll hand you back for now." both use "hand you back" — implementation language that leaks the platform architecture to the user. Change both to something natural: "I didn't catch anything — just say thermostat when you need me." and "I'm having trouble with that. Say thermostat when you want to try again."

  5. The eco mode on-confirmation is 33 words across three sentences: "Eco mode is now on. The thermostat will use energy-saving temperatures. I won't be able to change the temperature until eco mode is turned off." The third sentence is a system constraint that doesn't need to be spoken every time. Trim to: "Eco mode is on. Temperature control is paused until you turn it off."

  6. handle_fan_control resolves on/off with "on" in on_or_off.lower() or "run" in on_or_off.lower() or "start" in on_or_off.lower() — same brittle substring problem as point 1. A user saying "go ahead" or "yes" after being prompted won't match any of these. Since on_or_off comes from the LLM classifier's on_or_off field, the value should already be "on" or "off" — do an exact equality check instead: on_or_off.lower().strip() == "on".

  7. "Authentication successful! Using mock device data for testing." is developer-facing copy reaching the voice output. A real user should never hear "mock device data" from their speaker. This is AUTH_TEST mode so it may never ship to users, but flag it anyway — change to "Connected. Running in test mode." to avoid confusion if it ever does.

  8. run_oauth_setup_flow contains six sequential speak() + user_response() pairs with no LLM routing between them. Per the QA guide this warrants a manual voice test before approval — run through the setup flow out loud and confirm it doesn't feel like a phone tree. The prompts are long and instruction-heavy; consider whether any of the walkthrough steps can be collapsed or deferred to the logs rather than spoken.

Copy link
Contributor

@uzair401 uzair401 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @megz2020, Please address the issues highlighted by @abubakar4360, and then we will proceed further.

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

Labels

community-ability Community-contributed ability first-contribution First-time contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants