Skip to content

Add OpenEI TOU rate plan integration and CLI#75

Merged
eman merged 1 commit intomainfrom
copilot/different-tuna
Feb 16, 2026
Merged

Add OpenEI TOU rate plan integration and CLI#75
eman merged 1 commit intomainfrom
copilot/different-tuna

Conversation

Copy link
Contributor

Copilot AI commented Feb 16, 2026

Implements complete Time-of-Use rate plan workflow via OpenEI Utility Rates API v7, matching the Navien mobile app's functionality.

Core Components

  • OpenEIClient (src/nwp500/openei.py) - Async client for browsing 10,000+ utility rate plans by ZIP code
  • API methods - convert_tou() delegates conversion to Navien backend, update_tou() applies plans to devices
  • ConvertedTOUPlan model - Type-safe representation of server-converted schedules with season bitfields and scaled pricing

CLI Commands

# Browse utilities and rate plans for a ZIP code
nwp500 tou rates 94903

# View converted plan details (table format by default, --json optional)
nwp500 tou plan 94903 "Electric Vehicle EV (Sch) Rate A" --utility "Pacific Gas & Electric Co"

# Apply plan to device and optionally enable TOU mode
nwp500 tou apply 94903 "Electric Vehicle EV (Sch) Rate A" --enable

# View current device schedule (enhanced with table formatting)
nwp500 tou get

Output Formatting

Table output with intelligent day/month range collapsing:

  • Before: Monday, Tuesday, Wednesday, Thursday, Friday 16:00-21:00
  • After: Mon–Fri 16:00-21:00

Handles edge cases: weekends (Sat–Sun), all days (Every day), non-contiguous ranges (Mon–Wed, Fri).

Implementation Notes

  • API key sourced from OPENEI_API_KEY environment variable
  • Server-side conversion via POST /device/tou/convert eliminates client-side bitfield encoding
  • Removed redundant @click.pass_context decorators that caused argument collision with async_command
  • 15 new tests added (426 total passing)

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh gh pr list --repo eman/nwp500-python --head copilot/different-tuna (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

commit changes and create pr for the rate api

**Chronological Review:** 1. User requested implementation of `get_tou_info()` REST method → Already existed in codebase 2. User asked about CLI exposure, OpenEI API key source, and app workflow → Analyzed HAR files, discovered hardcoded API key in Navien app, identified missing endpoints 3. User requested a plan for full TOU workflow implementation → Created plan.md with 8 phases 4. User said "go" → Implemented all 8 phases: OpenEI client, API methods, models, CLI commands, handlers, tests, docs, changelog 5. User reported `tou get` output was hard to read → Added `--json` flag, made table default, added `print_tou_schedule()` to `OutputFormatter` with both plain and rich implementations 6. User reported Monday was separated from other days in formatting → Fixed `_abbreviate_days()` to collapse consecutive days into ranges (e.g., "Tue–Sat"), added `_collapse_ranges()` helper, fixed weekend special case 7. User reported `tou plan` command crashed with "multiple values for argument 'zip_code'" → Fixed by removing redundant `@click.pass_context` decorators from `tou_plan`, `tou_apply`, and `tou_get` commands 8. User requested `tou plan` also show table by default with `--json` option → Added `--json` flag and `output_json` parameter, refactored handler to use `print_tou_schedule()` by default

Intent Mapping:

  • Original: Implement OpenEI TOU rate plan integration (browse, select, apply)
  • Subsequent: Make CLI output human-readable with table formatting
  • Fix: Day abbreviation showing Monday separated from other days
  • Fix: CLI crash due to redundant @click.pass_context
  • Most recent: Make tou plan match tou get formatting (table default, --json option)

Technical Inventory:

  • Python async library for Navien NWP500 heat pump water heaters
  • OpenEI Utility Rates API v7 integration
  • aiohttp for HTTP, Pydantic for models, Click for CLI, Rich for formatted output
  • MQTT for device control, REST for cloud API
  • Strict linting: ruff (80 char lines), mypy, pyright, 426 tests

Code Archaeology:

  • All files created/modified across 8 implementation phases plus 3 rounds of fixes
  • Key pattern: async_command decorator wraps Click commands, injects (mqtt, device, *args, **kwargs)
  • @click.pass_context is handled BY async_command — adding it to individual commands causes double-passing bugs
  • OutputFormatter in rich_output.py has dual plain/rich implementations for each output method

Progress Assessment:

  • All 8 phases complete, all fixes applied, all validation passing
  • No remaining known issues

Recent Commands Analysis:
The most recent operations were:

  1. Added --json flag to tou plan CLI command in __main__.py
  2. Updated handle_tou_plan_request() handler with output_json kwarg
  3. When output_json=False (default), delegates to _formatter.print_tou_schedule()
  4. When output_json=True, builds decoded JSON and uses print_json()
  5. Ran ruff format/check, make ci-lint, mypy, pytest — all passing
1. Conversation Overview: - Primary Objectives: Implement full OpenEI TOU (Time-of-Use) rate plan integration for nwp500-python library. User said: "I expect to use the cli (or the python api) to be able to perform the same actions as the app via the same api key the app would use. 1. Supply a zip code 2. List utility providers 3. select a utility provider 4. list rate plans 5. Select a specific rate plan and view the rate plan details and metadata 6. Apply the rate plan to the water heater" - Session Context: Started with exploration of existing code, created implementation plan, built all 8 phases (OpenEI client, API methods, models, CLI commands, handlers, tests, docs, validation), then iterated on CLI output formatting and bug fixes across 4 additional rounds. - User Intent Evolution: Implementation → Make output human-readable (table by default, `--json` option) → Fix day formatting (Monday separated) → Fix CLI crash (duplicate `@click.pass_context`) → Make `tou plan` match `tou get` formatting
  1. Technical Foundation:
    • nwp500-python: Python async control library for Navien NWP500 heat pump water heaters
    • OpenEI API v7: https://api.openei.org/utility_rates — utility rate plan database; API key from OPENEI_API_KEY env var (Navien app hardcodes D8QhQKaB0DCM77tEhklCCjPDkjzxO9ZKJcW8zuMe)
    • Navien TOU flow (from HAR captures): GET /device/tou → GET openei.org → POST /device/tou/convert → PUT /device/tou → MQTT tou-on
    • Linting: ruff (80 char line limit), mypy, pyright; make ci-lint runs all three
    • Testing: pytest, 426 tests passing (excluding test_mqtt_hypothesis.py which needs missing hypothesis module)
    • CLI framework: Click with async_command decorator that handles auth/MQTT connection and passes (mqtt, device, *args, **kwargs) to command functions
    • Output: OutputFormatter class in rich_output.py with dual...

Created from Copilot CLI via the copilot delegate command.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI changed the title [WIP] Update rate API for improved data formatting Add OpenEI TOU rate plan integration and CLI Feb 16, 2026
Copilot AI requested a review from eman February 16, 2026 19:59
@eman eman marked this pull request as ready for review February 16, 2026 20:01
@eman eman merged commit eb821e4 into main Feb 16, 2026
9 checks passed
@eman eman deleted the copilot/different-tuna branch February 16, 2026 20:03
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