nwp500-python 7.4.10__tar.gz → 8.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/.github/workflows/ci.yml +4 -4
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/.github/workflows/release.yml +3 -3
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/.readthedocs.yml +1 -1
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/CHANGELOG.rst +136 -2
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/CONTRIBUTING.rst +1 -1
- nwp500_python-8.0.0/PKG-INFO +120 -0
- nwp500_python-8.0.0/README.rst +78 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/docs/conf.py +1 -1
- nwp500_python-7.4.10/docs/guides/advanced_features_explained.rst → nwp500_python-8.0.0/docs/explanation/advanced-features.rst +13 -19
- nwp500_python-8.0.0/docs/explanation/architecture.rst +81 -0
- nwp500_python-8.0.0/docs/explanation/index.rst +11 -0
- nwp500_python-7.4.10/docs/guides/auto_recovery.rst → nwp500_python-8.0.0/docs/how-to/auto-recovery.rst +2 -2
- nwp500_python-7.4.10/docs/guides/mqtt_diagnostics.rst → nwp500_python-8.0.0/docs/how-to/diagnose-mqtt.rst +34 -34
- nwp500_python-7.4.10/docs/guides/home_assistant_integration.rst → nwp500_python-8.0.0/docs/how-to/home-assistant.rst +6 -7
- nwp500_python-8.0.0/docs/how-to/index.rst +20 -0
- nwp500_python-8.0.0/docs/how-to/maintenance.rst +119 -0
- nwp500_python-7.4.10/docs/guides/unit_conversion.rst → nwp500_python-8.0.0/docs/how-to/manage-units.rst +5 -5
- nwp500_python-7.4.10/docs/guides/event_system.rst → nwp500_python-8.0.0/docs/how-to/monitor-status.rst +110 -123
- nwp500_python-7.4.10/docs/guides/time_of_use.rst → nwp500_python-8.0.0/docs/how-to/optimize-tou.rst +16 -16
- nwp500_python-7.4.10/docs/guides/command_queue.rst → nwp500_python-8.0.0/docs/how-to/queue-commands.rst +13 -16
- nwp500_python-7.4.10/docs/guides/scheduling.rst → nwp500_python-8.0.0/docs/how-to/schedule-operation.rst +119 -12
- nwp500_python-8.0.0/docs/how-to/track-energy.rst +333 -0
- nwp500_python-8.0.0/docs/index.rst +64 -0
- {nwp500_python-7.4.10/docs/development → nwp500_python-8.0.0/docs/project}/history.rst +14 -13
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/reference}/configuration.rst +4 -4
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/reference}/enumerations.rst +3 -4
- nwp500_python-8.0.0/docs/reference/index.rst +43 -0
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/reference}/installation.rst +11 -7
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/reference}/protocol/data_conversions.rst +6 -6
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/reference}/protocol/device_features.rst +3 -3
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/reference}/protocol/device_status.rst +2 -2
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/reference}/protocol/error_codes.rst +1 -1
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/reference}/protocol/mqtt_protocol.rst +1 -1
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/reference}/protocol/quick_reference.rst +1 -1
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/reference}/python_api/auth_client.rst +4 -4
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/reference}/python_api/cli.rst +3 -3
- nwp500_python-8.0.0/docs/reference/python_api/events.rst +287 -0
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/reference}/python_api/exceptions.rst +18 -18
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/reference}/python_api/models.rst +157 -6
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/reference}/python_api/mqtt_client.rst +374 -317
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/docs/requirements.txt +2 -0
- nwp500_python-7.4.10/docs/quickstart.rst → nwp500_python-8.0.0/docs/tutorials/getting-started.rst +13 -14
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/air_filter_reset.py +3 -3
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/anti_legionella.py +4 -4
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/combined_callbacks.py +3 -3
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/demand_response.py +3 -3
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/device_capabilities.py +2 -2
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/device_status_debug.py +2 -2
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/energy_analytics.py +1 -1
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/firmware_payload_capture.py +4 -4
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/mqtt_diagnostics.py +11 -13
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/power_control.py +3 -3
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/recirculation_control.py +4 -6
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/reconnection_demo.py +7 -7
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/reservation_schedule.py +2 -2
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/token_restoration.py +1 -1
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/tou_openei.py +1 -1
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/tou_schedule.py +5 -5
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/water_reservation.py +2 -2
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/beginner/04_set_temperature.py +2 -2
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/intermediate/advanced_auth_patterns.py +1 -1
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/intermediate/command_queue.py +8 -8
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/intermediate/device_status_callback.py +2 -2
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/intermediate/error_handling.py +2 -2
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/intermediate/event_driven_control.py +30 -33
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/intermediate/improved_auth.py +1 -1
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/intermediate/mqtt_realtime_monitoring.py +3 -3
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/intermediate/periodic_requests.py +4 -4
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/intermediate/set_mode.py +2 -2
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/intermediate/vacation_mode.py +2 -2
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/testing/periodic_device_info.py +2 -2
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/testing/test_mqtt_messaging.py +3 -3
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/pyproject.toml +3 -3
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/setup.cfg +3 -3
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/__init__.py +16 -0
- nwp500_python-8.0.0/src/nwp500/_base.py +78 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/api_client.py +4 -7
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/auth.py +40 -69
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/cli/__init__.py +2 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/cli/__main__.py +3 -1
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/cli/commands.py +2 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/cli/handlers.py +31 -30
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/cli/monitoring.py +3 -3
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/cli/output_formatters.py +2 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/cli/rich_output.py +2 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/cli/token_storage.py +4 -2
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/command_decorators.py +2 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/config.py +3 -0
- nwp500_python-8.0.0/src/nwp500/converters.py +191 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/device_capabilities.py +6 -4
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/device_info_cache.py +13 -11
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/encoding.py +2 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/enums.py +2 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/events.py +15 -8
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/exceptions.py +5 -3
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/factory.py +2 -0
- nwp500_python-8.0.0/src/nwp500/models/__init__.py +96 -0
- nwp500_python-8.0.0/src/nwp500/models/_converters.py +77 -0
- nwp500_python-8.0.0/src/nwp500/models/device.py +59 -0
- nwp500_python-8.0.0/src/nwp500/models/energy.py +78 -0
- nwp500_python-8.0.0/src/nwp500/models/feature.py +411 -0
- nwp500_python-8.0.0/src/nwp500/models/mqtt_models.py +33 -0
- nwp500_python-8.0.0/src/nwp500/models/schedule.py +338 -0
- nwp500_python-8.0.0/src/nwp500/models/status.py +927 -0
- nwp500_python-8.0.0/src/nwp500/models/tou.py +162 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/mqtt/__init__.py +2 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/mqtt/client.py +386 -36
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/mqtt/connection.py +16 -8
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/mqtt/control.py +201 -20
- nwp500_python-8.0.0/src/nwp500/mqtt/state_tracker.py +162 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/mqtt/subscriptions.py +334 -138
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/mqtt/utils.py +51 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/mqtt_events.py +55 -31
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/reservations.py +15 -37
- nwp500_python-8.0.0/src/nwp500/topic_builder.py +70 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/utils.py +2 -0
- nwp500_python-8.0.0/src/nwp500_python.egg-info/PKG-INFO +120 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500_python.egg-info/SOURCES.txt +51 -37
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500_python.egg-info/requires.txt +1 -1
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_auth.py +22 -22
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_cli_commands.py +69 -13
- nwp500_python-8.0.0/tests/test_multi_device.py +243 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_reservations.py +40 -42
- nwp500_python-7.4.10/PKG-INFO +0 -328
- nwp500_python-7.4.10/README.rst +0 -286
- nwp500_python-7.4.10/docs/api/nwp500.rst +0 -182
- nwp500_python-7.4.10/docs/guides/energy_monitoring.rst +0 -339
- nwp500_python-7.4.10/docs/index.rst +0 -161
- nwp500_python-7.4.10/docs/python_api/device_control.rst +0 -1188
- nwp500_python-7.4.10/docs/python_api/events.rst +0 -358
- nwp500_python-7.4.10/src/nwp500/converters.py +0 -543
- nwp500_python-7.4.10/src/nwp500/models.py +0 -1453
- nwp500_python-7.4.10/src/nwp500/topic_builder.py +0 -40
- nwp500_python-7.4.10/src/nwp500_python.egg-info/PKG-INFO +0 -328
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/.coveragerc +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/.github/RESOLVING_PR_COMMENTS.md +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/.github/copilot-instructions.md +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/.gitignore +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/.pre-commit-config.yaml +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/AUTHORS.rst +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/LICENSE.txt +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/Makefile +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/RELEASE.md +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/docs/Makefile +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/docs/_static/.gitignore +0 -0
- /nwp500_python-7.4.10/docs/guides/authentication.rst → /nwp500_python-8.0.0/docs/how-to/authenticate.rst +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/docs/openapi.yaml +0 -0
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/project}/authors.rst +0 -0
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/project}/changelog.rst +0 -0
- {nwp500_python-7.4.10/docs/development → nwp500_python-8.0.0/docs/project}/contributing.rst +0 -0
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/project}/license.rst +0 -0
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/reference}/protocol/rest_api.rst +0 -0
- {nwp500_python-7.4.10/docs → nwp500_python-8.0.0/docs/reference}/python_api/api_client.rst +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/.ruff.toml +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/README.md +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/auto_recovery.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/error_code_demo.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/advanced/simple_auto_recovery.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/beginner/01_authentication.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/beginner/02_list_devices.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/beginner/03_get_status.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/intermediate/legacy_auth_constructor.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/mask.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/testing/simple_periodic_info.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/testing/test_api_client.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/testing/test_mqtt_connection.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/examples/testing/test_periodic_minimal.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/scripts/README.md +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/scripts/bump_version.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/scripts/diagnose_mqtt_connection.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/scripts/extract_changelog.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/scripts/format.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/scripts/lint.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/scripts/setup-dev.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/scripts/validate_version.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/setup.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/field_factory.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/mqtt/command_queue.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/mqtt/diagnostics.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/mqtt/periodic.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/mqtt/reconnection.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/openei.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/py.typed +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/temperature.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500/unit_system.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500_python.egg-info/dependency_links.txt +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500_python.egg-info/entry_points.txt +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500_python.egg-info/not-zip-safe +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/src/nwp500_python.egg-info/top_level.txt +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/conftest.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_api_helpers.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_cli_basic.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_command_decorators.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_command_queue.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_device_capabilities.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_device_info_cache.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_events.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_exceptions.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_model_converters.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_models.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_mqtt_client_init.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_mqtt_hypothesis.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_openei.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_temperature_converters.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_tou_api.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_unit_switching.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tests/test_utils.py +0 -0
- {nwp500_python-7.4.10 → nwp500_python-8.0.0}/tox.ini +0 -0
|
@@ -18,7 +18,7 @@ jobs:
|
|
|
18
18
|
- name: Set up Python
|
|
19
19
|
uses: actions/setup-python@v5
|
|
20
20
|
with:
|
|
21
|
-
python-version: '3.
|
|
21
|
+
python-version: '3.14'
|
|
22
22
|
|
|
23
23
|
- name: Install tox
|
|
24
24
|
run: |
|
|
@@ -37,7 +37,7 @@ jobs:
|
|
|
37
37
|
- name: Set up Python
|
|
38
38
|
uses: actions/setup-python@v5
|
|
39
39
|
with:
|
|
40
|
-
python-version: '3.
|
|
40
|
+
python-version: '3.14'
|
|
41
41
|
|
|
42
42
|
- name: Install ruff
|
|
43
43
|
run: |
|
|
@@ -52,7 +52,7 @@ jobs:
|
|
|
52
52
|
runs-on: ubuntu-latest
|
|
53
53
|
strategy:
|
|
54
54
|
matrix:
|
|
55
|
-
python-version: ['3.
|
|
55
|
+
python-version: ['3.14']
|
|
56
56
|
|
|
57
57
|
steps:
|
|
58
58
|
- uses: actions/checkout@v4
|
|
@@ -87,7 +87,7 @@ jobs:
|
|
|
87
87
|
- name: Set up Python
|
|
88
88
|
uses: actions/setup-python@v5
|
|
89
89
|
with:
|
|
90
|
-
python-version: '3.
|
|
90
|
+
python-version: '3.14'
|
|
91
91
|
|
|
92
92
|
- name: Install build dependencies
|
|
93
93
|
run: |
|
|
@@ -18,7 +18,7 @@ jobs:
|
|
|
18
18
|
- name: Set up Python
|
|
19
19
|
uses: actions/setup-python@v5
|
|
20
20
|
with:
|
|
21
|
-
python-version: '3.
|
|
21
|
+
python-version: '3.14'
|
|
22
22
|
|
|
23
23
|
- name: Install dependencies
|
|
24
24
|
run: |
|
|
@@ -53,7 +53,7 @@ jobs:
|
|
|
53
53
|
- name: Set up Python
|
|
54
54
|
uses: actions/setup-python@v5
|
|
55
55
|
with:
|
|
56
|
-
python-version: '3.
|
|
56
|
+
python-version: '3.14'
|
|
57
57
|
|
|
58
58
|
- name: Install build dependencies
|
|
59
59
|
run: |
|
|
@@ -80,7 +80,7 @@ jobs:
|
|
|
80
80
|
- name: Set up Python
|
|
81
81
|
uses: actions/setup-python@v5
|
|
82
82
|
with:
|
|
83
|
-
python-version: '3.
|
|
83
|
+
python-version: '3.14'
|
|
84
84
|
|
|
85
85
|
- name: Extract changelog for this version
|
|
86
86
|
id: changelog
|
|
@@ -2,6 +2,140 @@
|
|
|
2
2
|
Changelog
|
|
3
3
|
=========
|
|
4
4
|
|
|
5
|
+
Unreleased (8.x)
|
|
6
|
+
================
|
|
7
|
+
|
|
8
|
+
Bug Fixes
|
|
9
|
+
---------
|
|
10
|
+
- **Fix MQTT reconnection after unexpected AWS hangup**: The
|
|
11
|
+
``on_connection_resumed`` callback was missing the ``connection`` parameter
|
|
12
|
+
required by the AWS IoT SDK callback signature. The SDK calls
|
|
13
|
+
``on_connection_resumed(connection, return_code, session_present, **kwargs)``,
|
|
14
|
+
but the handler only accepted ``(return_code, session_present)``. The
|
|
15
|
+
mismatched signature caused the callback to fail silently (exception swallowed
|
|
16
|
+
by the AWS CRT C layer), so ``self._connected`` was never restored to ``True``
|
|
17
|
+
after an ``AWS_ERROR_MQTT_UNEXPECTED_HANGUP``. As a result, the
|
|
18
|
+
``connection_resumed`` event was never emitted, the reconnection loop ran
|
|
19
|
+
indefinitely, and device sensors became permanently unavailable until a manual
|
|
20
|
+
restart. (`#85 <https://github.com/eman/nwp500-python/issues/85>`_)
|
|
21
|
+
|
|
22
|
+
Features
|
|
23
|
+
--------
|
|
24
|
+
- **Multi-device support enhancements**: Improved support for accounts with multiple
|
|
25
|
+
Navilink devices by injecting device identity into models and events.
|
|
26
|
+
|
|
27
|
+
- Added ``mac_address`` field to ``DeviceStatus`` and ``DeviceFeature`` models.
|
|
28
|
+
- Added ``device_mac`` attribute to all device-specific MQTT events (temperature
|
|
29
|
+
changes, mode changes, power updates, errors, etc.).
|
|
30
|
+
- Updated ``DeviceStateTracker`` and ``MqttSubscriptionManager`` to propagate
|
|
31
|
+
device identity correctly.
|
|
32
|
+
|
|
33
|
+
**BREAKING CHANGES**: ``.on()`` event handler callbacks now receive a single typed
|
|
34
|
+
event dataclass instead of positional arguments. ``MqttDeviceController`` is no longer
|
|
35
|
+
accessible as ``.control`` on ``NavienMqttClient``; all control methods are now
|
|
36
|
+
available directly on the client.
|
|
37
|
+
|
|
38
|
+
Breaking Changes
|
|
39
|
+
----------------
|
|
40
|
+
- **Typed event payloads**: All ``.on()`` event handler callbacks now receive a single
|
|
41
|
+
typed event dataclass instance. The dataclasses are exported from
|
|
42
|
+
``nwp500.mqtt_events``.
|
|
43
|
+
|
|
44
|
+
.. code-block:: python
|
|
45
|
+
|
|
46
|
+
# OLD (removed)
|
|
47
|
+
mqtt.on("temperature_changed", lambda old, new: print(old, new))
|
|
48
|
+
mqtt.on("connection_resumed", lambda rc, sp: print(rc, sp))
|
|
49
|
+
|
|
50
|
+
# NEW
|
|
51
|
+
mqtt.on("temperature_changed", lambda e: print(e.old_temperature, e.new_temperature))
|
|
52
|
+
mqtt.on("connection_resumed", lambda e: print(e.return_code, e.session_present))
|
|
53
|
+
|
|
54
|
+
- **``MqttDeviceController`` no longer public**: ``NavienMqttClient`` no longer exposes
|
|
55
|
+
a ``.control`` attribute. All control methods are now available directly on the
|
|
56
|
+
client.
|
|
57
|
+
|
|
58
|
+
.. code-block:: python
|
|
59
|
+
|
|
60
|
+
# OLD (removed)
|
|
61
|
+
await mqtt.control.set_temperature(device, 50)
|
|
62
|
+
|
|
63
|
+
# NEW
|
|
64
|
+
await mqtt.set_temperature(device, 50)
|
|
65
|
+
|
|
66
|
+
Migration Guide (from 7.x.x)
|
|
67
|
+
----------------------------
|
|
68
|
+
The following steps are recommended for a smooth migration, particularly for complex
|
|
69
|
+
integrations like Home Assistant:
|
|
70
|
+
|
|
71
|
+
1. **Update Event Listeners**: Locate all ``mqtt.on()`` or ``mqtt.once()`` calls.
|
|
72
|
+
Update the callback signatures to accept a single argument (the event object) and
|
|
73
|
+
update the body to access fields via the object (e.g., ``event.new_temperature``
|
|
74
|
+
instead of ``new_val``).
|
|
75
|
+
2. **Refactor Control Calls**: Remove ``.control`` from all device command invocations.
|
|
76
|
+
Instead of ``await mqtt.control.set_power(...)``, use ``await mqtt.set_power(...)``.
|
|
77
|
+
3. **Handle Unit Conversions**: If your integration previously performed its own
|
|
78
|
+
conversions or relied on the library's eager conversion, note that
|
|
79
|
+
``DeviceStatus`` fields like ``dhw_temperature`` are now properties. They return
|
|
80
|
+
values based on the global unit system context (``us_customary`` by default).
|
|
81
|
+
|
|
82
|
+
* **Home Assistant Tip**: To ensure your state tracking is immune to unit system
|
|
83
|
+
toggles within the library, use the new ``*_raw`` fields (e.g.,
|
|
84
|
+
``status.dhw_temperature_raw``) for comparison logic, and use the properties
|
|
85
|
+
only for display or when a converted value is explicitly needed.
|
|
86
|
+
4. **Remove ``from_dict()`` Calls**: The ``from_dict()`` method has been removed
|
|
87
|
+
from all models. Use ``model_validate()`` instead.
|
|
88
|
+
|
|
89
|
+
* **Note**: ``AuthenticationResponse.model_validate()`` now automatically handles
|
|
90
|
+
the ``"data": { ... }`` wrapper found in raw API responses.
|
|
91
|
+
5. **Subpackage Imports**: While top-level imports from ``nwp500.models`` are
|
|
92
|
+
preserved, if you were importing from the internal ``nwp500.models`` module file
|
|
93
|
+
directly, you must update your imports to point to the new structured files
|
|
94
|
+
(e.g., ``nwp500.models.status``).
|
|
95
|
+
|
|
96
|
+
Added
|
|
97
|
+
-----
|
|
98
|
+
- **New control methods**: Nine previously unimplemented ``CommandCode`` values now have
|
|
99
|
+
full implementations: ``check_firmware``, ``commit_firmware``, ``reconnect_wifi``,
|
|
100
|
+
``reset_wifi``, ``set_freeze_protection_temperature``, ``run_smart_diagnostic``,
|
|
101
|
+
``enable_intelligent_reservation``, ``disable_intelligent_reservation``, and
|
|
102
|
+
``set_water_program_reservation``.
|
|
103
|
+
- **Typed subscription methods**: ``subscribe_reservation``,
|
|
104
|
+
``subscribe_weekly_reservation``, and ``subscribe_recirculation`` return typed
|
|
105
|
+
responses directly without requiring raw MQTT event handlers.
|
|
106
|
+
- **New protocol models**: ``WeeklyReservationSchedule``, ``WeeklyReservationEntry``,
|
|
107
|
+
``RecirculationSchedule``, ``RecirculationScheduleEntry``, and ``OtaCommitPayload``.
|
|
108
|
+
- **``DeviceStateTracker``**: State change detection extracted into a dedicated class
|
|
109
|
+
in ``nwp500.mqtt.state_tracker`` with per-device tracking keyed by MAC address.
|
|
110
|
+
- **``MQTT_PROTOCOL_VERSION`` constant**: Protocol version is now a named constant in
|
|
111
|
+
``nwp500.config`` rather than a hardcoded integer in the command payload builder.
|
|
112
|
+
- **``response_ack_topic()``**: New method on ``MqttTopicBuilder`` for control command
|
|
113
|
+
acknowledgement topics.
|
|
114
|
+
|
|
115
|
+
Changed
|
|
116
|
+
-------
|
|
117
|
+
- **Unit conversion redesign**: Temperature, flow rate, and volume fields in
|
|
118
|
+
``DeviceStatus`` and ``DeviceFeature`` now store raw device values as ``*_raw: int``
|
|
119
|
+
fields and expose converted values via lazy computed properties. Conversion happens at
|
|
120
|
+
access time rather than during Pydantic deserialization, preserving the original
|
|
121
|
+
device value in all cases.
|
|
122
|
+
- **Models split into subpackage**: ``nwp500.models`` is now a package
|
|
123
|
+
(``nwp500/models/``) with modules for status, schedule, TOU, and MQTT models. Public
|
|
124
|
+
imports from ``nwp500.models`` are unchanged.
|
|
125
|
+
- **Topic building centralised**: All MQTT topic construction now goes through
|
|
126
|
+
``MqttTopicBuilder``. Hardcoded topic strings removed from ``control.py``,
|
|
127
|
+
``reservations.py``, and ``cli/handlers.py``.
|
|
128
|
+
- **``set_vacation_days`` delegates to ``set_dhw_mode``**: The method now calls
|
|
129
|
+
``set_dhw_mode(device, DhwOperationSetting.VACATION, vacation_days=days)`` directly.
|
|
130
|
+
- **Per-device state tracking**: ``_previous_status`` changed from a single
|
|
131
|
+
``DeviceStatus | None`` to a ``dict[str, DeviceStatus]`` keyed by MAC address,
|
|
132
|
+
preventing spurious state-change events when multiple devices are connected.
|
|
133
|
+
- **Unit system stored as instance variable**: ``NavienAPIClient``,
|
|
134
|
+
``NavienMqttClient``, and ``NavienAuthClient`` no longer call ``set_unit_system()``
|
|
135
|
+
as a constructor side-effect.
|
|
136
|
+
- **``NavienBaseModel`` consolidated**: Duplicate definitions in ``auth.py`` and
|
|
137
|
+
``models.py`` merged into a single definition in ``nwp500._base``.
|
|
138
|
+
|
|
5
139
|
Version 7.4.10 (2026-04-13)
|
|
6
140
|
===========================
|
|
7
141
|
|
|
@@ -205,7 +339,7 @@ Breaking Changes
|
|
|
205
339
|
.. code-block:: python
|
|
206
340
|
|
|
207
341
|
# OLD (hardcoded 95-150°F)
|
|
208
|
-
await mqtt.
|
|
342
|
+
await mqtt.set_dhw_temperature(device, temperature_f=140.0)
|
|
209
343
|
entry = build_reservation_entry(
|
|
210
344
|
enabled=True,
|
|
211
345
|
days=["Monday"],
|
|
@@ -217,7 +351,7 @@ Breaking Changes
|
|
|
217
351
|
|
|
218
352
|
# NEW (device-provided limits, unit-aware)
|
|
219
353
|
# Temperature value automatically uses user's preferred unit
|
|
220
|
-
await mqtt.
|
|
354
|
+
await mqtt.set_dhw_temperature(device, 140.0)
|
|
221
355
|
|
|
222
356
|
# Device features provide min/max in user's preferred unit
|
|
223
357
|
features = await device_info_cache.get(device.device_info.mac_address)
|
|
@@ -135,7 +135,7 @@ Follow a clear exception hierarchy with consistent naming:
|
|
|
135
135
|
.. code-block:: python
|
|
136
136
|
|
|
137
137
|
try:
|
|
138
|
-
await mqtt_client.
|
|
138
|
+
await mqtt_client.set_temperature(device, 150)
|
|
139
139
|
except MqttNotConnectedError:
|
|
140
140
|
# Handle specific case: not connected
|
|
141
141
|
print("Connect to device first")
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nwp500-python
|
|
3
|
+
Version: 8.0.0
|
|
4
|
+
Summary: A library for controlling Navien NWP500 Water Heaters via NaviLink
|
|
5
|
+
Home-page: https://github.com/eman/nwp500-python
|
|
6
|
+
Author: Emmanuel Levijarvi
|
|
7
|
+
Author-email: emansl@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Documentation, https://nwp500-python.readthedocs.io/en/latest/
|
|
10
|
+
Project-URL: Source, https://github.com/eman/nwp500-python
|
|
11
|
+
Project-URL: Tracker, https://github.com/eman/nwp500-python/issues
|
|
12
|
+
Platform: any
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Programming Language :: Python
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Requires-Python: >=3.14
|
|
19
|
+
Description-Content-Type: text/x-rst; charset=UTF-8
|
|
20
|
+
License-File: LICENSE.txt
|
|
21
|
+
Requires-Dist: aiohttp>=3.13.5
|
|
22
|
+
Requires-Dist: awsiotsdk>=1.29.0
|
|
23
|
+
Requires-Dist: pydantic>=2.0.0
|
|
24
|
+
Provides-Extra: cli
|
|
25
|
+
Requires-Dist: click>=8.3.0; extra == "cli"
|
|
26
|
+
Requires-Dist: rich>=14.3.0; extra == "cli"
|
|
27
|
+
Provides-Extra: testing
|
|
28
|
+
Requires-Dist: setuptools; extra == "testing"
|
|
29
|
+
Requires-Dist: pytest; extra == "testing"
|
|
30
|
+
Requires-Dist: pytest-cov; extra == "testing"
|
|
31
|
+
Requires-Dist: pytest-asyncio; extra == "testing"
|
|
32
|
+
Requires-Dist: hypothesis; extra == "testing"
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pyright>=1.1.0; extra == "dev"
|
|
36
|
+
Requires-Dist: setuptools; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
39
|
+
Requires-Dist: pytest-asyncio; extra == "dev"
|
|
40
|
+
Requires-Dist: hypothesis; extra == "dev"
|
|
41
|
+
Dynamic: license-file
|
|
42
|
+
|
|
43
|
+
=============
|
|
44
|
+
nwp500-python
|
|
45
|
+
=============
|
|
46
|
+
|
|
47
|
+
|PyPI-v| |Python-versions| |CI-status| |Docs-status| |Code-style| |License|
|
|
48
|
+
|
|
49
|
+
Python library for Navien NWP500 Heat Pump Water Heater
|
|
50
|
+
========================================================
|
|
51
|
+
|
|
52
|
+
A complete Python library for monitoring and controlling the Navien NWP500 Heat Pump Water Heater through the Navilink cloud service.
|
|
53
|
+
|
|
54
|
+
* **Documentation:** https://nwp500-python.readthedocs.io/
|
|
55
|
+
* **Source:** https://github.com/eman/nwp500-python
|
|
56
|
+
|
|
57
|
+
Features
|
|
58
|
+
========
|
|
59
|
+
* **Complete Interface:** Full support for both REST API and real-time MQTT (AWS IoT).
|
|
60
|
+
* **Monitoring:** Real-time tracking of temperature, power usage, tank charge, and component status.
|
|
61
|
+
* **Control:** Remote control of target temperatures, operation modes, and vacation settings.
|
|
62
|
+
* **Advanced Features:** Native support for reservations, time-of-use (TOU) optimization, and anti-legionella cycles.
|
|
63
|
+
* **Type-Safe:** Built with Pydantic for robust data validation and unit handling.
|
|
64
|
+
* **Async/Await:** Modern asyncio-based implementation for high-performance integration.
|
|
65
|
+
|
|
66
|
+
Getting Started
|
|
67
|
+
===============
|
|
68
|
+
|
|
69
|
+
.. code-block:: bash
|
|
70
|
+
|
|
71
|
+
pip install nwp500-python
|
|
72
|
+
|
|
73
|
+
Quick Example
|
|
74
|
+
-------------
|
|
75
|
+
|
|
76
|
+
.. code-block:: python
|
|
77
|
+
|
|
78
|
+
from nwp500 import NavienAuthClient, NavienAPIClient
|
|
79
|
+
|
|
80
|
+
async with NavienAuthClient("email@example.com", "password") as auth:
|
|
81
|
+
api = NavienAPIClient(auth)
|
|
82
|
+
devices = await api.list_devices()
|
|
83
|
+
|
|
84
|
+
if devices:
|
|
85
|
+
device = devices[0]
|
|
86
|
+
print(f"Temperature: {device.status.dhw_temperature}°F")
|
|
87
|
+
await api.set_device_temperature(device, 130)
|
|
88
|
+
|
|
89
|
+
Documentation
|
|
90
|
+
=============
|
|
91
|
+
|
|
92
|
+
The documentation follows the `Diátaxis <https://diataxis.fr/>`_ framework:
|
|
93
|
+
|
|
94
|
+
* `Tutorials <https://nwp500-python.readthedocs.io/en/latest/tutorials/getting-started.html>`_: Start here if you're new to the library.
|
|
95
|
+
* `How-to Guides <https://nwp500-python.readthedocs.io/en/latest/how-to/index.html>`_: Practical step-by-step recipes for specific tasks.
|
|
96
|
+
* `Reference <https://nwp500-python.readthedocs.io/en/latest/reference/index.html>`_: Technical descriptions of the API, models, and protocol.
|
|
97
|
+
* `Explanation <https://nwp500-python.readthedocs.io/en/latest/explanation/index.html>`_: Understanding-oriented deep dives into the library's design and advanced features.
|
|
98
|
+
|
|
99
|
+
Contributing
|
|
100
|
+
============
|
|
101
|
+
|
|
102
|
+
We welcome contributions! Please see our `Contributing Guide <https://nwp500-python.readthedocs.io/en/latest/project/contributing.html>`_ for more details.
|
|
103
|
+
|
|
104
|
+
License
|
|
105
|
+
=======
|
|
106
|
+
|
|
107
|
+
This project is licensed under the MIT License. See the `LICENSE.txt <https://github.com/eman/nwp500-python/blob/main/LICENSE.txt>`_ file for details.
|
|
108
|
+
|
|
109
|
+
.. |PyPI-v| image:: https://img.shields.io/pypi/v/nwp500-python.svg
|
|
110
|
+
:target: https://pypi.org/project/nwp500-python/
|
|
111
|
+
.. |Python-versions| image:: https://img.shields.io/pypi/pyversions/nwp500-python.svg
|
|
112
|
+
:target: https://pypi.org/project/nwp500-python/
|
|
113
|
+
.. |CI-status| image:: https://github.com/eman/nwp500-python/actions/workflows/ci.yml/badge.svg
|
|
114
|
+
:target: https://github.com/eman/nwp500-python/actions/workflows/ci.yml
|
|
115
|
+
.. |Docs-status| image:: https://readthedocs.org/projects/nwp500-python/badge/?version=latest
|
|
116
|
+
:target: https://nwp500-python.readthedocs.io/en/latest/?badge=latest
|
|
117
|
+
.. |Code-style| image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
|
|
118
|
+
:target: https://github.com/astral-sh/ruff
|
|
119
|
+
.. |License| image:: https://img.shields.io/pypi/l/nwp500-python.svg
|
|
120
|
+
:target: https://opensource.org/licenses/MIT
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
=============
|
|
2
|
+
nwp500-python
|
|
3
|
+
=============
|
|
4
|
+
|
|
5
|
+
|PyPI-v| |Python-versions| |CI-status| |Docs-status| |Code-style| |License|
|
|
6
|
+
|
|
7
|
+
Python library for Navien NWP500 Heat Pump Water Heater
|
|
8
|
+
========================================================
|
|
9
|
+
|
|
10
|
+
A complete Python library for monitoring and controlling the Navien NWP500 Heat Pump Water Heater through the Navilink cloud service.
|
|
11
|
+
|
|
12
|
+
* **Documentation:** https://nwp500-python.readthedocs.io/
|
|
13
|
+
* **Source:** https://github.com/eman/nwp500-python
|
|
14
|
+
|
|
15
|
+
Features
|
|
16
|
+
========
|
|
17
|
+
* **Complete Interface:** Full support for both REST API and real-time MQTT (AWS IoT).
|
|
18
|
+
* **Monitoring:** Real-time tracking of temperature, power usage, tank charge, and component status.
|
|
19
|
+
* **Control:** Remote control of target temperatures, operation modes, and vacation settings.
|
|
20
|
+
* **Advanced Features:** Native support for reservations, time-of-use (TOU) optimization, and anti-legionella cycles.
|
|
21
|
+
* **Type-Safe:** Built with Pydantic for robust data validation and unit handling.
|
|
22
|
+
* **Async/Await:** Modern asyncio-based implementation for high-performance integration.
|
|
23
|
+
|
|
24
|
+
Getting Started
|
|
25
|
+
===============
|
|
26
|
+
|
|
27
|
+
.. code-block:: bash
|
|
28
|
+
|
|
29
|
+
pip install nwp500-python
|
|
30
|
+
|
|
31
|
+
Quick Example
|
|
32
|
+
-------------
|
|
33
|
+
|
|
34
|
+
.. code-block:: python
|
|
35
|
+
|
|
36
|
+
from nwp500 import NavienAuthClient, NavienAPIClient
|
|
37
|
+
|
|
38
|
+
async with NavienAuthClient("email@example.com", "password") as auth:
|
|
39
|
+
api = NavienAPIClient(auth)
|
|
40
|
+
devices = await api.list_devices()
|
|
41
|
+
|
|
42
|
+
if devices:
|
|
43
|
+
device = devices[0]
|
|
44
|
+
print(f"Temperature: {device.status.dhw_temperature}°F")
|
|
45
|
+
await api.set_device_temperature(device, 130)
|
|
46
|
+
|
|
47
|
+
Documentation
|
|
48
|
+
=============
|
|
49
|
+
|
|
50
|
+
The documentation follows the `Diátaxis <https://diataxis.fr/>`_ framework:
|
|
51
|
+
|
|
52
|
+
* `Tutorials <https://nwp500-python.readthedocs.io/en/latest/tutorials/getting-started.html>`_: Start here if you're new to the library.
|
|
53
|
+
* `How-to Guides <https://nwp500-python.readthedocs.io/en/latest/how-to/index.html>`_: Practical step-by-step recipes for specific tasks.
|
|
54
|
+
* `Reference <https://nwp500-python.readthedocs.io/en/latest/reference/index.html>`_: Technical descriptions of the API, models, and protocol.
|
|
55
|
+
* `Explanation <https://nwp500-python.readthedocs.io/en/latest/explanation/index.html>`_: Understanding-oriented deep dives into the library's design and advanced features.
|
|
56
|
+
|
|
57
|
+
Contributing
|
|
58
|
+
============
|
|
59
|
+
|
|
60
|
+
We welcome contributions! Please see our `Contributing Guide <https://nwp500-python.readthedocs.io/en/latest/project/contributing.html>`_ for more details.
|
|
61
|
+
|
|
62
|
+
License
|
|
63
|
+
=======
|
|
64
|
+
|
|
65
|
+
This project is licensed under the MIT License. See the `LICENSE.txt <https://github.com/eman/nwp500-python/blob/main/LICENSE.txt>`_ file for details.
|
|
66
|
+
|
|
67
|
+
.. |PyPI-v| image:: https://img.shields.io/pypi/v/nwp500-python.svg
|
|
68
|
+
:target: https://pypi.org/project/nwp500-python/
|
|
69
|
+
.. |Python-versions| image:: https://img.shields.io/pypi/pyversions/nwp500-python.svg
|
|
70
|
+
:target: https://pypi.org/project/nwp500-python/
|
|
71
|
+
.. |CI-status| image:: https://github.com/eman/nwp500-python/actions/workflows/ci.yml/badge.svg
|
|
72
|
+
:target: https://github.com/eman/nwp500-python/actions/workflows/ci.yml
|
|
73
|
+
.. |Docs-status| image:: https://readthedocs.org/projects/nwp500-python/badge/?version=latest
|
|
74
|
+
:target: https://nwp500-python.readthedocs.io/en/latest/?badge=latest
|
|
75
|
+
.. |Code-style| image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
|
|
76
|
+
:target: https://github.com/astral-sh/ruff
|
|
77
|
+
.. |License| image:: https://img.shields.io/pypi/l/nwp500-python.svg
|
|
78
|
+
:target: https://opensource.org/licenses/MIT
|
|
@@ -33,7 +33,7 @@ try: # for Sphinx >= 1.7
|
|
|
33
33
|
except ImportError:
|
|
34
34
|
from sphinx import apidoc
|
|
35
35
|
|
|
36
|
-
output_dir = os.path.join(__location__, "api")
|
|
36
|
+
output_dir = os.path.join(__location__, "reference", "api")
|
|
37
37
|
module_dir = os.path.join(__location__, "../src/nwp500")
|
|
38
38
|
try:
|
|
39
39
|
shutil.rmtree(output_dir)
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
Weather Response, Demand Response, and Tank Stratification
|
|
2
|
+
===========================================================
|
|
3
3
|
|
|
4
|
-
This document
|
|
4
|
+
This document covers three advanced NWP500 features.
|
|
5
5
|
|
|
6
6
|
Overview of Advanced Features
|
|
7
7
|
-----------------------------
|
|
8
8
|
|
|
9
|
-
The NWP500 heat pump water heater implements
|
|
9
|
+
The NWP500 heat pump water heater implements algorithms for grid integration, environmental responsiveness, and efficiency optimization:
|
|
10
10
|
|
|
11
11
|
1. **Weather-Responsive Heating** - Adjusts heating strategy based on ambient temperature conditions
|
|
12
12
|
2. **Demand Response Integration** - Responds to grid signals for demand/response events (CTA-2045)
|
|
13
|
-
3. **Tank Stratification Optimization** - Uses dual temperature sensors for
|
|
13
|
+
3. **Tank Stratification Optimization** - Uses dual temperature sensors for improved heating efficiency
|
|
14
14
|
|
|
15
15
|
Weather-Responsive Heating
|
|
16
16
|
==========================
|
|
@@ -18,7 +18,7 @@ Weather-Responsive Heating
|
|
|
18
18
|
Feature Overview
|
|
19
19
|
----------------
|
|
20
20
|
|
|
21
|
-
The device continuously monitors ambient air temperature to optimize heat pump performance and adjust heating strategies
|
|
21
|
+
The device continuously monitors ambient air temperature to optimize heat pump performance and adjust heating strategies based on seasonal conditions.
|
|
22
22
|
|
|
23
23
|
Technical Implementation
|
|
24
24
|
------------------------
|
|
@@ -109,7 +109,7 @@ The ``outsideTemperature`` field is transmitted in the device status update. Pyt
|
|
|
109
109
|
.. code-block:: python
|
|
110
110
|
|
|
111
111
|
# From device status updates
|
|
112
|
-
status = await mqtt_client.
|
|
112
|
+
status = await mqtt_client.request_device_status()
|
|
113
113
|
|
|
114
114
|
# Access ambient temperature data
|
|
115
115
|
outdoor_temp = status.outside_temperature # Raw integer value
|
|
@@ -230,12 +230,6 @@ Implementation in Device Firmware
|
|
|
230
230
|
3. **Grid Stability**: Participate in demand response events, earn utility incentives
|
|
231
231
|
4. **Cost Reduction**: Shift heating to low-price periods automatically
|
|
232
232
|
|
|
233
|
-
Utility Integration Requirements
|
|
234
|
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
235
|
-
|
|
236
|
-
To use demand response with your NWP500:
|
|
237
|
-
|
|
238
|
-
|
|
239
233
|
Tank Temperature Sensors
|
|
240
234
|
------------------------
|
|
241
235
|
|
|
@@ -389,7 +383,7 @@ Monitoring Stratification from Python
|
|
|
389
383
|
async def monitor_stratification(mqtt_client: NavienMQTTClient, device_id: str):
|
|
390
384
|
"""Monitor tank stratification quality"""
|
|
391
385
|
|
|
392
|
-
status = await mqtt_client.
|
|
386
|
+
status = await mqtt_client.request_device_status(device_id)
|
|
393
387
|
|
|
394
388
|
upper_temp = status.tank_upper_temperature # float in °F
|
|
395
389
|
lower_temp = status.tank_lower_temperature # float in °F
|
|
@@ -470,7 +464,7 @@ The NWP500 uses **half-degrees Celsius** encoding for temperature fields.
|
|
|
470
464
|
|
|
471
465
|
**Related Documentation**:
|
|
472
466
|
|
|
473
|
-
See :doc:`../protocol/data_conversions` for complete field conversion reference and formula applications.
|
|
467
|
+
See :doc:`../reference/protocol/data_conversions` for complete field conversion reference and formula applications.
|
|
474
468
|
|
|
475
469
|
Summary and Recommendations
|
|
476
470
|
============================
|
|
@@ -497,7 +491,7 @@ Summary and Recommendations
|
|
|
497
491
|
See Also
|
|
498
492
|
--------
|
|
499
493
|
|
|
500
|
-
* :doc:`../protocol/data_conversions` - Temperature field conversions (HalfCelsiusToF, DeciCelsiusToF)
|
|
501
|
-
* :doc:`../protocol/device_status` - Complete device status field reference
|
|
502
|
-
* :doc
|
|
503
|
-
* :doc:`../python_api/models` - DeviceStatus model field definitions
|
|
494
|
+
* :doc:`../reference/protocol/data_conversions` - Temperature field conversions (HalfCelsiusToF, DeciCelsiusToF)
|
|
495
|
+
* :doc:`../reference/protocol/device_status` - Complete device status field reference
|
|
496
|
+
* :doc:`../how-to/schedule-operation` - Scheduling and automation guide
|
|
497
|
+
* :doc:`../reference/python_api/models` - DeviceStatus model field definitions
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
============
|
|
2
|
+
Architecture
|
|
3
|
+
============
|
|
4
|
+
|
|
5
|
+
This document explains the high-level architecture of the ``nwp500-python`` library and how it interacts with the Navien Smart Control cloud platform.
|
|
6
|
+
|
|
7
|
+
System Overview
|
|
8
|
+
===============
|
|
9
|
+
|
|
10
|
+
The library acts as a bridge between your Python application and the Navien NWP500 Heat Pump Water Heater. Communication happens through two primary channels:
|
|
11
|
+
|
|
12
|
+
1. **REST API**: Used for authentication, account management, and listing devices.
|
|
13
|
+
2. **MQTT (AWS IoT)**: Used for real-time monitoring and control of the device.
|
|
14
|
+
|
|
15
|
+
Component Diagram
|
|
16
|
+
=================
|
|
17
|
+
|
|
18
|
+
.. code-block:: text
|
|
19
|
+
|
|
20
|
+
+-------------------+ +------------------------+
|
|
21
|
+
| | | |
|
|
22
|
+
| Your Application | | Navien Smart Control |
|
|
23
|
+
| | | (Cloud) |
|
|
24
|
+
+---------+---------+ +-----------+------------+
|
|
25
|
+
| |
|
|
26
|
+
| +-------------+ |
|
|
27
|
+
+------>| Auth Client |<------+ (Sign-in/Tokens)
|
|
28
|
+
| +-------------+ |
|
|
29
|
+
| |
|
|
30
|
+
| +-------------+ |
|
|
31
|
+
+------>| API Client |<------+ (REST API)
|
|
32
|
+
| +-------------+ |
|
|
33
|
+
| |
|
|
34
|
+
| +-------------+ |
|
|
35
|
+
+------>| MQTT Client |<------+ (AWS IoT Core)
|
|
36
|
+
+-------------+
|
|
37
|
+
|
|
38
|
+
Core Components
|
|
39
|
+
===============
|
|
40
|
+
|
|
41
|
+
Authentication Client
|
|
42
|
+
---------------------
|
|
43
|
+
|
|
44
|
+
The ``NavienAuthClient`` is responsible for managing credentials and tokens. It performs the initial sign-in to obtain:
|
|
45
|
+
* A JWT access token for REST API requests.
|
|
46
|
+
* AWS IoT credentials (identity ID, session token, etc.) for MQTT connection.
|
|
47
|
+
|
|
48
|
+
REST API Client
|
|
49
|
+
---------------
|
|
50
|
+
|
|
51
|
+
The ``NavienAPIClient`` provides methods for "heavy" or infrequent operations, such as:
|
|
52
|
+
* Retrieving the list of devices.
|
|
53
|
+
* Getting detailed device information.
|
|
54
|
+
* Accessing historical energy data.
|
|
55
|
+
|
|
56
|
+
MQTT Client
|
|
57
|
+
-----------
|
|
58
|
+
|
|
59
|
+
The ``NavienMqttClient`` is the heart of real-time interaction. It maintains a persistent connection to AWS IoT Core and handles:
|
|
60
|
+
* Subscribing to device status updates.
|
|
61
|
+
* Publishing control commands (e.g., setting temperature).
|
|
62
|
+
* Parsing incoming hex-encoded payloads into structured data models.
|
|
63
|
+
|
|
64
|
+
Data Models
|
|
65
|
+
===========
|
|
66
|
+
|
|
67
|
+
The library uses **Pydantic** for all data models. This ensures:
|
|
68
|
+
* **Type Safety**: All fields have explicit types.
|
|
69
|
+
* **Validation**: Incoming data is validated against expected formats.
|
|
70
|
+
* **Unit Handling**: Temperatures and other units are automatically converted to appropriate scales (e.g., Fahrenheit).
|
|
71
|
+
|
|
72
|
+
Event System
|
|
73
|
+
============
|
|
74
|
+
|
|
75
|
+
The library implements an asynchronous event system. You can subscribe to various events (e.g., status updates, connection changes) and provide callback functions that will be executed when those events occur.
|
|
76
|
+
|
|
77
|
+
See Also
|
|
78
|
+
========
|
|
79
|
+
|
|
80
|
+
* :doc:`advanced-features` - Deep dive into TOU, reservations, and more.
|
|
81
|
+
* :doc:`../reference/protocol/mqtt_protocol` - Low-level details of the MQTT messaging.
|
|
@@ -127,7 +127,7 @@ Refresh authentication tokens before retrying (handles token expiry).
|
|
|
127
127
|
await mqtt_client.subscribe_device_status(device, on_status)
|
|
128
128
|
await mqtt_client.start_periodic_requests(device)
|
|
129
129
|
|
|
130
|
-
**Pros:** Handles token expiry, more
|
|
130
|
+
**Pros:** Handles token expiry, more reliable
|
|
131
131
|
|
|
132
132
|
**Cons:** More complex, need to manage client lifecycle
|
|
133
133
|
|
|
@@ -453,4 +453,4 @@ For production use, **use Strategy 4 (Exponential Backoff)** via the ``Resilient
|
|
|
453
453
|
* Subscription restoration
|
|
454
454
|
* Configurable limits and delays
|
|
455
455
|
|
|
456
|
-
|
|
456
|
+
Your application will stay connected even through extended network outages.
|