nwp500-python 7.4.10__tar.gz → 8.1.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.
Files changed (210) hide show
  1. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/.github/workflows/ci.yml +4 -4
  2. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/.github/workflows/release.yml +3 -3
  3. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/.readthedocs.yml +1 -1
  4. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/CHANGELOG.rst +198 -2
  5. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/CONTRIBUTING.rst +1 -1
  6. nwp500_python-8.1.0/PKG-INFO +120 -0
  7. nwp500_python-8.1.0/README.rst +78 -0
  8. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/docs/conf.py +1 -1
  9. nwp500_python-7.4.10/docs/guides/advanced_features_explained.rst → nwp500_python-8.1.0/docs/explanation/advanced-features.rst +13 -19
  10. nwp500_python-8.1.0/docs/explanation/architecture.rst +81 -0
  11. nwp500_python-8.1.0/docs/explanation/index.rst +11 -0
  12. nwp500_python-7.4.10/docs/guides/auto_recovery.rst → nwp500_python-8.1.0/docs/how-to/auto-recovery.rst +2 -2
  13. nwp500_python-7.4.10/docs/guides/mqtt_diagnostics.rst → nwp500_python-8.1.0/docs/how-to/diagnose-mqtt.rst +34 -34
  14. nwp500_python-7.4.10/docs/guides/home_assistant_integration.rst → nwp500_python-8.1.0/docs/how-to/home-assistant.rst +6 -7
  15. nwp500_python-8.1.0/docs/how-to/index.rst +20 -0
  16. nwp500_python-8.1.0/docs/how-to/maintenance.rst +119 -0
  17. nwp500_python-7.4.10/docs/guides/unit_conversion.rst → nwp500_python-8.1.0/docs/how-to/manage-units.rst +5 -5
  18. nwp500_python-7.4.10/docs/guides/event_system.rst → nwp500_python-8.1.0/docs/how-to/monitor-status.rst +110 -123
  19. nwp500_python-7.4.10/docs/guides/time_of_use.rst → nwp500_python-8.1.0/docs/how-to/optimize-tou.rst +16 -16
  20. nwp500_python-7.4.10/docs/guides/command_queue.rst → nwp500_python-8.1.0/docs/how-to/queue-commands.rst +13 -16
  21. nwp500_python-7.4.10/docs/guides/scheduling.rst → nwp500_python-8.1.0/docs/how-to/schedule-operation.rst +119 -12
  22. nwp500_python-8.1.0/docs/how-to/track-energy.rst +333 -0
  23. nwp500_python-8.1.0/docs/index.rst +64 -0
  24. {nwp500_python-7.4.10/docs/development → nwp500_python-8.1.0/docs/project}/history.rst +14 -13
  25. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/reference}/configuration.rst +4 -4
  26. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/reference}/enumerations.rst +3 -4
  27. nwp500_python-8.1.0/docs/reference/index.rst +43 -0
  28. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/reference}/installation.rst +11 -7
  29. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/reference}/protocol/data_conversions.rst +6 -6
  30. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/reference}/protocol/device_features.rst +3 -3
  31. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/reference}/protocol/device_status.rst +2 -2
  32. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/reference}/protocol/error_codes.rst +1 -1
  33. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/reference}/protocol/mqtt_protocol.rst +1 -1
  34. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/reference}/protocol/quick_reference.rst +1 -1
  35. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/reference}/python_api/auth_client.rst +4 -4
  36. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/reference}/python_api/cli.rst +3 -3
  37. nwp500_python-8.1.0/docs/reference/python_api/events.rst +287 -0
  38. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/reference}/python_api/exceptions.rst +18 -18
  39. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/reference}/python_api/models.rst +157 -6
  40. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/reference}/python_api/mqtt_client.rst +374 -317
  41. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/docs/requirements.txt +2 -0
  42. nwp500_python-7.4.10/docs/quickstart.rst → nwp500_python-8.1.0/docs/tutorials/getting-started.rst +13 -14
  43. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/air_filter_reset.py +3 -3
  44. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/anti_legionella.py +4 -4
  45. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/combined_callbacks.py +3 -3
  46. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/demand_response.py +3 -3
  47. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/device_capabilities.py +2 -2
  48. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/device_status_debug.py +2 -2
  49. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/energy_analytics.py +1 -1
  50. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/firmware_payload_capture.py +4 -4
  51. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/mqtt_diagnostics.py +11 -13
  52. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/power_control.py +3 -3
  53. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/recirculation_control.py +4 -6
  54. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/reconnection_demo.py +7 -7
  55. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/reservation_schedule.py +2 -2
  56. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/token_restoration.py +1 -1
  57. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/tou_openei.py +1 -1
  58. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/tou_schedule.py +5 -5
  59. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/water_reservation.py +2 -2
  60. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/beginner/04_set_temperature.py +2 -2
  61. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/intermediate/advanced_auth_patterns.py +1 -1
  62. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/intermediate/command_queue.py +8 -8
  63. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/intermediate/device_status_callback.py +2 -2
  64. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/intermediate/error_handling.py +2 -2
  65. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/intermediate/event_driven_control.py +30 -33
  66. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/intermediate/improved_auth.py +1 -1
  67. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/intermediate/mqtt_realtime_monitoring.py +3 -3
  68. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/intermediate/periodic_requests.py +4 -4
  69. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/intermediate/set_mode.py +2 -2
  70. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/intermediate/vacation_mode.py +2 -2
  71. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/testing/periodic_device_info.py +2 -2
  72. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/testing/test_mqtt_messaging.py +3 -3
  73. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/pyproject.toml +3 -3
  74. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/scripts/bump_version.py +77 -0
  75. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/setup.cfg +3 -3
  76. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/__init__.py +16 -0
  77. nwp500_python-8.1.0/src/nwp500/_base.py +78 -0
  78. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/api_client.py +4 -7
  79. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/auth.py +40 -69
  80. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/cli/__init__.py +2 -0
  81. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/cli/__main__.py +3 -1
  82. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/cli/commands.py +2 -0
  83. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/cli/handlers.py +31 -30
  84. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/cli/monitoring.py +3 -3
  85. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/cli/output_formatters.py +2 -0
  86. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/cli/rich_output.py +2 -0
  87. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/cli/token_storage.py +4 -2
  88. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/command_decorators.py +2 -0
  89. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/config.py +3 -0
  90. nwp500_python-8.1.0/src/nwp500/converters.py +191 -0
  91. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/device_capabilities.py +6 -4
  92. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/device_info_cache.py +22 -17
  93. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/encoding.py +32 -8
  94. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/enums.py +2 -0
  95. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/events.py +16 -9
  96. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/exceptions.py +5 -3
  97. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/factory.py +2 -0
  98. nwp500_python-8.1.0/src/nwp500/models/__init__.py +96 -0
  99. nwp500_python-8.1.0/src/nwp500/models/_converters.py +77 -0
  100. nwp500_python-8.1.0/src/nwp500/models/device.py +59 -0
  101. nwp500_python-8.1.0/src/nwp500/models/energy.py +78 -0
  102. nwp500_python-8.1.0/src/nwp500/models/feature.py +411 -0
  103. nwp500_python-8.1.0/src/nwp500/models/mqtt_models.py +33 -0
  104. nwp500_python-8.1.0/src/nwp500/models/schedule.py +338 -0
  105. nwp500_python-8.1.0/src/nwp500/models/status.py +927 -0
  106. nwp500_python-8.1.0/src/nwp500/models/tou.py +162 -0
  107. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/mqtt/__init__.py +2 -0
  108. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/mqtt/client.py +409 -51
  109. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/mqtt/connection.py +54 -8
  110. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/mqtt/control.py +201 -20
  111. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/mqtt/diagnostics.py +6 -1
  112. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/mqtt/periodic.py +6 -0
  113. nwp500_python-8.1.0/src/nwp500/mqtt/state_tracker.py +162 -0
  114. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/mqtt/subscriptions.py +334 -138
  115. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/mqtt/utils.py +54 -1
  116. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/mqtt_events.py +55 -31
  117. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/reservations.py +15 -37
  118. nwp500_python-8.1.0/src/nwp500/topic_builder.py +70 -0
  119. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/utils.py +2 -0
  120. nwp500_python-8.1.0/src/nwp500_python.egg-info/PKG-INFO +120 -0
  121. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500_python.egg-info/SOURCES.txt +53 -37
  122. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500_python.egg-info/requires.txt +1 -1
  123. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_auth.py +22 -22
  124. nwp500_python-8.1.0/tests/test_bug_fixes.py +198 -0
  125. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_cli_commands.py +69 -13
  126. nwp500_python-8.1.0/tests/test_mqtt_reconnection.py +130 -0
  127. nwp500_python-8.1.0/tests/test_multi_device.py +243 -0
  128. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_reservations.py +40 -42
  129. nwp500_python-7.4.10/PKG-INFO +0 -328
  130. nwp500_python-7.4.10/README.rst +0 -286
  131. nwp500_python-7.4.10/docs/api/nwp500.rst +0 -182
  132. nwp500_python-7.4.10/docs/guides/energy_monitoring.rst +0 -339
  133. nwp500_python-7.4.10/docs/index.rst +0 -161
  134. nwp500_python-7.4.10/docs/python_api/device_control.rst +0 -1188
  135. nwp500_python-7.4.10/docs/python_api/events.rst +0 -358
  136. nwp500_python-7.4.10/src/nwp500/converters.py +0 -543
  137. nwp500_python-7.4.10/src/nwp500/models.py +0 -1453
  138. nwp500_python-7.4.10/src/nwp500/topic_builder.py +0 -40
  139. nwp500_python-7.4.10/src/nwp500_python.egg-info/PKG-INFO +0 -328
  140. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/.coveragerc +0 -0
  141. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/.github/RESOLVING_PR_COMMENTS.md +0 -0
  142. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/.github/copilot-instructions.md +0 -0
  143. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/.gitignore +0 -0
  144. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/.pre-commit-config.yaml +0 -0
  145. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/AUTHORS.rst +0 -0
  146. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/LICENSE.txt +0 -0
  147. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/Makefile +0 -0
  148. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/RELEASE.md +0 -0
  149. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/docs/Makefile +0 -0
  150. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/docs/_static/.gitignore +0 -0
  151. /nwp500_python-7.4.10/docs/guides/authentication.rst → /nwp500_python-8.1.0/docs/how-to/authenticate.rst +0 -0
  152. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/docs/openapi.yaml +0 -0
  153. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/project}/authors.rst +0 -0
  154. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/project}/changelog.rst +0 -0
  155. {nwp500_python-7.4.10/docs/development → nwp500_python-8.1.0/docs/project}/contributing.rst +0 -0
  156. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/project}/license.rst +0 -0
  157. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/reference}/protocol/rest_api.rst +0 -0
  158. {nwp500_python-7.4.10/docs → nwp500_python-8.1.0/docs/reference}/python_api/api_client.rst +0 -0
  159. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/.ruff.toml +0 -0
  160. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/README.md +0 -0
  161. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/auto_recovery.py +0 -0
  162. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/error_code_demo.py +0 -0
  163. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/advanced/simple_auto_recovery.py +0 -0
  164. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/beginner/01_authentication.py +0 -0
  165. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/beginner/02_list_devices.py +0 -0
  166. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/beginner/03_get_status.py +0 -0
  167. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/intermediate/legacy_auth_constructor.py +0 -0
  168. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/mask.py +0 -0
  169. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/testing/simple_periodic_info.py +0 -0
  170. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/testing/test_api_client.py +0 -0
  171. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/testing/test_mqtt_connection.py +0 -0
  172. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/examples/testing/test_periodic_minimal.py +0 -0
  173. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/scripts/README.md +0 -0
  174. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/scripts/diagnose_mqtt_connection.py +0 -0
  175. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/scripts/extract_changelog.py +0 -0
  176. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/scripts/format.py +0 -0
  177. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/scripts/lint.py +0 -0
  178. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/scripts/setup-dev.py +0 -0
  179. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/scripts/validate_version.py +0 -0
  180. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/setup.py +0 -0
  181. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/field_factory.py +0 -0
  182. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/mqtt/command_queue.py +0 -0
  183. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/mqtt/reconnection.py +0 -0
  184. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/openei.py +0 -0
  185. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/py.typed +0 -0
  186. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/temperature.py +0 -0
  187. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500/unit_system.py +0 -0
  188. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500_python.egg-info/dependency_links.txt +0 -0
  189. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500_python.egg-info/entry_points.txt +0 -0
  190. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500_python.egg-info/not-zip-safe +0 -0
  191. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/src/nwp500_python.egg-info/top_level.txt +0 -0
  192. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/conftest.py +0 -0
  193. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_api_helpers.py +0 -0
  194. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_cli_basic.py +0 -0
  195. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_command_decorators.py +0 -0
  196. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_command_queue.py +0 -0
  197. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_device_capabilities.py +0 -0
  198. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_device_info_cache.py +0 -0
  199. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_events.py +0 -0
  200. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_exceptions.py +0 -0
  201. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_model_converters.py +0 -0
  202. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_models.py +0 -0
  203. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_mqtt_client_init.py +0 -0
  204. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_mqtt_hypothesis.py +0 -0
  205. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_openei.py +0 -0
  206. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_temperature_converters.py +0 -0
  207. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_tou_api.py +0 -0
  208. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_unit_switching.py +0 -0
  209. {nwp500_python-7.4.10 → nwp500_python-8.1.0}/tests/test_utils.py +0 -0
  210. {nwp500_python-7.4.10 → nwp500_python-8.1.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.13'
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.13'
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.13', '3.14']
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.13'
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.13'
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.10'
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.10'
83
+ python-version: '3.14'
84
84
 
85
85
  - name: Extract changelog for this version
86
86
  id: changelog
@@ -19,7 +19,7 @@ formats:
19
19
  build:
20
20
  os: ubuntu-22.04
21
21
  tools:
22
- python: "3.13"
22
+ python: "3.14"
23
23
 
24
24
  python:
25
25
  install:
@@ -2,6 +2,202 @@
2
2
  Changelog
3
3
  =========
4
4
 
5
+ Unreleased
6
+ ==========
7
+
8
+ Version 8.1.0 (2026-05-16)
9
+ ==========================
10
+
11
+ Bug Fixes
12
+ ---------
13
+ - **Fix MQTT connection flapping after reconnect**: When ``_active_reconnect()``
14
+ created a new ``MqttConnection``, the old connection was never closed. The old
15
+ SDK connection's built-in auto-reconnect would eventually succeed, creating two
16
+ active connections sharing the same client ID. Because AWS IoT allows only one
17
+ connection per client ID, the broker would kick one off, triggering
18
+ ``on_connection_interrupted`` and starting yet another reconnection — an
19
+ infinite connect/disconnect loop. Fixed by adding ``MqttConnection.close()``
20
+ (unconditional teardown regardless of ``_connected`` state) and calling it
21
+ before creating the replacement connection in both ``_active_reconnect()`` and
22
+ ``_deep_reconnect()``.
23
+
24
+ - **Thread-safety race in ``ensure_device_info_cached``**: The ``future.done()``
25
+ check and ``future.set_result()`` were performed in the AWS SDK callback thread
26
+ without synchronisation, creating a race against the asyncio event loop thread.
27
+ Moved both operations inside a ``call_soon_threadsafe`` callback so they execute
28
+ atomically on the event loop thread.
29
+
30
+ - **ZeroDivisionError when ``deep_reconnect_threshold`` is 0**: Config validation
31
+ now clamps ``deep_reconnect_threshold`` to a minimum of 1, preventing a
32
+ ``ZeroDivisionError`` in the exponential-backoff reconnection logic.
33
+
34
+ - **Reconnect counter never incremented**: ``total_reconnect_attempts`` in
35
+ diagnostics was not incremented on connection drops, so it always reported 0
36
+ despite active reconnections. Counter is now incremented on each
37
+ ``on_connection_interrupted`` event.
38
+
39
+ - **``shortest_session_seconds`` not JSON-serialisable**: The diagnostics
40
+ ``to_dict()`` method used ``float('inf')`` as the initial value for
41
+ ``shortest_session_seconds``, which is not valid JSON. Changed to ``None``
42
+ so serialisation succeeds when no session has completed yet.
43
+
44
+ - **``wait_for()`` future not bound to running loop**: ``wait_for()`` created a
45
+ bare ``asyncio.Future()`` rather than
46
+ ``asyncio.get_running_loop().create_future()``, which could bind the future to
47
+ a different loop in multi-loop test setups.
48
+
49
+ - **Reservation temperature validation was US-only**: ``build_reservation_entry``
50
+ validated set-point temperatures against hardcoded Fahrenheit bounds (95–150 °F)
51
+ regardless of the active unit system. Validation now uses the current unit system
52
+ context: 35–65 °C in metric mode, 95–150 °F in US mode. Celsius users previously
53
+ received spurious ``ValueError`` rejections for valid temperatures.
54
+
55
+ - **Malformed reservation data silently dropped**: ``build_reservation_entry`` now
56
+ logs a warning when reservation hex data contains unexpected trailing bytes
57
+ instead of silently dropping partial entries.
58
+
59
+ - **Unknown ``PeriodicRequestType`` silently ignored**: The periodic-request handler
60
+ now logs an error and breaks when it encounters an unknown request type instead of
61
+ doing nothing.
62
+
63
+ - **Memory leak in device info cache**: ``get_all_cached()`` only filtered expired
64
+ entries from its return value but left them in the cache dictionary. Expired
65
+ entries are now evicted during ``get_all_cached()`` to prevent unbounded growth.
66
+
67
+ Version 8.0.0 (2026-05-13)
68
+ ===========================
69
+
70
+ Bug Fixes
71
+ ---------
72
+ - **Fix MQTT reconnection after unexpected AWS hangup**: The
73
+ ``on_connection_resumed`` callback was missing the ``connection`` parameter
74
+ required by the AWS IoT SDK callback signature. The SDK calls
75
+ ``on_connection_resumed(connection, return_code, session_present, **kwargs)``,
76
+ but the handler only accepted ``(return_code, session_present)``. The
77
+ mismatched signature caused the callback to fail silently (exception swallowed
78
+ by the AWS CRT C layer), so ``self._connected`` was never restored to ``True``
79
+ after an ``AWS_ERROR_MQTT_UNEXPECTED_HANGUP``. As a result, the
80
+ ``connection_resumed`` event was never emitted, the reconnection loop ran
81
+ indefinitely, and device sensors became permanently unavailable until a manual
82
+ restart. (`#85 <https://github.com/eman/nwp500-python/issues/85>`_)
83
+
84
+ Features
85
+ --------
86
+ - **Multi-device support enhancements**: Improved support for accounts with multiple
87
+ Navilink devices by injecting device identity into models and events.
88
+
89
+ - Added ``mac_address`` field to ``DeviceStatus`` and ``DeviceFeature`` models.
90
+ - Added ``device_mac`` attribute to all device-specific MQTT events (temperature
91
+ changes, mode changes, power updates, errors, etc.).
92
+ - Updated ``DeviceStateTracker`` and ``MqttSubscriptionManager`` to propagate
93
+ device identity correctly.
94
+
95
+ **BREAKING CHANGES**: ``.on()`` event handler callbacks now receive a single typed
96
+ event dataclass instead of positional arguments. ``MqttDeviceController`` is no longer
97
+ accessible as ``.control`` on ``NavienMqttClient``; all control methods are now
98
+ available directly on the client.
99
+
100
+ Breaking Changes
101
+ ----------------
102
+ - **Typed event payloads**: All ``.on()`` event handler callbacks now receive a single
103
+ typed event dataclass instance. The dataclasses are exported from
104
+ ``nwp500.mqtt_events``.
105
+
106
+ .. code-block:: python
107
+
108
+ # OLD (removed)
109
+ mqtt.on("temperature_changed", lambda old, new: print(old, new))
110
+ mqtt.on("connection_resumed", lambda rc, sp: print(rc, sp))
111
+
112
+ # NEW
113
+ mqtt.on("temperature_changed", lambda e: print(e.old_temperature, e.new_temperature))
114
+ mqtt.on("connection_resumed", lambda e: print(e.return_code, e.session_present))
115
+
116
+ - **``MqttDeviceController`` no longer public**: ``NavienMqttClient`` no longer exposes
117
+ a ``.control`` attribute. All control methods are now available directly on the
118
+ client.
119
+
120
+ .. code-block:: python
121
+
122
+ # OLD (removed)
123
+ await mqtt.control.set_temperature(device, 50)
124
+
125
+ # NEW
126
+ await mqtt.set_temperature(device, 50)
127
+
128
+ Migration Guide (from 7.x.x)
129
+ ----------------------------
130
+ The following steps are recommended for a smooth migration, particularly for complex
131
+ integrations like Home Assistant:
132
+
133
+ 1. **Update Event Listeners**: Locate all ``mqtt.on()`` or ``mqtt.once()`` calls.
134
+ Update the callback signatures to accept a single argument (the event object) and
135
+ update the body to access fields via the object (e.g., ``event.new_temperature``
136
+ instead of ``new_val``).
137
+ 2. **Refactor Control Calls**: Remove ``.control`` from all device command invocations.
138
+ Instead of ``await mqtt.control.set_power(...)``, use ``await mqtt.set_power(...)``.
139
+ 3. **Handle Unit Conversions**: If your integration previously performed its own
140
+ conversions or relied on the library's eager conversion, note that
141
+ ``DeviceStatus`` fields like ``dhw_temperature`` are now properties. They return
142
+ values based on the global unit system context (``us_customary`` by default).
143
+
144
+ * **Home Assistant Tip**: To ensure your state tracking is immune to unit system
145
+ toggles within the library, use the new ``*_raw`` fields (e.g.,
146
+ ``status.dhw_temperature_raw``) for comparison logic, and use the properties
147
+ only for display or when a converted value is explicitly needed.
148
+ 4. **Remove ``from_dict()`` Calls**: The ``from_dict()`` method has been removed
149
+ from all models. Use ``model_validate()`` instead.
150
+
151
+ * **Note**: ``AuthenticationResponse.model_validate()`` now automatically handles
152
+ the ``"data": { ... }`` wrapper found in raw API responses.
153
+ 5. **Subpackage Imports**: While top-level imports from ``nwp500.models`` are
154
+ preserved, if you were importing from the internal ``nwp500.models`` module file
155
+ directly, you must update your imports to point to the new structured files
156
+ (e.g., ``nwp500.models.status``).
157
+
158
+ Added
159
+ -----
160
+ - **New control methods**: Nine previously unimplemented ``CommandCode`` values now have
161
+ full implementations: ``check_firmware``, ``commit_firmware``, ``reconnect_wifi``,
162
+ ``reset_wifi``, ``set_freeze_protection_temperature``, ``run_smart_diagnostic``,
163
+ ``enable_intelligent_reservation``, ``disable_intelligent_reservation``, and
164
+ ``set_water_program_reservation``.
165
+ - **Typed subscription methods**: ``subscribe_reservation``,
166
+ ``subscribe_weekly_reservation``, and ``subscribe_recirculation`` return typed
167
+ responses directly without requiring raw MQTT event handlers.
168
+ - **New protocol models**: ``WeeklyReservationSchedule``, ``WeeklyReservationEntry``,
169
+ ``RecirculationSchedule``, ``RecirculationScheduleEntry``, and ``OtaCommitPayload``.
170
+ - **``DeviceStateTracker``**: State change detection extracted into a dedicated class
171
+ in ``nwp500.mqtt.state_tracker`` with per-device tracking keyed by MAC address.
172
+ - **``MQTT_PROTOCOL_VERSION`` constant**: Protocol version is now a named constant in
173
+ ``nwp500.config`` rather than a hardcoded integer in the command payload builder.
174
+ - **``response_ack_topic()``**: New method on ``MqttTopicBuilder`` for control command
175
+ acknowledgement topics.
176
+
177
+ Changed
178
+ -------
179
+ - **Unit conversion redesign**: Temperature, flow rate, and volume fields in
180
+ ``DeviceStatus`` and ``DeviceFeature`` now store raw device values as ``*_raw: int``
181
+ fields and expose converted values via lazy computed properties. Conversion happens at
182
+ access time rather than during Pydantic deserialization, preserving the original
183
+ device value in all cases.
184
+ - **Models split into subpackage**: ``nwp500.models`` is now a package
185
+ (``nwp500/models/``) with modules for status, schedule, TOU, and MQTT models. Public
186
+ imports from ``nwp500.models`` are unchanged.
187
+ - **Topic building centralised**: All MQTT topic construction now goes through
188
+ ``MqttTopicBuilder``. Hardcoded topic strings removed from ``control.py``,
189
+ ``reservations.py``, and ``cli/handlers.py``.
190
+ - **``set_vacation_days`` delegates to ``set_dhw_mode``**: The method now calls
191
+ ``set_dhw_mode(device, DhwOperationSetting.VACATION, vacation_days=days)`` directly.
192
+ - **Per-device state tracking**: ``_previous_status`` changed from a single
193
+ ``DeviceStatus | None`` to a ``dict[str, DeviceStatus]`` keyed by MAC address,
194
+ preventing spurious state-change events when multiple devices are connected.
195
+ - **Unit system stored as instance variable**: ``NavienAPIClient``,
196
+ ``NavienMqttClient``, and ``NavienAuthClient`` no longer call ``set_unit_system()``
197
+ as a constructor side-effect.
198
+ - **``NavienBaseModel`` consolidated**: Duplicate definitions in ``auth.py`` and
199
+ ``models.py`` merged into a single definition in ``nwp500._base``.
200
+
5
201
  Version 7.4.10 (2026-04-13)
6
202
  ===========================
7
203
 
@@ -205,7 +401,7 @@ Breaking Changes
205
401
  .. code-block:: python
206
402
 
207
403
  # OLD (hardcoded 95-150°F)
208
- await mqtt.control.set_dhw_temperature(device, temperature_f=140.0)
404
+ await mqtt.set_dhw_temperature(device, temperature_f=140.0)
209
405
  entry = build_reservation_entry(
210
406
  enabled=True,
211
407
  days=["Monday"],
@@ -217,7 +413,7 @@ Breaking Changes
217
413
 
218
414
  # NEW (device-provided limits, unit-aware)
219
415
  # Temperature value automatically uses user's preferred unit
220
- await mqtt.control.set_dhw_temperature(device, 140.0)
416
+ await mqtt.set_dhw_temperature(device, 140.0)
221
417
 
222
418
  # Device features provide min/max in user's preferred unit
223
419
  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.control.set_temperature(device, 150)
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.1.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
- Advanced Features Explained: Weather-Responsive Heating, Demand Response, and Tank Stratification
2
- ==================================================================================================
1
+ Weather Response, Demand Response, and Tank Stratification
2
+ ===========================================================
3
3
 
4
- This document provides comprehensive technical documentation for three advanced NWP500 features.
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 sophisticated algorithms for grid integration, environmental responsiveness, and efficiency optimization:
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 enhanced heating efficiency
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. This enables the system to maintain comfort while adapting to seasonal conditions automatically.
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.control.request_device_status()
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.control.request_device_status(device_id)
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:`scheduling` - Scheduling and automation guide
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.