Releases: eman/nwp500-python
Release list
v7.4.7
Added
- OpenEI Client Module: New
OpenEIClientasync 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 fromOPENEI_API_KEYenvironment 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'sPUT /device/touendpoint. - 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--enableflag to activate TOU via MQTT. - CLI Reservations Table Output:
nwp-cli reservations getnow displays reservations as a formatted table by default with global status indicator (ENABLED/DISABLED). Use--jsonflag for JSON output. - CLI
anti-legionella set-period: New subcommand to change the Anti-Legionella cycle period (1-30 days) without toggling the feature. Usenwp-cli anti-legionella set-period 7to update cycle period.
Changed
examples/advanced/tou_openei.py: Rewritten to use the newOpenEIClientandconvert_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 setsubscription 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
Fixed
- Converter Consistency:
div_10()andmul_10()now correctly apply division/multiplication to all input types afterfloat()conversion, not justint/floattypes - 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:
MqttCommandQueuenow raises onQueueFullinstead of silently swallowing the error - Flow Rate Metadata: Removed hardcoded
"GPM"unit fromrecirc_dhw_flow_ratefield; unit is now dynamic based on unit system - Temperature Rounding:
RawCelsiusFahrenheit conversion now uses a catch-all default for standard rounding instead of matching onlySTANDARDenum value - Unit System Default:
is_metric_preferred()now returnsFalse(Fahrenheit) instead ofNonewhen 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.sessionproperty to access the activeaiohttpsession without usinggetattr - 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
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
Fixed
-
Temperature Delta Conversions: Fixed incorrect Fahrenheit conversion for differential temperature settings (heat pump and heater element on/off thresholds)
- Created new
DeciCelsiusDeltaclass for temperature deltas that apply scale factor (9/5) but NOT the +32 offset - Heat pump and heater element differential settings now use
DeciCelsiusDeltainstead ofDeciCelsius 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
- Created new
-
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_preferredconverter for temperature delta values in device models
v7.3.3
Breaking Changes
-
Temperature Setpoint Limits: Replaced hardcoded temperature limits with device-provided values
set_dhw_temperature()now validates against device-specificdhw_temperature_minanddhw_temperature_maxinstead of hardcoded 95-150°F boundsbuild_reservation_entry()changed parameter name fromtemperature_ftotemperature(unit-agnostic)- Added optional
temperature_minandtemperature_maxparameters tobuild_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()andbuild_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 callingfahrenheit_to_half_celsius()with unit-agnostic temperature parameterbuild_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
Changed
-
Unit System Consistency: Removed deprecated
"imperial"unit system identifier in favor of"us_customary"for Home Assistant compatibility- Changed all references from
UnitSystem.IMPERIALtoUnitSystem.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
- Changed all references from
Fixed
-
Unit System Consolidation: Consolidated duplicate
UnitSystemTypetype alias definitions into single canonical definition inunit_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
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
Added
-
Daily Energy Breakdown by Month: New
--monthoption 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
ModuleNotFoundErrorwhen 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
Fixed
-
TOU Status Always Showing False: Fixed
touStatusfield always reportingFalseregardless of actual device state- Root cause: Version 7.2.1 incorrectly changed
touStatusto use device-specific 1/2 encoding, but the device uses standard 0/1 encoding - Solution: Use Python's built-in
bool()fortouStatusfield (handles 0=False, 1=True naturally) - Updated documentation in
docs/protocol/quick_reference.rstto notetouStatusexception - Added tests verifying built-in
bool()handles 0/1 encoding correctly - Device encoding: 0=OFF/disabled, 1=ON/enabled (standard Python truthiness)
- Root cause: Version 7.2.1 incorrectly changed
v7.2.1
Added
-
CLI Command: New
device-infocommand to retrieve basic device information from REST API.. code-block:: bash
Get basic device info (DeviceInfo model)
python3 -m nwp500.cli device-info
python3 -m nwp500.cli device-info --raw -
ConnectionStatus Enum: New
ConnectionStatusenum for device cloud connection stateConnectionStatus.DISCONNECTED= 1 - Device offline/not connectedConnectionStatus.CONNECTED= 2 - Device online and reachable- Used in
DeviceInfo.connectedfield with automatic validation
-
InstallType Enum: New
InstallTypeenum for device installation classificationInstallType.RESIDENTIAL= "R" - Residential useInstallType.COMMERCIAL= "C" - Commercial use- Used in
DeviceInfo.install_typefield with automatic validation - Includes
INSTALL_TYPE_TEXTmapping for display purposes
-
String Enum Validator: New
str_enum_validator()converter for string-based enums
Changed
-
DeviceInfo Model:
connectedfield now usesConnectionStatusenum instead of plain intinstall_typefield now usesInstallTypeenum instead of plain string
-
TOU Status Conversion: Simplified TOU status to use standard
device_bool_to_pythonconverter (consistent with other OnOffFlag fields)- Removed special-case
tou_status_to_python()converter TouStatusannotated type now usesdevice_bool_to_pythonvalidator- Device encoding: 1=OFF/disabled, 2=ON/enabled (consistent with all other boolean fields)
- Removed special-case
-
CLI Documentation: Clarified distinction between
info(DeviceFeature via MQTT) anddevice-info(DeviceInfo via REST API) commands -
Type Annotations: Fixed CLI rich_output console type annotation to declare at class level
Removed
-
constants.py Module: Removed empty
constants.pymodule.CommandCodeenum was already moved toenums.pyin version 4.2.0... code-block:: python
OLD (removed)
from nwp500.constants import CommandCode
NEW (use this)
from nwp500.enums import CommandCode
-
Firmware Tracking: Removed unused firmware tracking constants and documentation (
KNOWN_FIRMWARE_FIELD_CHANGES,LATEST_KNOWN_FIRMWARE,docs/protocol/firmware_tracking.rst) -
TOU Status Converter: Removed redundant
tou_status_to_python()converter function and associated tests