Skip to content

Add Tomorrow.io 5-day forecast reporting#45

Merged
simons-plugins merged 3 commits into
mainfrom
feat/forecast-reporting
Apr 10, 2026
Merged

Add Tomorrow.io 5-day forecast reporting#45
simons-plugins merged 3 commits into
mainfrom
feat/forecast-reporting

Conversation

@simons-plugins

@simons-plugins simons-plugins commented Apr 10, 2026

Copy link
Copy Markdown
Owner

Summary

  • Fetch daily forecast from Tomorrow.io (/v4/weather/forecast?timesteps=1d) and report 6 days of weather data to each sprinkler device via Netro's report_weather API
  • Netro confirmed to accept future dates (tested up to 7 days ahead)
  • Gives Netro better scheduling data for smarter irrigation decisions
  • Uses actual daily rainfall totals (rainAccumulationSum) instead of point-in-time intensity
  • Adds t_max, t_min, t_dew fields not available from realtime endpoint
  • Forecast runs on separate 60-min interval (existing FORECAST_UPDATE_INTERVAL_MINUTES constant)
  • 16 new tests, 410 total passing

Field mapping

Tomorrow.io Daily Netro Field Notes
temperatureAvg t Daily average
temperatureMax t_max Daily high
temperatureMin t_min Daily low
dewPointAvg t_dew v2 only
weatherCodeMax condition Most severe weather
humidityAvg humidity Average
rainAccumulationSum rain Total mm (not intensity)
precipitationProbabilityMax rain_prob Peak probability
windSpeedAvg wind_speed Average
pressureSurfaceLevelAvg pressure Average

Token budget

  • Tomorrow.io: +24 calls/day → ~72 total (within 500 free tier)
  • Netro: +144 calls/device/day → ~192 total/device (within 2000)

Test plan

  • All 410 tests pass
  • Deploy to server, check event log for forecast messages
  • Verify via Netro that future dates show reported weather

Closes #44

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added daily weather forecast integration from Tomorrow.io with automatic device weather reporting.
    • Enhanced weather data support including dew point temperature conversions.
  • Chores

    • Updated plugin version to 2026.3.0.

simons-plugins and others added 2 commits April 10, 2026 17:51
Fetch daily forecast from Tomorrow.io and report 6 days of weather data
(today + 5 days ahead) to each sprinkler device. Gives Netro better
scheduling data — e.g., skip watering today if rain forecast tomorrow.

- Add fetch_forecast() and _transform_forecast_response() to TomorrowClient
- Map daily aggregated fields: temperatureMax→t_max, temperatureMin→t_min,
  rainAccumulationSum→rain (actual daily total, not intensity), dewPointAvg→t_dew
- Forecast runs on separate 60-min interval (vs 30-min realtime)
- Add t_dew support to metric↔US conversion functions
- Strip t_dew for v1 devices (unsupported by v1 API)
- 16 new tests covering forecast transform, fetch, and dew point conversion

Closes #44

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Apr 10, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@simons-plugins has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 3 minutes and 31 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 3 minutes and 31 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7ba3f35f-b845-49e1-aab5-1c59b74ef6d0

📥 Commits

Reviewing files that changed from the base of the PR and between 739f4e8 and b1582ae.

📒 Files selected for processing (3)
  • Netro Sprinklers.indigoPlugin/Contents/Server Plugin/plugin.py
  • Netro Sprinklers.indigoPlugin/Contents/Server Plugin/tomorrow_client.py
  • tests/test_tomorrow_client.py
📝 Walkthrough

Walkthrough

This PR adds daily weather forecast reporting from Tomorrow.io to the Netro Sprinkler plugin, enabling multi-day irrigation scheduling decisions. It includes forecast data fetching, transformation, device reporting, unit conversion support for dew point, and comprehensive test coverage.

Changes

Cohort / File(s) Summary
Version Update
Netro Sprinklers.indigoPlugin/Contents/Info.plist
Incremented plugin version from 2026.2.0 to 2026.3.0.
Forecast API Integration
Netro Sprinklers.indigoPlugin/Contents/Server Plugin/tomorrow_client.py
Added FORECAST_URL constant and new fetch_forecast() method to retrieve daily forecast data from Tomorrow.io. Implemented _transform_forecast_response() to convert Tomorrow.io daily timelines into Netro-format weather dictionaries with temperature, precipitation, humidity, wind, and pressure aggregations. Includes dedicated forecast error handling for missing/invalid timelines and missing temperature averages per day.
Forecast Reporting & Scheduling
Netro Sprinklers.indigoPlugin/Contents/Server Plugin/plugin.py
Integrated forecast updates into polling thread alongside realtime weather. Introduced _update_forecast_from_tomorrow() method to fetch forecast data, transform for Netro v1 devices (unit conversion, remove unsupported t_dew), and report to enabled sprinkler devices. Added _next_forecast_update timestamp tracking and FORECAST_UPDATE_INTERVAL_MINUTES configuration. Reset both weather and forecast update timers on status/refresh/update-all actions and preference changes. Includes per-device exception handling for throttling and general errors.
Dew Point Unit Conversion
Netro Sprinklers.indigoPlugin/Contents/Server Plugin/utils.py
Extended convert_weather_us_to_metric() and convert_weather_metric_to_us() to include t_dew field in temperature conversions, handling None values and rounding to one decimal place.
Forecast Transformation Tests
tests/test_tomorrow_client.py
Added sample_forecast_response and rainy_forecast_day fixtures simulating Tomorrow.io daily forecast payloads. Created TestTransformForecastResponse suite validating daily entry extraction, aggregated field mapping (temp avg/max/min, dew point, humidity, rainfall, precipitation probability, wind speed, surface pressure), weather code-to-condition mapping, wind override behavior, skipping days with missing temperatureAvg, and error/empty-list handling. Created TestFetchForecast suite validating successful API calls, request parameters (timesteps=1d, units=metric), and HTTP error handling.
Dew Point Conversion Tests
tests/test_weather_integration.py
Added TestDewPointConversion test suite validating bidirectional t_dew unit conversion between Celsius and Fahrenheit, and confirming that missing t_dew does not create spurious fields during metric-to-US conversion.

Sequence Diagram

sequenceDiagram
    actor Polling as Polling Thread
    participant Plugin as plugin.py
    participant TomorrowClient as TomorrowClient
    participant TomorrowAPI as Tomorrow.io API
    participant NetroAPI as Netro API
    participant Device as Sprinkler Device

    loop On Schedule
        Polling->>Plugin: concurrent polling tick
        Plugin->>Plugin: _update_forecast_from_tomorrow()
        Plugin->>Plugin: schedule next run (_next_forecast_update)
        Plugin->>TomorrowClient: fetch_forecast()
        TomorrowClient->>TomorrowAPI: GET /v4/weather/forecast?timesteps=1d
        TomorrowAPI-->>TomorrowClient: daily forecast data
        TomorrowClient->>TomorrowClient: _transform_forecast_response()
        TomorrowClient-->>Plugin: List[Dict] (transformed daily weather)
        loop for each enabled device
            Plugin->>Plugin: convert units for Netro v1 (remove t_dew)
            Plugin->>NetroAPI: api_client.report_weather(date, weather_dict)
            NetroAPI-->>Plugin: status=OK
            Plugin->>Device: weather recorded
        end
        Plugin-->>Polling: forecast update complete
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related PRs

Poem

🐰 Hopping through the forecast with a five-day gleam,
Tomorrow's rain and sunshine now fuel the watering dream,
From API to sprinkler, the data flows bright,
Scheduling smarter, from dawn through the night! 🌧️☀️

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding Tomorrow.io 5-day forecast reporting capability to the plugin.
Linked Issues check ✅ Passed All objectives from issue #44 are met: fetch_forecast() implemented, Tomorrow.io fields mapped to Netro format, t_dew added to conversions, v1 device stripping, 60-min interval scheduling, and token cost analysis confirms acceptable limits.
Out of Scope Changes check ✅ Passed All changes are scoped to forecast reporting implementation: Tomorrow.io API integration, weather field mappings, scheduling, unit conversions, version bump, and comprehensive tests—no unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 94.44% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/forecast-reporting

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Netro` Sprinklers.indigoPlugin/Contents/Info.plist:
- Around line 5-6: The PluginVersion value "2026.3.0" is already used as a git
tag and must be bumped to a unique, unused version; update the
<key>PluginVersion</key> entry by changing the <string> value to a new semantic
version (e.g., "2026.3.1" or the next appropriate patch/minor) that does not
already exist in tags, commit the change, and retry CI so the version check
passes.

In `@Netro` Sprinklers.indigoPlugin/Contents/Server Plugin/tomorrow_client.py:
- Around line 309-318: Limit the transformed forecast to six days by slicing the
parsed timelines.daily list before iteration: after extracting daily =
data["timelines"]["daily"], replace the unbounded loop over daily with a slice
like daily = daily[:6] (or equivalent) so the for day in daily loop only
processes today +5 days; update the forecasts-building logic that populates
forecasts accordingly and add a regression test that supplies a timelines.daily
array longer than six entries to verify only six are emitted.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3fa57be2-e09e-4418-b416-ae2232650d31

📥 Commits

Reviewing files that changed from the base of the PR and between f618c5e and 739f4e8.

📒 Files selected for processing (6)
  • Netro Sprinklers.indigoPlugin/Contents/Info.plist
  • Netro Sprinklers.indigoPlugin/Contents/Server Plugin/plugin.py
  • Netro Sprinklers.indigoPlugin/Contents/Server Plugin/tomorrow_client.py
  • Netro Sprinklers.indigoPlugin/Contents/Server Plugin/utils.py
  • tests/test_tomorrow_client.py
  • tests/test_weather_integration.py

Comment on lines 5 to +6
<key>PluginVersion</key>
<string>2026.2.0</string>
<string>2026.3.0</string>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Use a new, unused plugin version.

CI is already failing because 2026.3.0 exists as a git tag, so this release cannot pass the version check as written. Please bump PluginVersion to a unique value before merge.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Netro` Sprinklers.indigoPlugin/Contents/Info.plist around lines 5 - 6, The
PluginVersion value "2026.3.0" is already used as a git tag and must be bumped
to a unique, unused version; update the <key>PluginVersion</key> entry by
changing the <string> value to a new semantic version (e.g., "2026.3.1" or the
next appropriate patch/minor) that does not already exist in tags, commit the
change, and retry CI so the version check passes.

Comment on lines +309 to +318
try:
daily = data["timelines"]["daily"]
except (KeyError, TypeError):
self.logger.error(
"Unexpected Tomorrow.io forecast structure - missing timelines.daily"
)
return None

forecasts = []
for day in daily:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Cap the transformed forecast to six days.

This currently processes every entry in timelines.daily, but the feature contract and token-budget math assume today + 5 days only. If Tomorrow.io returns a longer daily horizon, we'll over-report to Netro and may send dates beyond the supported window. Please slice the daily list before iterating and add a regression test for responses longer than six days.

Proposed fix
-            daily = data["timelines"]["daily"]
+            daily = data["timelines"]["daily"][:6]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Netro` Sprinklers.indigoPlugin/Contents/Server Plugin/tomorrow_client.py
around lines 309 - 318, Limit the transformed forecast to six days by slicing
the parsed timelines.daily list before iteration: after extracting daily =
data["timelines"]["daily"], replace the unbounded loop over daily with a slice
like daily = daily[:6] (or equivalent) so the for day in daily loop only
processes today +5 days; update the forecasts-building logic that populates
forecasts accordingly and add a regression test that supplies a timelines.daily
array longer than six entries to verify only six are emitted.

- Wrap per-day forecast transform in try/except so one bad value
  doesn't discard all 6 days
- Add missing fetch_forecast error tests (ConnectionError, Timeout,
  generic Exception)
- Add wind override boundary test at exactly 15.0 m/s for forecast
- Fix fragile ternary f-string in debug log — use explicit if/else
- Update stale class docstring to mention forecasts
- Fix docstrings: optional field markers, refreshWeather mentions forecast,
  accurate API call count, "6 days" not hardcoded
- Improve summary log to say "days fetched" not imply all succeeded
- Log when zero sprinkler devices found (avoids wasting API calls silently)
- Clarify v1 t_dew strip comment

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@simons-plugins simons-plugins merged commit 86012d1 into main Apr 10, 2026
3 checks passed
@simons-plugins simons-plugins deleted the feat/forecast-reporting branch April 10, 2026 17:08
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.

Add Tomorrow.io forecast reporting for multi-day weather data

1 participant