nwp500-python 7.3.2__tar.gz → 7.3.4__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.3.2 → nwp500_python-7.3.4}/CHANGELOG.rst +108 -0
- {nwp500_python-7.3.2/src/nwp500_python.egg-info → nwp500_python-7.3.4}/PKG-INFO +1 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/api/nwp500.rst +8 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/guides/reservations.rst +32 -31
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/protocol/data_conversions.rst +25 -17
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/protocol/mqtt_protocol.rst +1 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/python_api/device_control.rst +8 -7
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/python_api/mqtt_client.rst +12 -10
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/combined_callbacks.py +4 -2
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/demand_response.py +2 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/device_capabilities.py +3 -2
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/device_status_debug.py +2 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/power_control.py +2 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/reconnection_demo.py +2 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/reservation_schedule.py +12 -6
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/simple_auto_recovery.py +2 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/water_reservation.py +2 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/beginner/03_get_status.py +2 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/beginner/04_set_temperature.py +14 -9
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/intermediate/advanced_auth_patterns.py +4 -2
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/intermediate/device_status_callback.py +14 -8
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/intermediate/event_driven_control.py +8 -5
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/intermediate/improved_auth.py +3 -2
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/intermediate/mqtt_realtime_monitoring.py +4 -3
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/intermediate/periodic_requests.py +2 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/intermediate/set_mode.py +2 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/intermediate/vacation_mode.py +2 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/testing/periodic_device_info.py +2 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/testing/test_periodic_minimal.py +2 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/__init__.py +4 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/cli/handlers.py +3 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/cli/monitoring.py +4 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/cli/output_formatters.py +56 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/converters.py +39 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/encoding.py +23 -11
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/events.py +4 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/models.py +69 -8
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/mqtt/control.py +28 -5
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/mqtt/subscriptions.py +4 -3
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/mqtt_events.py +14 -8
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/temperature.py +74 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4/src/nwp500_python.egg-info}/PKG-INFO +1 -1
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/test_api_helpers.py +4 -4
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/.agent/workflows/pre-completion-testing.md +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/.coveragerc +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/.github/copilot-instructions.md +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/.github/workflows/ci.yml +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/.github/workflows/release.yml +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/.gitignore +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/.pre-commit-config.yaml +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/.readthedocs.yml +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/AUTHORS.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/CONTRIBUTING.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/LICENSE.txt +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/Makefile +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/README.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/RELEASE.md +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/Makefile +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/_static/.gitignore +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/authors.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/changelog.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/conf.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/configuration.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/development/contributing.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/development/history.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/enumerations.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/guides/advanced_features_explained.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/guides/authentication.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/guides/auto_recovery.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/guides/command_queue.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/guides/energy_monitoring.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/guides/event_system.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/guides/home_assistant_integration.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/guides/mqtt_diagnostics.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/guides/scheduling_features.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/guides/time_of_use.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/guides/unit_conversion.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/index.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/installation.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/license.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/openapi.yaml +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/protocol/device_features.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/protocol/device_status.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/protocol/error_codes.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/protocol/quick_reference.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/protocol/rest_api.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/python_api/api_client.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/python_api/auth_client.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/python_api/cli.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/python_api/events.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/python_api/exceptions.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/python_api/models.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/quickstart.rst +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/docs/requirements.txt +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/.ruff.toml +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/README.md +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/air_filter_reset.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/anti_legionella.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/auto_recovery.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/energy_analytics.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/error_code_demo.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/mqtt_diagnostics.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/recirculation_control.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/token_restoration.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/tou_openei.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/advanced/tou_schedule.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/beginner/01_authentication.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/beginner/02_list_devices.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/intermediate/command_queue.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/intermediate/error_handling.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/intermediate/legacy_auth_constructor.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/mask.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/testing/simple_periodic_info.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/testing/test_api_client.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/testing/test_mqtt_connection.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/examples/testing/test_mqtt_messaging.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/pyproject.toml +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/scripts/README.md +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/scripts/bump_version.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/scripts/diagnose_mqtt_connection.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/scripts/extract_changelog.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/scripts/format.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/scripts/lint.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/scripts/setup-dev.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/scripts/validate_version.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/setup.cfg +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/setup.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/api_client.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/auth.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/cli/__init__.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/cli/__main__.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/cli/commands.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/cli/rich_output.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/cli/token_storage.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/command_decorators.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/config.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/device_capabilities.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/device_info_cache.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/enums.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/exceptions.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/factory.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/field_factory.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/mqtt/__init__.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/mqtt/client.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/mqtt/command_queue.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/mqtt/connection.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/mqtt/diagnostics.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/mqtt/periodic.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/mqtt/reconnection.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/mqtt/utils.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/py.typed +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/topic_builder.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/unit_system.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500/utils.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500_python.egg-info/SOURCES.txt +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500_python.egg-info/dependency_links.txt +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500_python.egg-info/entry_points.txt +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500_python.egg-info/not-zip-safe +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500_python.egg-info/requires.txt +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/src/nwp500_python.egg-info/top_level.txt +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/conftest.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/test_auth.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/test_cli_basic.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/test_cli_commands.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/test_command_decorators.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/test_command_queue.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/test_device_capabilities.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/test_device_info_cache.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/test_events.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/test_exceptions.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/test_model_converters.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/test_models.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/test_mqtt_client_init.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/test_temperature_converters.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/test_unit_switching.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tests/test_utils.py +0 -0
- {nwp500_python-7.3.2 → nwp500_python-7.3.4}/tox.ini +0 -0
|
@@ -2,6 +2,114 @@
|
|
|
2
2
|
Changelog
|
|
3
3
|
=========
|
|
4
4
|
|
|
5
|
+
Version 7.3.4 (2026-01-27)
|
|
6
|
+
==========================
|
|
7
|
+
|
|
8
|
+
Fixed
|
|
9
|
+
-----
|
|
10
|
+
- **Temperature Delta Conversions**: Fixed incorrect Fahrenheit conversion for differential temperature settings (heat pump and heater element on/off thresholds)
|
|
11
|
+
|
|
12
|
+
- Created new ``DeciCelsiusDelta`` class for temperature deltas that apply scale factor (9/5) but NOT the +32 offset
|
|
13
|
+
- Heat pump and heater element differential settings now use ``DeciCelsiusDelta`` instead of ``DeciCelsius``
|
|
14
|
+
- ``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
|
|
15
|
+
- Example: A device value of 5 (representing 0.5°C delta) now correctly converts to 0.9°F delta instead of 32.9°F
|
|
16
|
+
|
|
17
|
+
- **CLI Output**: Added display of heat pump and heater element differential temperature settings in device status output
|
|
18
|
+
|
|
19
|
+
Changed
|
|
20
|
+
-------
|
|
21
|
+
- **Internal API**: Added ``div_10_celsius_delta_to_preferred`` converter for temperature delta values in device models
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
Version 7.3.3 (2026-01-27)
|
|
25
|
+
==========================
|
|
26
|
+
|
|
27
|
+
Breaking Changes
|
|
28
|
+
----------------
|
|
29
|
+
- **Temperature Setpoint Limits**: Replaced hardcoded temperature limits with device-provided values
|
|
30
|
+
|
|
31
|
+
- ``set_dhw_temperature()`` now validates against device-specific ``dhw_temperature_min`` and ``dhw_temperature_max`` instead of hardcoded 95-150°F bounds
|
|
32
|
+
- ``build_reservation_entry()`` changed parameter name from ``temperature_f`` to ``temperature`` (unit-agnostic)
|
|
33
|
+
- Added optional ``temperature_min`` and ``temperature_max`` parameters to ``build_reservation_entry()`` for device-specific limit overrides
|
|
34
|
+
- Temperature parameters now accept values in the user's preferred unit (Celsius or Fahrenheit) based on global unit system context
|
|
35
|
+
- Fixes Home Assistant and other integrations that prefer Celsius unit display
|
|
36
|
+
|
|
37
|
+
**Migration guide:**
|
|
38
|
+
|
|
39
|
+
.. code-block:: python
|
|
40
|
+
|
|
41
|
+
# OLD (hardcoded 95-150°F)
|
|
42
|
+
await mqtt.control.set_dhw_temperature(device, temperature_f=140.0)
|
|
43
|
+
entry = build_reservation_entry(
|
|
44
|
+
enabled=True,
|
|
45
|
+
days=["Monday"],
|
|
46
|
+
hour=6,
|
|
47
|
+
minute=0,
|
|
48
|
+
mode_id=3,
|
|
49
|
+
temperature_f=140.0,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# NEW (device-provided limits, unit-aware)
|
|
53
|
+
# Temperature value automatically uses user's preferred unit
|
|
54
|
+
await mqtt.control.set_dhw_temperature(device, 140.0)
|
|
55
|
+
|
|
56
|
+
# Device features provide min/max in user's preferred unit
|
|
57
|
+
features = await device_info_cache.get(device.device_info.mac_address)
|
|
58
|
+
entry = build_reservation_entry(
|
|
59
|
+
enabled=True,
|
|
60
|
+
days=["Monday"],
|
|
61
|
+
hour=6,
|
|
62
|
+
minute=0,
|
|
63
|
+
mode_id=3,
|
|
64
|
+
temperature=140.0,
|
|
65
|
+
temperature_min=features.dhw_temperature_min,
|
|
66
|
+
temperature_max=features.dhw_temperature_max,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
Added
|
|
70
|
+
-----
|
|
71
|
+
- **Reservation Temperature Conversion**: New ``reservation_param_to_preferred()`` utility function for unit-aware reservation display
|
|
72
|
+
|
|
73
|
+
- Converts device reservation parameters (half-degree Celsius) to user's preferred unit
|
|
74
|
+
- Respects global unit system context (metric/us_customary)
|
|
75
|
+
- Enables proper thermostat/reservation scheduling display in Home Assistant and other integrations
|
|
76
|
+
- Example usage:
|
|
77
|
+
|
|
78
|
+
.. code-block:: python
|
|
79
|
+
|
|
80
|
+
from nwp500 import reservation_param_to_preferred
|
|
81
|
+
|
|
82
|
+
# Display reservation temperature in user's preferred unit
|
|
83
|
+
param = 120 # Device raw value in half-Celsius
|
|
84
|
+
temp = reservation_param_to_preferred(param)
|
|
85
|
+
# Returns: 60.0 (Celsius) or 140.0 (Fahrenheit) based on unit context
|
|
86
|
+
|
|
87
|
+
- **Unit-Aware Temperature Conversion**: New ``preferred_to_half_celsius()`` utility function
|
|
88
|
+
|
|
89
|
+
- Converts temperature from user's preferred unit to half-degree Celsius for device commands
|
|
90
|
+
- Respects global unit system context (metric/us_customary)
|
|
91
|
+
- Replaces misleading ``fahrenheit_to_half_celsius()`` in unit-agnostic code paths
|
|
92
|
+
- Used internally by ``set_dhw_temperature()`` and ``build_reservation_entry()``
|
|
93
|
+
|
|
94
|
+
Changed
|
|
95
|
+
-------
|
|
96
|
+
- **Unit System Agnostic Display**: All logging and user-facing messages now respect global unit system context
|
|
97
|
+
|
|
98
|
+
- Temperature change logs dynamically show °C or °F based on user preference
|
|
99
|
+
- CLI monitoring and temperature setting messages use correct unit suffix
|
|
100
|
+
- Event listener documentation updated with unit-aware examples
|
|
101
|
+
- Reservation schedule examples now use ``reservation_param_to_preferred()`` for proper unit handling
|
|
102
|
+
|
|
103
|
+
Fixed
|
|
104
|
+
-----
|
|
105
|
+
- **Critical: Temperature Unit Bug in Set Operations**: Fixed incorrect temperature conversion when setting DHW temperature and reservations
|
|
106
|
+
|
|
107
|
+
- ``set_dhw_temperature()`` was calling ``fahrenheit_to_half_celsius()`` with unit-agnostic temperature parameter
|
|
108
|
+
- ``build_reservation_entry()`` had the same issue
|
|
109
|
+
- **Impact**: If user preferred Celsius, temperature would be interpreted as Fahrenheit, causing wrong setpoints
|
|
110
|
+
- **Fix**: Use new ``preferred_to_half_celsius()`` that respects unit system context
|
|
111
|
+
- This was a critical data correctness bug that would cause incorrect device behavior for Celsius users
|
|
112
|
+
|
|
5
113
|
Version 7.3.2 (2026-01-25)
|
|
6
114
|
==========================
|
|
7
115
|
|
|
@@ -149,6 +149,14 @@ nwp500.topic\_builder module
|
|
|
149
149
|
:show-inheritance:
|
|
150
150
|
:undoc-members:
|
|
151
151
|
|
|
152
|
+
nwp500.unit\_system module
|
|
153
|
+
--------------------------
|
|
154
|
+
|
|
155
|
+
.. automodule:: nwp500.unit_system
|
|
156
|
+
:members:
|
|
157
|
+
:show-inheritance:
|
|
158
|
+
:undoc-members:
|
|
159
|
+
|
|
152
160
|
nwp500.utils module
|
|
153
161
|
-------------------
|
|
154
162
|
|
|
@@ -44,14 +44,14 @@ Here's a simple example that sets up a weekday morning reservation:
|
|
|
44
44
|
device = await api.get_first_device()
|
|
45
45
|
|
|
46
46
|
# Build reservation entry
|
|
47
|
-
weekday_morning =
|
|
47
|
+
weekday_morning = build_reservation_entry(
|
|
48
48
|
enabled=True,
|
|
49
49
|
days=["Monday", "Tuesday", "Wednesday", "Thursday",
|
|
50
50
|
"Friday"],
|
|
51
51
|
hour=6,
|
|
52
52
|
minute=30,
|
|
53
53
|
mode_id=4, # High Demand
|
|
54
|
-
|
|
54
|
+
temperature=140.0 # Temperature in user's preferred unit
|
|
55
55
|
)
|
|
56
56
|
|
|
57
57
|
# Send to device
|
|
@@ -149,8 +149,8 @@ Field Descriptions
|
|
|
149
149
|
(e.g., ``98`` for 120°F) for consistency.
|
|
150
150
|
|
|
151
151
|
**Note:** When using ``build_reservation_entry()``, you don't need to
|
|
152
|
-
calculate the param value manually - just pass ``
|
|
153
|
-
|
|
152
|
+
calculate the param value manually - just pass ``temperature`` in
|
|
153
|
+
your user's preferred unit and the conversion is handled automatically.
|
|
154
154
|
|
|
155
155
|
Helper Functions
|
|
156
156
|
================
|
|
@@ -161,33 +161,33 @@ Building Reservation Entries
|
|
|
161
161
|
-----------------------------
|
|
162
162
|
|
|
163
163
|
Use ``build_reservation_entry()`` to create properly formatted entries.
|
|
164
|
-
The function accepts temperature in
|
|
164
|
+
The function accepts temperature in your user's preferred unit and handles the conversion
|
|
165
165
|
to the device's internal format automatically:
|
|
166
166
|
|
|
167
167
|
.. code-block:: python
|
|
168
168
|
|
|
169
169
|
from nwp500 import build_reservation_entry
|
|
170
170
|
|
|
171
|
-
# Weekday morning - High Demand mode at 140°F
|
|
171
|
+
# Weekday morning - High Demand mode at 140 (°F or °C based on unit preference)
|
|
172
172
|
entry = build_reservation_entry(
|
|
173
173
|
enabled=True,
|
|
174
174
|
days=["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
|
175
175
|
hour=6,
|
|
176
176
|
minute=30,
|
|
177
177
|
mode_id=4, # High Demand
|
|
178
|
-
|
|
178
|
+
temperature=140.0 # Temperature in user's preferred unit
|
|
179
179
|
)
|
|
180
180
|
# Returns: {'enable': 1, 'week': 62, 'hour': 6, 'min': 30,
|
|
181
181
|
# 'mode': 4, 'param': 120}
|
|
182
182
|
|
|
183
|
-
# Weekend - Energy Saver mode at 120°F
|
|
183
|
+
# Weekend - Energy Saver mode at 120 (°F or °C)
|
|
184
184
|
entry2 = build_reservation_entry(
|
|
185
185
|
enabled=True,
|
|
186
186
|
days=["Saturday", "Sunday"],
|
|
187
187
|
hour=8,
|
|
188
188
|
minute=0,
|
|
189
189
|
mode_id=3, # Energy Saver
|
|
190
|
-
|
|
190
|
+
temperature=120.0
|
|
191
191
|
)
|
|
192
192
|
|
|
193
193
|
# You can also use day indices (0=Sunday, 6=Saturday)
|
|
@@ -197,7 +197,7 @@ to the device's internal format automatically:
|
|
|
197
197
|
hour=18,
|
|
198
198
|
minute=0,
|
|
199
199
|
mode_id=1, # Heat Pump Only
|
|
200
|
-
|
|
200
|
+
temperature=130.0
|
|
201
201
|
)
|
|
202
202
|
|
|
203
203
|
Temperature Conversion Utility
|
|
@@ -269,7 +269,7 @@ Send a new reservation schedule to the device:
|
|
|
269
269
|
|
|
270
270
|
# Build multiple reservation entries
|
|
271
271
|
reservations = [
|
|
272
|
-
# Weekday morning: High Demand at 140
|
|
272
|
+
# Weekday morning: High Demand at 140 (user's preferred unit)
|
|
273
273
|
build_reservation_entry(
|
|
274
274
|
enabled=True,
|
|
275
275
|
days=["Monday", "Tuesday", "Wednesday", "Thursday",
|
|
@@ -277,9 +277,9 @@ Send a new reservation schedule to the device:
|
|
|
277
277
|
hour=6,
|
|
278
278
|
minute=30,
|
|
279
279
|
mode_id=4,
|
|
280
|
-
|
|
280
|
+
temperature=140.0
|
|
281
281
|
),
|
|
282
|
-
# Weekday evening: Energy Saver at 130
|
|
282
|
+
# Weekday evening: Energy Saver at 130 (user's preferred unit)
|
|
283
283
|
build_reservation_entry(
|
|
284
284
|
enabled=True,
|
|
285
285
|
days=["Monday", "Tuesday", "Wednesday", "Thursday",
|
|
@@ -287,16 +287,16 @@ Send a new reservation schedule to the device:
|
|
|
287
287
|
hour=18,
|
|
288
288
|
minute=0,
|
|
289
289
|
mode_id=3,
|
|
290
|
-
|
|
290
|
+
temperature=130.0
|
|
291
291
|
),
|
|
292
|
-
# Weekend: Heat Pump Only at 120
|
|
292
|
+
# Weekend: Heat Pump Only at 120 (user's preferred unit)
|
|
293
293
|
build_reservation_entry(
|
|
294
294
|
enabled=True,
|
|
295
295
|
days=["Saturday", "Sunday"],
|
|
296
296
|
hour=8,
|
|
297
297
|
minute=0,
|
|
298
298
|
mode_id=1,
|
|
299
|
-
|
|
299
|
+
temperature=120.0
|
|
300
300
|
),
|
|
301
301
|
]
|
|
302
302
|
|
|
@@ -439,7 +439,7 @@ Different settings for work days and weekends:
|
|
|
439
439
|
hour=5,
|
|
440
440
|
minute=30,
|
|
441
441
|
mode_id=4, # High Demand
|
|
442
|
-
|
|
442
|
+
temperature=140.0
|
|
443
443
|
),
|
|
444
444
|
# Weekend morning: later start, energy saver
|
|
445
445
|
build_reservation_entry(
|
|
@@ -448,7 +448,7 @@ Different settings for work days and weekends:
|
|
|
448
448
|
hour=8,
|
|
449
449
|
minute=0,
|
|
450
450
|
mode_id=3, # Energy Saver
|
|
451
|
-
|
|
451
|
+
temperature=130.0
|
|
452
452
|
),
|
|
453
453
|
]
|
|
454
454
|
|
|
@@ -467,7 +467,7 @@ Minimize energy use during peak hours:
|
|
|
467
467
|
hour=6,
|
|
468
468
|
minute=0,
|
|
469
469
|
mode_id=4,
|
|
470
|
-
|
|
470
|
+
temperature=140.0
|
|
471
471
|
),
|
|
472
472
|
# Day: 9:00 AM - Switch to Energy Saver
|
|
473
473
|
build_reservation_entry(
|
|
@@ -476,7 +476,7 @@ Minimize energy use during peak hours:
|
|
|
476
476
|
hour=9,
|
|
477
477
|
minute=0,
|
|
478
478
|
mode_id=3,
|
|
479
|
-
|
|
479
|
+
temperature=120.0
|
|
480
480
|
),
|
|
481
481
|
# Evening: 5:00 PM - Heat Pump Only (before peak pricing)
|
|
482
482
|
build_reservation_entry(
|
|
@@ -485,7 +485,7 @@ Minimize energy use during peak hours:
|
|
|
485
485
|
hour=17,
|
|
486
486
|
minute=0,
|
|
487
487
|
mode_id=1,
|
|
488
|
-
|
|
488
|
+
temperature=130.0
|
|
489
489
|
),
|
|
490
490
|
# Night: 10:00 PM - Back to Energy Saver
|
|
491
491
|
build_reservation_entry(
|
|
@@ -494,7 +494,7 @@ Minimize energy use during peak hours:
|
|
|
494
494
|
hour=22,
|
|
495
495
|
minute=0,
|
|
496
496
|
mode_id=3,
|
|
497
|
-
|
|
497
|
+
temperature=120.0
|
|
498
498
|
),
|
|
499
499
|
]
|
|
500
500
|
|
|
@@ -512,7 +512,7 @@ Automatically enable vacation mode during a trip:
|
|
|
512
512
|
hour=20,
|
|
513
513
|
minute=0,
|
|
514
514
|
mode_id=5, # Vacation Mode
|
|
515
|
-
|
|
515
|
+
temperature=120.0 # Temperature doesn't matter for vacation mode
|
|
516
516
|
)
|
|
517
517
|
|
|
518
518
|
# Return to normal operation when you get back
|
|
@@ -522,7 +522,7 @@ Automatically enable vacation mode during a trip:
|
|
|
522
522
|
hour=14,
|
|
523
523
|
minute=0,
|
|
524
524
|
mode_id=3, # Energy Saver
|
|
525
|
-
|
|
525
|
+
temperature=130.0
|
|
526
526
|
)
|
|
527
527
|
|
|
528
528
|
reservations = [start_vacation, end_vacation]
|
|
@@ -533,11 +533,12 @@ Important Notes
|
|
|
533
533
|
Temperature Conversion
|
|
534
534
|
-----------------------
|
|
535
535
|
|
|
536
|
-
When using ``build_reservation_entry()``, pass temperatures in
|
|
537
|
-
using the ``
|
|
538
|
-
to the device's internal format
|
|
536
|
+
When using ``build_reservation_entry()``, pass temperatures in your user's
|
|
537
|
+
preferred unit (Celsius or Fahrenheit) using the ``temperature`` parameter.
|
|
538
|
+
The function automatically converts to the device's internal format
|
|
539
|
+
(half-degrees Celsius).
|
|
539
540
|
|
|
540
|
-
The valid temperature range is 95°F to 150°F.
|
|
541
|
+
The valid temperature range is 35°C to 65.5°C (95°F to 150°F).
|
|
541
542
|
|
|
542
543
|
For reading reservation responses from the device, the ``param`` field
|
|
543
544
|
contains the raw half-degrees Celsius value. Convert to Fahrenheit with:
|
|
@@ -619,7 +620,7 @@ Full working example with error handling and response monitoring:
|
|
|
619
620
|
hour=6,
|
|
620
621
|
minute=30,
|
|
621
622
|
mode_id=4, # High Demand
|
|
622
|
-
|
|
623
|
+
temperature=140.0
|
|
623
624
|
),
|
|
624
625
|
# Weekday day
|
|
625
626
|
build_reservation_entry(
|
|
@@ -629,7 +630,7 @@ Full working example with error handling and response monitoring:
|
|
|
629
630
|
hour=9,
|
|
630
631
|
minute=0,
|
|
631
632
|
mode_id=3, # Energy Saver
|
|
632
|
-
|
|
633
|
+
temperature=120.0
|
|
633
634
|
),
|
|
634
635
|
# Weekend morning
|
|
635
636
|
build_reservation_entry(
|
|
@@ -638,7 +639,7 @@ Full working example with error handling and response monitoring:
|
|
|
638
639
|
hour=8,
|
|
639
640
|
minute=0,
|
|
640
641
|
mode_id=3, # Energy Saver
|
|
641
|
-
|
|
642
|
+
temperature=130.0
|
|
642
643
|
),
|
|
643
644
|
]
|
|
644
645
|
|
|
@@ -34,9 +34,17 @@ The device uses several encoding schemes to minimize transmission overhead:
|
|
|
34
34
|
- Applied to decimal precision values
|
|
35
35
|
- Formula: ``displayed_value = raw_value / 10.0``
|
|
36
36
|
- Purpose: Preserve decimal precision in integer storage
|
|
37
|
-
- Common for flow rates
|
|
37
|
+
- Common for flow rates
|
|
38
38
|
- Example: Raw 125 → 12.5 GPM
|
|
39
39
|
|
|
40
|
+
3.5. **Temperature Delta (Decicelsius)** (div_10_celsius_delta)
|
|
41
|
+
- Applied to differential temperature settings (heat pump and element hysteresis)
|
|
42
|
+
- Formula: ``displayed_value_celsius = raw_value / 10.0``, ``displayed_value_fahrenheit = (raw_value / 10.0) * 9/5`` (NO +32 offset)
|
|
43
|
+
- Purpose: Represents temperature DIFFERENCES/DELTAS, not absolute temperatures
|
|
44
|
+
- Key difference from absolute temperature conversion: No +32 offset applied when converting to Fahrenheit
|
|
45
|
+
- Example: Raw 5 → 0.5°C delta → 0.9°F delta (NOT 32.9°F)
|
|
46
|
+
- Used for: Heat pump on/off differential, heating element on/off differential
|
|
47
|
+
|
|
40
48
|
4. **Boolean Encoding** (device_bool)
|
|
41
49
|
- Applied to all status flags
|
|
42
50
|
- Formula: ``displayed_value = (raw_value == 2)``
|
|
@@ -181,21 +189,21 @@ Electric heating elements are controlled via thermostat ranges. Two sensors (upp
|
|
|
181
189
|
- °F
|
|
182
190
|
- **Lower element OFF threshold**. Lower tank temp rises above this to deactivate lower element.
|
|
183
191
|
* - ``heUpperOnDiffTempSetting``
|
|
184
|
-
-
|
|
192
|
+
- div_10_celsius_delta
|
|
185
193
|
- °F
|
|
186
|
-
- **Upper element differential** (ON-OFF
|
|
194
|
+
- **Upper element differential** (ON-OFF hysteresis width). Temperature delta to prevent rapid cycling. Typically 2-5°F. This is a DELTA value, not an absolute temperature (0 delta = 0°F difference).
|
|
187
195
|
* - ``heUpperOffDiffTempSetting``
|
|
188
|
-
-
|
|
196
|
+
- div_10_celsius_delta
|
|
189
197
|
- °F
|
|
190
|
-
- **Upper element differential**
|
|
198
|
+
- **Upper element OFF differential** (advanced tuning). May vary based on mode. DELTA value.
|
|
191
199
|
* - ``heLowerOnDiffTempSetting``
|
|
192
|
-
-
|
|
200
|
+
- div_10_celsius_delta
|
|
193
201
|
- °F
|
|
194
|
-
- **Lower element differential** (ON-OFF
|
|
202
|
+
- **Lower element differential** (ON-OFF hysteresis width). DELTA value.
|
|
195
203
|
* - ``heLowerOffDiffTempSetting``
|
|
196
|
-
-
|
|
204
|
+
- div_10_celsius_delta
|
|
197
205
|
- °F
|
|
198
|
-
- **Lower element differential** variation.
|
|
206
|
+
- **Lower element OFF differential** variation. DELTA value.
|
|
199
207
|
* - ``heatMinOpTemperature``
|
|
200
208
|
- HalfCelsiusToF
|
|
201
209
|
- °F
|
|
@@ -231,21 +239,21 @@ Heat pump stages are similarly controlled via thermostat ranges:
|
|
|
231
239
|
- °F
|
|
232
240
|
- **Lower heat pump OFF**. Lower tank rises above this to stop lower tank heat pump operation.
|
|
233
241
|
* - ``hpUpperOnDiffTempSetting``
|
|
234
|
-
-
|
|
242
|
+
- div_10_celsius_delta
|
|
235
243
|
- °F
|
|
236
|
-
- **Heat pump upper differential** (ON-OFF hysteresis).
|
|
244
|
+
- **Heat pump upper differential** (ON-OFF hysteresis). Temperature delta to prevent rapid cycling. DELTA value.
|
|
237
245
|
* - ``hpUpperOffDiffTempSetting``
|
|
238
|
-
-
|
|
246
|
+
- div_10_celsius_delta
|
|
239
247
|
- °F
|
|
240
|
-
- **Heat pump upper differential** variation.
|
|
248
|
+
- **Heat pump upper OFF differential** variation. DELTA value.
|
|
241
249
|
* - ``hpLowerOnDiffTempSetting``
|
|
242
|
-
-
|
|
250
|
+
- div_10_celsius_delta
|
|
243
251
|
- °F
|
|
244
|
-
- **Heat pump lower differential**.
|
|
252
|
+
- **Heat pump lower ON differential**. DELTA value.
|
|
245
253
|
* - ``hpLowerOffDiffTempSetting``
|
|
246
|
-
-
|
|
254
|
+
- div_10_celsius_delta
|
|
247
255
|
- °F
|
|
248
|
-
- **Heat pump lower differential** variation.
|
|
256
|
+
- **Heat pump lower OFF differential** variation. DELTA value.
|
|
249
257
|
|
|
250
258
|
Freeze Protection Temperatures
|
|
251
259
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
@@ -422,7 +422,7 @@ DHW Temperature
|
|
|
422
422
|
Temperature values are encoded in **half-degrees Celsius**.
|
|
423
423
|
Use formula: ``fahrenheit = (param / 2.0) * 9/5 + 32``
|
|
424
424
|
For 140°F, send ``param=120`` (which is 60°C × 2).
|
|
425
|
-
Valid range:
|
|
425
|
+
Valid range: Device-specific (see device features for ``dhw_temperature_min`` and ``dhw_temperature_max``).
|
|
426
426
|
|
|
427
427
|
Anti-Legionella
|
|
428
428
|
---------------
|
|
@@ -220,7 +220,7 @@ Temperature Control
|
|
|
220
220
|
set_dhw_temperature()
|
|
221
221
|
^^^^^^^^^^^^^^^^^^^^^
|
|
222
222
|
|
|
223
|
-
.. py:method:: set_dhw_temperature(device,
|
|
223
|
+
.. py:method:: set_dhw_temperature(device, temperature)
|
|
224
224
|
|
|
225
225
|
Set DHW target temperature.
|
|
226
226
|
|
|
@@ -228,24 +228,25 @@ set_dhw_temperature()
|
|
|
228
228
|
|
|
229
229
|
:param device: Device object
|
|
230
230
|
:type device: Device
|
|
231
|
-
:param
|
|
232
|
-
:type
|
|
231
|
+
:param temperature: Target temperature in user's preferred unit (Celsius or Fahrenheit)
|
|
232
|
+
:type temperature: float
|
|
233
233
|
:return: Publish packet ID
|
|
234
234
|
:rtype: int
|
|
235
|
-
:raises RangeValidationError: If temperature is outside
|
|
235
|
+
:raises RangeValidationError: If temperature is outside valid range
|
|
236
236
|
:raises DeviceCapabilityError: If device doesn't support temperature control
|
|
237
237
|
|
|
238
238
|
The temperature is automatically converted to the device's internal format
|
|
239
|
-
(half-degrees Celsius).
|
|
239
|
+
(half-degrees Celsius). The valid range depends on the device's
|
|
240
|
+
temperature preference and configuration.
|
|
240
241
|
|
|
241
242
|
**Example:**
|
|
242
243
|
|
|
243
244
|
.. code-block:: python
|
|
244
245
|
|
|
245
|
-
# Set temperature
|
|
246
|
+
# Set temperature (interpreted in device's preferred unit)
|
|
246
247
|
await mqtt.control.set_dhw_temperature(device, 140.0)
|
|
247
248
|
|
|
248
|
-
# Common temperatures
|
|
249
|
+
# Common temperatures (device-dependent units)
|
|
249
250
|
await mqtt.control.set_dhw_temperature(device, 120.0) # Standard
|
|
250
251
|
await mqtt.control.set_dhw_temperature(device, 130.0) # Medium
|
|
251
252
|
await mqtt.control.set_dhw_temperature(device, 140.0) # Hot
|
|
@@ -49,8 +49,9 @@ Basic Monitoring
|
|
|
49
49
|
|
|
50
50
|
# Subscribe to status updates
|
|
51
51
|
def on_status(status):
|
|
52
|
-
|
|
53
|
-
print(f"
|
|
52
|
+
unit = status.get_field_unit('dhw_temperature')
|
|
53
|
+
print(f"Water Temp: {status.dhw_temperature}{unit}")
|
|
54
|
+
print(f"Target: {status.dhw_temperature_setting}{unit}")
|
|
54
55
|
print(f"Power: {status.current_inst_power}W")
|
|
55
56
|
print(f"Mode: {status.dhw_operation_setting.name}")
|
|
56
57
|
|
|
@@ -87,7 +88,7 @@ control method reference, capability checking, and advanced features.
|
|
|
87
88
|
# Control operations (with automatic capability checking)
|
|
88
89
|
await mqtt.control.set_power(device, power_on=True)
|
|
89
90
|
await mqtt.control.set_dhw_mode(device, mode_id=3) # Energy Saver
|
|
90
|
-
await mqtt.control.set_dhw_temperature(device, 140.0)
|
|
91
|
+
await mqtt.control.set_dhw_temperature(device, 140.0) # Temperature in user's preferred unit
|
|
91
92
|
|
|
92
93
|
await mqtt.disconnect()
|
|
93
94
|
|
|
@@ -442,29 +443,30 @@ set_dhw_mode()
|
|
|
442
443
|
set_dhw_temperature()
|
|
443
444
|
^^^^^^^^^^^^^^^^^^^^^
|
|
444
445
|
|
|
445
|
-
.. py:method:: set_dhw_temperature(device,
|
|
446
|
+
.. py:method:: set_dhw_temperature(device, temperature)
|
|
446
447
|
|
|
447
448
|
Set target DHW temperature.
|
|
448
449
|
|
|
449
450
|
:param device: Device object
|
|
450
451
|
:type device: Device
|
|
451
|
-
:param
|
|
452
|
-
:type
|
|
452
|
+
:param temperature: Temperature in user's preferred unit (Celsius or Fahrenheit)
|
|
453
|
+
:type temperature: float
|
|
453
454
|
:return: Publish packet ID
|
|
454
455
|
:rtype: int
|
|
455
|
-
:raises RangeValidationError: If temperature is outside
|
|
456
|
+
:raises RangeValidationError: If temperature is outside valid range
|
|
456
457
|
|
|
457
458
|
The temperature is automatically converted to the device's internal
|
|
458
|
-
format (half-degrees Celsius).
|
|
459
|
+
format (half-degrees Celsius). The actual valid range depends on the
|
|
460
|
+
device's temperature preference and configuration.
|
|
459
461
|
|
|
460
462
|
**Example:**
|
|
461
463
|
|
|
462
464
|
.. code-block:: python
|
|
463
465
|
|
|
464
|
-
# Set temperature
|
|
466
|
+
# Set temperature (value interpreted in device's preferred unit)
|
|
465
467
|
await mqtt.control.set_dhw_temperature(device, 140.0)
|
|
466
468
|
|
|
467
|
-
# Common temperatures
|
|
469
|
+
# Common temperatures (device-dependent units)
|
|
468
470
|
await mqtt.control.set_dhw_temperature(device, 120.0) # Standard
|
|
469
471
|
await mqtt.control.set_dhw_temperature(device, 130.0) # Medium
|
|
470
472
|
await mqtt.control.set_dhw_temperature(device, 140.0) # Hot
|
|
@@ -86,9 +86,10 @@ async def main():
|
|
|
86
86
|
# Callback for status updates
|
|
87
87
|
def on_status(status: DeviceStatus):
|
|
88
88
|
counts["status"] += 1
|
|
89
|
+
unit = status.get_field_unit("dhw_temperature")
|
|
89
90
|
print(f"\n📊 Status Update #{counts['status']}")
|
|
90
91
|
print(f" Mode: {status.operation_mode.name}")
|
|
91
|
-
print(f" DHW Temp: {status.dhw_temperature:.1f}
|
|
92
|
+
print(f" DHW Temp: {status.dhw_temperature:.1f}{unit}")
|
|
92
93
|
print(f" DHW Charge: {status.dhw_charge_per:.1f}%")
|
|
93
94
|
print(f" Compressor: {'On' if status.comp_use else 'Off'}")
|
|
94
95
|
|
|
@@ -98,8 +99,9 @@ async def main():
|
|
|
98
99
|
print(f"\n📋 Feature Info #{counts['feature']}")
|
|
99
100
|
print(f" Serial: {feature.controller_serial_number}")
|
|
100
101
|
print(f" FW Version: {feature.controller_sw_version}")
|
|
102
|
+
unit_suffix = feature.get_field_unit("dhw_temperature_min")
|
|
101
103
|
print(
|
|
102
|
-
f" Temp Range: {feature.dhw_temperature_min}-{feature.dhw_temperature_max}
|
|
104
|
+
f" Temp Range: {feature.dhw_temperature_min}-{feature.dhw_temperature_max}{unit_suffix}"
|
|
103
105
|
)
|
|
104
106
|
print(
|
|
105
107
|
f" Heat Pump: {'Yes' if feature.heatpump_use == OnOffFlag.ON else 'No'}"
|
|
@@ -48,8 +48,9 @@ async def demand_response_example():
|
|
|
48
48
|
nonlocal current_status
|
|
49
49
|
current_status = status
|
|
50
50
|
logger.info(f"Current operation mode: {status.operation_mode.name}")
|
|
51
|
+
unit = status.get_field_unit("dhw_target_temperature_setting")
|
|
51
52
|
logger.info(
|
|
52
|
-
f"Current DHW temperature setting: {status.dhw_target_temperature_setting}
|
|
53
|
+
f"Current DHW temperature setting: {status.dhw_target_temperature_setting}{unit}"
|
|
53
54
|
)
|
|
54
55
|
|
|
55
56
|
await mqtt_client.subscribe_device_status(device, on_current_status)
|
|
@@ -138,13 +138,14 @@ async def main():
|
|
|
138
138
|
)
|
|
139
139
|
|
|
140
140
|
print("\nConfiguration:")
|
|
141
|
+
unit_suffix = feature.get_field_unit("dhw_temperature_min")
|
|
141
142
|
print(f" Temperature Unit: {feature.temperature_type.name}")
|
|
142
143
|
print(f" Temp Formula Type: {feature.temp_formula_type}")
|
|
143
144
|
print(
|
|
144
|
-
f" DHW Temp Range: {feature.dhw_temperature_min}
|
|
145
|
+
f" DHW Temp Range: {feature.dhw_temperature_min}{unit_suffix} - {feature.dhw_temperature_max}{unit_suffix}"
|
|
145
146
|
)
|
|
146
147
|
print(
|
|
147
|
-
f" Freeze Prot Range: {feature.freeze_protection_temp_min}
|
|
148
|
+
f" Freeze Prot Range: {feature.freeze_protection_temp_min}{unit_suffix} - {feature.freeze_protection_temp_max}{unit_suffix}"
|
|
148
149
|
)
|
|
149
150
|
|
|
150
151
|
print("\nFeature Support:")
|
|
@@ -129,10 +129,11 @@ async def main():
|
|
|
129
129
|
def on_device_status(status: DeviceStatus):
|
|
130
130
|
"""Parsed status callback."""
|
|
131
131
|
message_count["status"] += 1
|
|
132
|
+
unit = status.get_field_unit("dhw_temperature")
|
|
132
133
|
print(
|
|
133
134
|
f"\n[SUCCESS] PARSED Status Update #{message_count['status']}"
|
|
134
135
|
)
|
|
135
|
-
print(f" DHW Temperature: {status.dhw_temperature:.1f}
|
|
136
|
+
print(f" DHW Temperature: {status.dhw_temperature:.1f}{unit}")
|
|
136
137
|
print(f" Operation Mode: {status.operation_mode.name}")
|
|
137
138
|
print(f" Compressor: {status.comp_use}")
|
|
138
139
|
|
|
@@ -48,7 +48,8 @@ async def power_control_example():
|
|
|
48
48
|
nonlocal current_status
|
|
49
49
|
current_status = status
|
|
50
50
|
logger.info(f"Current operation mode: {status.operation_mode.name}")
|
|
51
|
-
|
|
51
|
+
unit = status.get_field_unit("dhw_temperature")
|
|
52
|
+
logger.info(f"Current DHW temperature: {status.dhw_temperature}{unit}")
|
|
52
53
|
|
|
53
54
|
await mqtt_client.subscribe_device_status(device, on_current_status)
|
|
54
55
|
await mqtt_client.control.request_device_status(device)
|
|
@@ -89,8 +89,9 @@ async def main():
|
|
|
89
89
|
def on_status(status):
|
|
90
90
|
nonlocal status_count
|
|
91
91
|
status_count += 1
|
|
92
|
+
unit = status.get_field_unit("dhw_temperature")
|
|
92
93
|
print(f"\n📊 Status update #{status_count}:")
|
|
93
|
-
print(f" Temperature: {status.dhw_temperature}
|
|
94
|
+
print(f" Temperature: {status.dhw_temperature}{unit}")
|
|
94
95
|
print(f" Connected: {mqtt_client.is_connected}")
|
|
95
96
|
if mqtt_client.is_reconnecting:
|
|
96
97
|
print(f" Reconnecting: attempt {mqtt_client.reconnect_attempts}...")
|