Skip to content

Releases: eman/nwp500-python

v7.4.8

17 Feb 23:09

Choose a tag to compare

Added

  • Reservation CRUD Helpers: New public functions fetch_reservations(),
    add_reservation(), delete_reservation(), and update_reservation()
    in nwp500.reservations (and exported from nwp500). These abstract the
    read-modify-write pattern for single-entry schedule management so library
    users no longer need to fetch the full schedule, splice it manually, and send
    it back. The CLI now delegates to these library functions.

v7.4.7

17 Feb 21:16

Choose a tag to compare

Added

  • OpenEI Client Module: New OpenEIClient async client (nwp500.openei) for browsing utility rate plans from the OpenEI API by zip code. Supports listing utilities, filtering rate plans, and fetching plan details. API key read from OPENEI_API_KEY environment variable.
  • Convert TOU API: NavienAPIClient.convert_tou() sends raw OpenEI rate data to the Navien backend for server-side conversion into device-ready TOU schedules with season/week bitfields and scaled pricing.
  • Update TOU API: NavienAPIClient.update_tou() applies a converted TOU rate plan to a device, matching the mobile app's PUT /device/tou endpoint.
  • ConvertedTOUPlan Model: New Pydantic model for parsed convert_tou() results (utility, name, schedule).
  • CLI tou rates: Browse utilities and rate plans for a zip code (nwp500 tou rates 94903).
  • CLI tou plan: View converted rate plan details with decoded pricing (nwp500 tou plan 94903 "EV Rate A").
  • CLI tou apply: Apply a rate plan to the water heater with optional --enable flag to activate TOU via MQTT.
  • CLI Reservations Table Output: nwp-cli reservations get now displays reservations as a formatted table by default with global status indicator (ENABLED/DISABLED). Use --json flag for JSON output.
  • CLI anti-legionella set-period: New subcommand to change the Anti-Legionella cycle period (1-30 days) without toggling the feature. Use nwp-cli anti-legionella set-period 7 to update cycle period.

Changed

  • examples/advanced/tou_openei.py: Rewritten to use the new OpenEIClient and convert_tou()/update_tou() library methods instead of inline OpenEI API calls and client-side conversion.

Fixed

  • Week Bitfield Encoding (CRITICAL): Fixed MGPP week bitfield encoding to match NaviLink APK protocol. Sunday is now correctly bit 7 (128), Monday bit 6 (64), ..., Saturday bit 1 (2); bit 0 is unused. Affects all reservation and TOU schedule operations. Verified against reference captures.
  • Enable/Disable Convention: Fixed reservation and TOU enable/disable flags to use standard device boolean convention (1=OFF, 2=ON) instead of inverted logic. This aligns with other device binary sensors and matches app behavior. Global reservation status now correctly shows DISABLED when reservationUse=1.
  • Reservation Set Command Timeout: Fixed reservations set subscription pattern that had extra wildcards preventing response matching. Command now receives confirmations correctly.
  • Intermittent Fetch Bug: Tightened MQTT topic filter for reservation fetch from /res/ to /res/rsv/ with content validation to prevent false matches on unrelated response messages.

v7.4.6

14 Feb 02:27

Choose a tag to compare

Fixed

  • Converter Consistency: div_10() and mul_10() now correctly apply division/multiplication to all input types after float() conversion, not just int/float types
  • Reservation Decoding: Fixed decode_reservation_hex() to validate chunk length before checking for empty entries, preventing potential out-of-bounds access
  • Factory Cleanup: create_navien_clients() now properly cleans up auth session if authentication fails during context manager entry
  • MQTT Reconnection: MQTT client now resubscribes to all topics after successful reconnection
  • Subscription Leak: Fixed resource leak where wait_for_device_feature() did not unsubscribe its callback after completion
  • Duplicate Handlers: Subscription manager now prevents duplicate callback registration for the same topic
  • Command Queue: MqttCommandQueue now raises on QueueFull instead of silently swallowing the error
  • Flow Rate Metadata: Removed hardcoded "GPM" unit from recirc_dhw_flow_rate field; unit is now dynamic based on unit system
  • Temperature Rounding: RawCelsius Fahrenheit conversion now uses a catch-all default for standard rounding instead of matching only STANDARD enum value
  • Unit System Default: is_metric_preferred() now returns False (Fahrenheit) instead of None when no unit system override or context is set

Security

  • Sensitive Data Logging: Redacted MQTT topics in subscription manager logging to prevent leaking device IDs (resolves CodeQL alerts)

Added

  • Auth Session Property: Added NavienAuthClient.session property to access the active aiohttp session without using getattr
  • Unsubscribe Feature: Added unsubscribe_device_feature() method to MQTT client and subscription manager for targeted callback removal
  • Hypothesis Fuzzing: Added property-based fuzzing tests for MQTT payload handling
  • Bandit Security Scanning: Added bandit configuration for security analysis in CI

v7.4.5

04 Feb 18:32

Choose a tag to compare

Fixed

  • Energy Capacity Unit Scaling: Corrected unit scaling for energy capacity fields that were off by a factor of 10
  • CLI Output: Fixed linting issue by replacing str and Enum with StrEnum for InstallType

v7.3.4

27 Jan 23:37
502e87c

Choose a tag to compare

Fixed

  • Temperature Delta Conversions: Fixed incorrect Fahrenheit conversion for differential temperature settings (heat pump and heater element on/off thresholds)

    • Created new DeciCelsiusDelta class for temperature deltas that apply scale factor (9/5) but NOT the +32 offset
    • Heat pump and heater element differential settings now use DeciCelsiusDelta instead of DeciCelsius
    • hp_upper_on_diff_temp_setting, hp_lower_on_diff_temp_setting, he_upper_on_diff_temp_setting, he_lower_on_diff_temp_setting, and related off settings now convert correctly to Fahrenheit
    • Example: A device value of 5 (representing 0.5°C delta) now correctly converts to 0.9°F delta instead of 32.9°F
  • CLI Output: Added display of heat pump and heater element differential temperature settings in device status output

Changed

  • Internal API: Added div_10_celsius_delta_to_preferred converter for temperature delta values in device models

v7.3.3

27 Jan 19:35
c1a8822

Choose a tag to compare

Breaking Changes

  • Temperature Setpoint Limits: Replaced hardcoded temperature limits with device-provided values

    • set_dhw_temperature() now validates against device-specific dhw_temperature_min and dhw_temperature_max instead of hardcoded 95-150°F bounds
    • build_reservation_entry() changed parameter name from temperature_f to temperature (unit-agnostic)
    • Added optional temperature_min and temperature_max parameters to build_reservation_entry() for device-specific limit overrides
    • Temperature parameters now accept values in the user's preferred unit (Celsius or Fahrenheit) based on global unit system context
    • Fixes Home Assistant and other integrations that prefer Celsius unit display

    Migration guide:

    .. code-block:: python

    OLD (hardcoded 95-150°F)

    await mqtt.control.set_dhw_temperature(device, temperature_f=140.0)
    entry = build_reservation_entry(
    enabled=True,
    days=["Monday"],
    hour=6,
    minute=0,
    mode_id=3,
    temperature_f=140.0,
    )

    NEW (device-provided limits, unit-aware)

    Temperature value automatically uses user's preferred unit

    await mqtt.control.set_dhw_temperature(device, 140.0)

    Device features provide min/max in user's preferred unit

    features = await device_info_cache.get(device.device_info.mac_address)
    entry = build_reservation_entry(
    enabled=True,
    days=["Monday"],
    hour=6,
    minute=0,
    mode_id=3,
    temperature=140.0,
    temperature_min=features.dhw_temperature_min,
    temperature_max=features.dhw_temperature_max,
    )

Added

  • Reservation Temperature Conversion: New reservation_param_to_preferred() utility function for unit-aware reservation display

    • Converts device reservation parameters (half-degree Celsius) to user's preferred unit
    • Respects global unit system context (metric/us_customary)
    • Enables proper thermostat/reservation scheduling display in Home Assistant and other integrations
    • Example usage:

    .. code-block:: python

    from nwp500 import reservation_param_to_preferred

    Display reservation temperature in user's preferred unit

    param = 120 # Device raw value in half-Celsius
    temp = reservation_param_to_preferred(param)

    Returns: 60.0 (Celsius) or 140.0 (Fahrenheit) based on unit context

  • Unit-Aware Temperature Conversion: New preferred_to_half_celsius() utility function

    • Converts temperature from user's preferred unit to half-degree Celsius for device commands
    • Respects global unit system context (metric/us_customary)
    • Replaces misleading fahrenheit_to_half_celsius() in unit-agnostic code paths
    • Used internally by set_dhw_temperature() and build_reservation_entry()

Changed

  • Unit System Agnostic Display: All logging and user-facing messages now respect global unit system context

    • Temperature change logs dynamically show °C or °F based on user preference
    • CLI monitoring and temperature setting messages use correct unit suffix
    • Event listener documentation updated with unit-aware examples
    • Reservation schedule examples now use reservation_param_to_preferred() for proper unit handling

Fixed

  • Critical: Temperature Unit Bug in Set Operations: Fixed incorrect temperature conversion when setting DHW temperature and reservations

    • set_dhw_temperature() was calling fahrenheit_to_half_celsius() with unit-agnostic temperature parameter
    • build_reservation_entry() had the same issue
    • Impact: If user preferred Celsius, temperature would be interpreted as Fahrenheit, causing wrong setpoints
    • Fix: Use new preferred_to_half_celsius() that respects unit system context
    • This was a critical data correctness bug that would cause incorrect device behavior for Celsius users

v7.3.2

26 Jan 05:26

Choose a tag to compare

Changed

  • Unit System Consistency: Removed deprecated "imperial" unit system identifier in favor of "us_customary" for Home Assistant compatibility

    • Changed all references from UnitSystem.IMPERIAL to UnitSystem.US_CUSTOMARY
    • Updated set_unit_system() and related functions to use "us_customary" exclusively
    • "metric" remains unchanged for Metric conversions
    • Affects API client, MQTT client, and CLI unit system handling
    • Improves consistency with Home Assistant naming conventions

Fixed

  • Unit System Consolidation: Consolidated duplicate UnitSystemType type alias definitions into single canonical definition in unit_system.py

    • Removed redundant type definitions from multiple modules
    • Improved code maintainability and consistency
    • All unit system operations now reference centralized type definition

v7.3.1

25 Jan 22:18

Choose a tag to compare

Fixed

  • MQTT Client Initialization: Removed overly strict token validity check from NavienMqttClient.__init__()

    • The strict token validity check prevented creating MQTT clients with restored tokens that may have expired between application restarts
    • However, NavienMqttClient.connect() already handles token refresh automatically, making the check redundant
    • This change allows integrations to create MQTT clients with expired tokens and let connect() handle validation
    • Simplifies application code by removing duplicate token refresh calls
    • Enables proper handling of restored authentication sessions
    • Fixes MQTT connection failures when using stored tokens across application restarts

v7.2.3

16 Jan 01:41

Choose a tag to compare

Added

  • Daily Energy Breakdown by Month: New --month option for energy command to show daily energy data for a specific month

    .. code-block:: bash

    Daily breakdown for a single month

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

    Monthly summary for multiple months (existing)

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

    • Displays daily energy consumption, efficiency, and heat source breakdown
    • Rich formatted output with progress bars and color-coded efficiency percentages
    • Plain text fallback for non-Rich environments
    • Smart routing: single month shows daily data, multiple months show summary

Fixed

  • Documentation: Fixed all warnings and broken cross-references in documentation

    • Fixed docstring formatting in field_factory.py module
    • Fixed broken cross-reference links in enumerations.rst, mqtt_diagnostics.rst, cli.rst, and models.rst
    • Fixed invalid JSON syntax in code examples (removed invalid [...] and ... tokens)
    • Suppressed duplicate object description warnings from re-exported classes
  • CLI Documentation: Updated documentation for all 19 CLI commands

    • Added missing device-info command documentation
    • Added --raw flag documentation for status, info, and device-info commands
    • Added --month option documentation to energy command
    • Clarified mutually exclusive options (--months vs --month)
  • RST Title Hierarchy: Fixed title level inconsistencies in device_control.rst

  • Read the Docs Configuration: Updated Python version requirement to 3.13 in Read the Docs config

  • CI Test Failures: Fixed ModuleNotFoundError when running tests without CLI dependencies installed

    • Wrapped CLI module imports in try-except blocks in test modules
    • Tests are skipped gracefully when optional dependencies (click, rich) are not installed
    • Allows pytest to run without CLI extra, while supporting full test suite with tox
    • Network errors in authentication are now marked as retriable for better resilience

Changed

  • Installation Documentation: Updated installation instructions to clarify optional CLI and Rich dependencies

v7.2.2

26 Dec 07:16
903bd26

Choose a tag to compare

Fixed

  • TOU Status Always Showing False: Fixed touStatus field always reporting False regardless of actual device state

    • Root cause: Version 7.2.1 incorrectly changed touStatus to use device-specific 1/2 encoding, but the device uses standard 0/1 encoding
    • Solution: Use Python's built-in bool() for touStatus field (handles 0=False, 1=True naturally)
    • Updated documentation in docs/protocol/quick_reference.rst to note touStatus exception
    • Added tests verifying built-in bool() handles 0/1 encoding correctly
    • Device encoding: 0=OFF/disabled, 1=ON/enabled (standard Python truthiness)