Skip to content

feat: Add daily energy breakdown by month to energy command#58

Merged
eman merged 7 commits intomainfrom
feature/daily-energy-by-month
Dec 27, 2025
Merged

feat: Add daily energy breakdown by month to energy command#58
eman merged 7 commits intomainfrom
feature/daily-energy-by-month

Conversation

@eman
Copy link
Copy Markdown
Owner

@eman eman commented Dec 26, 2025

Description

This PR implements two major improvements:

  1. Daily Energy Breakdown by Month - New feature to show daily energy data
  2. Refactored Dependencies - Made Click optional, reducing core library footprint

Features

1. Daily Energy Breakdown (New CLI Feature)

Implements new --month option to show daily energy data for a specific month, complementing the existing --months option for monthly summaries.

New '--month' option:

  • Displays daily energy breakdown for a single month (1-12)
  • Shows per-day consumption data
  • Displays heat pump vs. electric heater split
  • Includes operating time for each component
  • Rich formatted output with progress bars and color-coded efficiency

Maintains '--months' option:

  • For monthly summary across multiple months
  • Shows aggregated monthly data

Smart routing:

  • Single month → Daily breakdown with progress bars
  • Multiple months → Monthly summary with trend data

Output formatting:

  • Rich formatted tables with colors and progress bars
  • Plain text fallback for non-Rich environments

Comprehensive error handling:

  • Validates month range (1-12)
  • Requires at least one of --month or --months
  • Clear error messages using Click's standard exception handling

2. Installation Documentation & Dependency Refactoring

Made Click optional, allowing the core library to be used without CLI framework. Rich formatting is included with Click in the CLI extra since it's only used for CLI output.

Changes:

  • Moved 'click' from install_requires to extras_require[cli]
  • Both 'click' and 'rich' included in extras_require[cli] (rich is CLI-specific)
  • Core library now has only 3 required dependencies
  • Updated README with clear installation instructions
  • Updated tox.ini to include [cli] extra in test environment
  • Fixed RST formatting in README for proper PyPI rendering

Installation Options:

# Library only (minimal footprint - 3 dependencies)
pip install nwp500-python

# Library with CLI support (recommended for CLI usage)
pip install nwp500-python[cli]

# Full development environment
pip install nwp500-python[cli,dev,testing]

Core Dependencies (always required):

  • aiohttp>=3.8.0
  • awsiotsdk>=1.27.0
  • pydantic>=2.0.0

CLI Extra Dependencies (only when using [cli]):

  • click>=8.0.0 (CLI framework)
  • rich>=13.0.0 (Enhanced terminal output for CLI)

Documentation improvements:

  • Basic library installation section
  • CLI installation section with [cli] extra
  • Clear explanation of when each dependency is needed
  • Removed misleading information about optional Rich without CLI

Usage Examples

Daily Breakdown (New Feature)

nwp-cli energy --year 2025 --month 12

Shows daily energy consumption for December 2025 with:

  • Daily breakdown table
  • Total usage and efficiency percentages
  • Heat pump vs. electric heater split
  • Operating time for each heat source
  • Rich formatted output with progress bars

Monthly Summary (Existing Feature)

nwp-cli energy --year 2025 --months 10,11,12

Shows monthly summary across October-December 2025.

Code Review Improvements

Addressed all Copilot code review comments:

  1. Performance: Eliminated O(n²) complexity

    • Replaced month_data.data.index(day_data) + 1 with enumerate(month_data.data, start=1)
    • Applied in both format_daily_energy_usage() and print_daily_energy_usage()
  2. Parameter Handling: Made year truly required

    • Changed --year from required=False to required=True
    • Updated function signature from year: int | None to year: int
    • Leverages Click's built-in validation
  3. Error Handling: Improved UX with Click exceptions

    • Replaced manual _logger.error() with click.ClickException()
    • Proper exit codes and consistent error formatting

Benefits

✓ Daily energy analysis for detailed consumption insights
✓ Smaller dependency footprint for library-only users (3 vs 5 dependencies)
✓ Clear separation between library and CLI requirements
✓ Better support for embedded/minimal environments
✓ Rich formatting available for CLI when needed
✓ Better code quality with improved performance and error handling
✓ 100% backward compatible - no breaking changes
✓ Clearer installation instructions in README

Testing & CI

✅ All 378 existing tests pass
✅ Linting: 0 errors, 227 pre-existing warnings
✅ Type checking: No new errors
✅ Manual testing: Daily and monthly modes verified
✅ Error cases: All validated
✅ Core library: Works without click dependency
✅ CLI: Works with [cli] extra
✅ CI Tests: All passing (Python 3.13 and 3.14)
✅ Build Distribution: PASSING
✅ Code review: All suggestions addressed

CI Status

  • ✓ Lint and Format Check: SUCCESS
  • ✓ Test on Python 3.13: SUCCESS
  • ✓ Test on Python 3.14: SUCCESS
  • ✓ Build Distribution: SUCCESS
  • ✓ CodeQL Analysis: SUCCESS

Backward Compatibility

✅ Fully backward compatible

  • Existing --months usage unchanged
  • Monthly summary output identical to before
  • Only adds new optional --month parameter
  • CLI still available with pip install nwp500-python[cli]
  • Core library functionality unaffected
  • Test environment properly configured for all tests
  • Distribution builds and validates correctly

Files Changed

  • src/nwp500/cli/__main__.py - Energy command enhancements and improved error handling
  • src/nwp500/cli/handlers.py - Handler logic with smart routing
  • src/nwp500/cli/output_formatters.py - Daily energy formatters with performance improvements
  • src/nwp500/cli/rich_output.py - Rich UI components for daily energy
  • setup.cfg - Dependency restructuring (click to [cli] extra)
  • README.rst - Installation documentation
  • tox.ini - Test environment configuration

Commits

  1. feat: Add daily energy breakdown by month to nwp-cli energy command

    • Implements --month option for daily energy data
    • Smart routing between daily/monthly views
    • Rich formatted output with progress bars
    • Comprehensive error handling
  2. docs: Update installation instructions for optional CLI and Rich dependencies

    • Moves click to optional CLI extra
    • Updates README with installation options
    • Clarifies that Rich is CLI-specific
  3. docs: Remove misleading 'Optional Rich Formatting' section

    • Clarifies that Rich is only used by CLI
    • Simplifies installation options to accurate choices
    • Improves documentation accuracy
  4. fix: Add cli extra to tox testing dependencies

    • Ensures click and rich are installed during test runs
    • Fixes CI test failures due to missing click dependency
    • Allows CLI tests to properly import modules
  5. fix: Correct RST title hierarchy in README

    • Fixed inconsistent reStructuredText title styles
    • Ensures README renders correctly on PyPI
    • Fixes Build Distribution validation
  6. refactor: Address code review comments from Copilot

    • Fixed O(n²) complexity in energy formatters
    • Made year parameter truly required in CLI
    • Improved error handling using Click exceptions
    • Cleaner, more maintainable code

eman added 5 commits December 26, 2025 15:00
Implements new --month option to show daily energy data for a specific month,
complementing the existing --months option for monthly summaries.

Features:
- New '--month' option displays daily energy breakdown for a single month
- Maintains existing '--months' option for monthly summary
- Smart routing: single month shows daily data, multiple months show summary
- Rich formatted output with progress bars and color-coded efficiency
- Plain text fallback for non-Rich environments
- Comprehensive error handling for invalid inputs

Usage:
  # Daily breakdown (new)
  nwp-cli energy --year 2025 --month 12

  # Monthly summary (existing)
  nwp-cli energy --year 2025 --months 10,11,12

Changes:
- CLI command now supports both --month and --months options
- Year parameter made optional in decorator, validated in function
- New output formatters for daily energy data
- Rich output formatter enhanced with daily energy table method
- Handler logic routes to appropriate formatter based on month count

Tests: All 378 tests pass
Linting: All checks pass (0 errors)
…ndencies

Make Click and Rich optional dependencies that are only required for the CLI,
allowing the core library to be used without these dependencies.

Changes:
- Move 'click' from install_requires to extras_require[cli]
- Update extras_require[cli] to include both click and rich
- Update README with detailed installation instructions for:
  * Basic library installation (without CLI)
  * CLI installation with rich formatting
  * Optional rich library usage
- Add CLI requirement note to Command Line Interface section
- Improve installation documentation clarity

Benefits:
- Smaller dependency footprint for library-only users
- Clear separation between library and CLI requirements
- Better support for embedded/minimal environments
- Optional rich formatting for enhanced output

This change is backward compatible as the [cli] extra provides all
dependencies needed for full CLI functionality.
Rich is only used by the CLI framework, so there's no practical use case
for installing rich without click. Simplified documentation to only show
two clear installation options:

1. Library only: pip install nwp500-python
2. Library with CLI: pip install nwp500-python[cli]

This makes the installation instructions clearer and more accurate about
when Rich is needed.
Since click was moved to optional [cli] extra, the test environment needs
to include it to run CLI tests. Added 'cli' to extras in [testenv:default]
so that both click and rich are installed during testing.

This fixes the CI test failure where CLI modules fail to import due to
missing click dependency.
Fixed inconsistent title style in README.rst where 'Quick Reference'
was using level 3 underline (~~~) when it should use level 2 (---)
to maintain proper reStructuredText hierarchy under the level 1
'Command Line Interface' section.

This fixes the twine distribution check error:
'Inconsistent title style: skip from level 2 to 4'
@eman eman requested a review from Copilot December 26, 2025 23:57
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a daily energy breakdown feature to the CLI and refactors dependencies to make Click and Rich optional. The daily breakdown shows per-day consumption data when querying a single month, while multiple months continue to show monthly summaries. The dependency refactoring reduces the core library footprint from 5 to 3 required dependencies by moving Click and Rich to an optional [cli] extra.

Key changes:

  • New --month option for daily energy breakdown with rich formatting
  • Smart routing between daily/monthly views based on input
  • Click and Rich moved to optional [cli] extra in setup.cfg
  • Updated installation documentation with clear guidance on when to use [cli] extra

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/nwp500/cli/main.py Adds --month parameter validation and routing logic for daily vs monthly energy views
src/nwp500/cli/handlers.py Implements conditional rendering based on single vs multiple months, improves device info formatting
src/nwp500/cli/output_formatters.py Adds daily energy formatting functions with plain text and rich table support
src/nwp500/cli/rich_output.py Implements rich-formatted daily energy tables with progress bars and color coding
setup.cfg Moves Click from required to optional [cli] extra alongside Rich
tox.ini Adds [cli] extra to test environment dependencies
README.rst Documents basic vs CLI installation options and restructures installation sections

Comment on lines +284 to +293
for day_data in month_data.data:
total_wh = day_data.total_usage
hp_wh = day_data.heat_pump_usage
he_wh = day_data.heat_element_usage
hp_time = day_data.heat_pump_time
he_time = day_data.heat_element_time

# Use day index + 1 as day number (assuming data is ordered by day)
day_num = month_data.data.index(day_data) + 1

Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

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

Using .index() in a loop results in O(n²) complexity. Consider using enumerate() instead: for day_num, day_data in enumerate(month_data.data, start=1):

Suggested change
for day_data in month_data.data:
total_wh = day_data.total_usage
hp_wh = day_data.heat_pump_usage
he_wh = day_data.heat_element_usage
hp_time = day_data.heat_pump_time
he_time = day_data.heat_element_time
# Use day index + 1 as day number (assuming data is ordered by day)
day_num = month_data.data.index(day_data) + 1
for day_num, day_data in enumerate(month_data.data, start=1):
total_wh = day_data.total_usage
hp_wh = day_data.heat_pump_usage
he_wh = day_data.heat_element_usage
hp_time = day_data.heat_pump_time
he_time = day_data.heat_element_time

Copilot uses AI. Check for mistakes.
Comment on lines +324 to +325
for day_data in month_data.data:
day_num = month_data.data.index(day_data) + 1
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

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

Using .index() in a loop results in O(n²) complexity. Consider using enumerate() instead: for day_num, day_data in enumerate(month_data.data, start=1):

Suggested change
for day_data in month_data.data:
day_num = month_data.data.index(day_data) + 1
for day_num, day_data in enumerate(month_data.data, start=1):

Copilot uses AI. Check for mistakes.
Comment on lines +342 to +344
year: int | None,
months: str | None,
month: int | None,
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

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

The year parameter is documented as required but typed as optional (int | None). Consider making it truly required by using type=int, required=True in the click.option decorator instead of checking for None in the function body. This provides better error messages and matches the documented behavior.

Copilot uses AI. Check for mistakes.
Comment on lines +351 to +353
if year is None:
_logger.error("--year is required")
return
Copy link

Copilot AI Dec 26, 2025

Choose a reason for hiding this comment

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

The error message should use Click's built-in error handling for better UX. Since year is marked as required in the help text, either make it truly required in the decorator or use click.ClickException to provide a proper exit code: raise click.ClickException('--year is required')

Copilot uses AI. Check for mistakes.
eman added 2 commits December 26, 2025 16:10
Implemented the following improvements based on Copilot review:

1. Fixed O(n²) complexity in energy formatters
   - Replaced month_data.data.index(day_data) + 1 with enumerate(month_data.data, start=1)
   - Applied fix in both format_daily_energy_usage() and print_daily_energy_usage()
   - Improves performance from quadratic to linear time

2. Made year parameter truly required in CLI
   - Changed --year from required=False to required=True in @click.option
   - Updated function signature from year: int | None to year: int
   - Removes manual validation and lets Click handle requirement

3. Improved error handling using Click's standard exceptions
   - Replaced _logger.error() calls with click.ClickException()
   - Provides proper exit codes and consistent error formatting
   - Better user experience with standard CLI error messages

All tests pass (378/378)
No linting errors
Apply ruff formatting to improve code consistency.
@eman eman marked this pull request as ready for review December 27, 2025 00:28
@eman eman merged commit 08b0bbe into main Dec 27, 2025
7 checks passed
@eman eman deleted the feature/daily-energy-by-month branch December 27, 2025 00:31
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