Skip to content

Add air-quality-pollen-alert ability: proactive AQI and pollen monitor for allergy and asthma sufferers#288

Open
hassan1731996 wants to merge 17 commits into
openhome-dev:devfrom
hassan1731996:feature/air-quality-pollen-alert
Open

Add air-quality-pollen-alert ability: proactive AQI and pollen monitor for allergy and asthma sufferers#288
hassan1731996 wants to merge 17 commits into
openhome-dev:devfrom
hassan1731996:feature/air-quality-pollen-alert

Conversation

@hassan1731996

Copy link
Copy Markdown
Contributor

Summary

  • Proactive air quality and pollen monitor personalized to the user's health conditions (asthma, hay fever, COPD)
  • Morning briefing + evening prep alert via background daemon; on-demand queries (check, forecast, activity, windows) handled in a single multi-turn session via outer loop
  • City extracted directly from the trigger phrase — no follow-up questions during setup

Setup flow

The city goes in the trigger phrase itself:

"Set up air quality for Ottawa"

The ability extracts the city via LLM, geocodes it, and confirms in one step. No follow-up question, no loop. If no city is given, the ability gives a redirect prompt and exits cleanly.

What's included

main.py — 6-intent foreground with outer loop

  • SETUP — city extracted from trigger; saves location, morning time defaults to 7am
  • CHECK — on-demand AQI + pollen with condition-aware response (pollen-first for hay fever, AQI-first for asthma)
  • FORECAST — today and tomorrow outlook
  • ACTIVITY — "is it safe to run?" with best outdoor time window
  • WINDOWS — "should I keep windows closed?" with pollen-aware response
  • UPDATE — change morning alert time, health conditions, pollen triggers

All follow-up queries in a session are handled by a user_response() outer loop — no re-triggering needed.

background.py — 5-minute daemon, two alert windows

  • Morning alert at user's configured time: fires when AQI ≥ threshold; condition-aware briefing with best outdoor window
  • Evening prep alert at 8pm: fires when tomorrow is forecast bad
  • resume_normal_flow() is delayed 90 seconds after daemon start, giving the foreground's outer loop exclusive conversation control for a full session before the background takes over

APIs

  • Open-Meteo Air Quality API — free, no key, global
  • Open-Meteo Geocoding API — free, no key

Validation

✅ All checks passed (validate_ability.py)

hassan1731996 and others added 15 commits June 21, 2026 01:12
After resume_normal_flow() fires from the background daemon, user_response()
returns None on every call — the outer while loop became an infinite no-op,
letting the generic assistant handle all follow-up queries.

Two architectural fixes:
- Remove outer while loop entirely; one trigger = one intent = exit cleanly.
  Follow-up queries re-trigger via does_match() as fresh invocations.
- Extract city from trigger text via LLM before calling user_response() in
  setup. "set up air quality for Toronto" now completes with zero user_response()
  calls, eliminating the race with the background daemon entirely.
…sion_tasks sleep loop

Background's session_tasks.sleep(300s) kept the ability permanently 'active',
preventing does_match() from firing for any subsequent utterance. All follow-up
queries (CHECK, FORECAST, ACTIVITY, WINDOWS) went to generic assistant with no
[AQAlert] logs.

Removing background.py eliminates the sleep loop so the ability goes idle after
each foreground invocation, allowing does_match() to fire normally for re-triggers.
On-demand queries now work reliably across the full demo flow.

README updated: setup phrase now requires city inline; background daemon section removed.
…se() handles all follow-ups

After resume_normal_flow() the runtime never calls does_match() again in the same
session, so the 'one trigger = one intent = re-trigger' design was always wrong.
The outer while loop with user_response() is the only correct multi-turn mechanism.

Without background.py (removed last commit), no competing resume_normal_flow()
can break user_response(), so the loop runs cleanly for the full session.

Stale echo filter added: discards the final-transcription replay of the trigger
phrase that fires immediately after speak() returns, preventing spurious SETUP re-runs.
Delay resume_normal_flow() until after STARTUP_GRACE (90s) instead of calling it
immediately at daemon startup. This gives the foreground's outer loop exclusive
conversation control for the first 90 seconds — long enough for any query session.
After 90s the background releases control and monitors for morning/evening alerts.

Alert logic, thresholds, and polling interval are unchanged.
@hassan1731996 hassan1731996 requested a review from a team as a code owner July 4, 2026 08:42
@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

✅ Community PR Path Check — Passed

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

@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

✅ Ability Validation Passed

📋 Validating: community/air-quality-pollen-alert
  ✅ All checks passed!

@github-actions github-actions Bot added the community-ability Community-contributed ability label Jul 4, 2026
@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

🔀 Branch Merge Check

PR direction: feature/air-quality-pollen-alertdev

Passedfeature/air-quality-pollen-alertdev is a valid merge direction

@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

🔍 Lint Results

__init__.py — Empty as expected

Files linted: community/air-quality-pollen-alert/background.py community/air-quality-pollen-alert/main.py

✅ Flake8 — Passed

✅ All checks passed!

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

Labels

community-ability Community-contributed ability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants