nwp500-python 7.1.0__tar.gz → 7.2.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 (178) hide show
  1. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/.github/copilot-instructions.md +9 -0
  2. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/.github/workflows/ci.yml +2 -2
  3. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/CHANGELOG.rst +237 -0
  4. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/CONTRIBUTING.rst +63 -0
  5. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/PKG-INFO +33 -1
  6. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/README.rst +28 -0
  7. nwp500_python-7.2.0/docs/guides/authentication.rst +304 -0
  8. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/guides/event_system.rst +62 -4
  9. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/index.rst +2 -0
  10. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/protocol/device_features.rst +1 -1
  11. nwp500_python-7.2.0/docs/protocol/quick_reference.rst +161 -0
  12. nwp500_python-7.2.0/examples/README.md +96 -0
  13. nwp500_python-7.1.0/examples/auto_recovery_example.py → nwp500_python-7.2.0/examples/advanced/auto_recovery.py +3 -2
  14. {nwp500_python-7.1.0/examples → nwp500_python-7.2.0/examples/advanced}/combined_callbacks.py +3 -2
  15. nwp500_python-7.1.0/examples/device_feature_callback.py → nwp500_python-7.2.0/examples/advanced/device_capabilities.py +4 -3
  16. nwp500_python-7.1.0/examples/device_status_callback_debug.py → nwp500_python-7.2.0/examples/advanced/device_status_debug.py +5 -4
  17. nwp500_python-7.1.0/examples/mqtt_diagnostics_example.py → nwp500_python-7.2.0/examples/advanced/mqtt_diagnostics.py +1 -1
  18. {nwp500_python-7.1.0/examples → nwp500_python-7.2.0/examples/advanced}/reconnection_demo.py +3 -2
  19. {nwp500_python-7.1.0/examples → nwp500_python-7.2.0/examples/advanced}/simple_auto_recovery.py +3 -2
  20. nwp500_python-7.1.0/examples/authenticate.py → nwp500_python-7.2.0/examples/beginner/01_authentication.py +2 -1
  21. nwp500_python-7.1.0/examples/api_client_example.py → nwp500_python-7.2.0/examples/beginner/02_list_devices.py +5 -4
  22. nwp500_python-7.1.0/examples/simple_periodic_status.py → nwp500_python-7.2.0/examples/beginner/03_get_status.py +2 -1
  23. nwp500_python-7.2.0/examples/intermediate/advanced_auth_patterns.py +179 -0
  24. nwp500_python-7.1.0/examples/command_queue_demo.py → nwp500_python-7.2.0/examples/intermediate/command_queue.py +1 -1
  25. {nwp500_python-7.1.0/examples → nwp500_python-7.2.0/examples/intermediate}/device_status_callback.py +4 -3
  26. nwp500_python-7.1.0/examples/exception_handling_example.py → nwp500_python-7.2.0/examples/intermediate/error_handling.py +2 -1
  27. nwp500_python-7.1.0/examples/event_emitter_demo.py → nwp500_python-7.2.0/examples/intermediate/event_driven_control.py +31 -23
  28. nwp500_python-7.1.0/examples/mqtt_client_example.py → nwp500_python-7.2.0/examples/intermediate/mqtt_realtime_monitoring.py +5 -4
  29. {nwp500_python-7.1.0/examples → nwp500_python-7.2.0/examples/intermediate}/periodic_requests.py +3 -2
  30. {nwp500_python-7.1.0/examples → nwp500_python-7.2.0/examples/testing}/periodic_device_info.py +3 -2
  31. {nwp500_python-7.1.0/examples → nwp500_python-7.2.0/examples/testing}/simple_periodic_info.py +2 -1
  32. {nwp500_python-7.1.0/examples → nwp500_python-7.2.0/examples/testing}/test_api_client.py +1 -1
  33. {nwp500_python-7.1.0/examples → nwp500_python-7.2.0/examples/testing}/test_mqtt_connection.py +1 -1
  34. {nwp500_python-7.1.0/examples → nwp500_python-7.2.0/examples/testing}/test_mqtt_messaging.py +3 -3
  35. {nwp500_python-7.1.0/examples → nwp500_python-7.2.0/examples/testing}/test_periodic_minimal.py +2 -1
  36. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/pyproject.toml +39 -0
  37. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/scripts/lint.py +17 -3
  38. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/setup.cfg +4 -0
  39. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/__init__.py +19 -9
  40. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/auth.py +25 -10
  41. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/cli/__init__.py +1 -1
  42. nwp500_python-7.2.0/src/nwp500/cli/__main__.py +348 -0
  43. nwp500_python-7.2.0/src/nwp500/cli/commands.py +89 -0
  44. nwp500_python-7.1.0/src/nwp500/cli/commands.py → nwp500_python-7.2.0/src/nwp500/cli/handlers.py +12 -6
  45. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/cli/output_formatters.py +368 -327
  46. nwp500_python-7.2.0/src/nwp500/cli/rich_output.py +522 -0
  47. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/command_decorators.py +3 -3
  48. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/constants.py +1 -1
  49. nwp500_python-7.2.0/src/nwp500/converters.py +154 -0
  50. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/device_capabilities.py +2 -2
  51. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/device_info_cache.py +3 -3
  52. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/encoding.py +2 -3
  53. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/enums.py +21 -1
  54. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/events.py +2 -4
  55. nwp500_python-7.2.0/src/nwp500/factory.py +82 -0
  56. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/models.py +56 -52
  57. nwp500_python-7.2.0/src/nwp500/mqtt/__init__.py +31 -0
  58. nwp500_python-7.1.0/src/nwp500/mqtt_client.py → nwp500_python-7.2.0/src/nwp500/mqtt/client.py +47 -40
  59. nwp500_python-7.1.0/src/nwp500/mqtt_command_queue.py → nwp500_python-7.2.0/src/nwp500/mqtt/command_queue.py +2 -2
  60. nwp500_python-7.1.0/src/nwp500/mqtt_connection.py → nwp500_python-7.2.0/src/nwp500/mqtt/connection.py +20 -22
  61. nwp500_python-7.1.0/src/nwp500/mqtt_device_control.py → nwp500_python-7.2.0/src/nwp500/mqtt/control.py +27 -17
  62. nwp500_python-7.1.0/src/nwp500/mqtt_periodic.py → nwp500_python-7.2.0/src/nwp500/mqtt/periodic.py +2 -2
  63. nwp500_python-7.1.0/src/nwp500/mqtt_reconnection.py → nwp500_python-7.2.0/src/nwp500/mqtt/reconnection.py +1 -1
  64. nwp500_python-7.1.0/src/nwp500/mqtt_subscriptions.py → nwp500_python-7.2.0/src/nwp500/mqtt/subscriptions.py +8 -8
  65. nwp500_python-7.1.0/src/nwp500/mqtt_utils.py → nwp500_python-7.2.0/src/nwp500/mqtt/utils.py +1 -1
  66. nwp500_python-7.2.0/src/nwp500/mqtt_events.py +344 -0
  67. nwp500_python-7.2.0/src/nwp500/temperature.py +187 -0
  68. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500_python.egg-info/PKG-INFO +33 -1
  69. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500_python.egg-info/SOURCES.txt +61 -49
  70. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500_python.egg-info/requires.txt +5 -0
  71. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/tests/test_cli_commands.py +1 -1
  72. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/tests/test_command_decorators.py +13 -13
  73. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/tests/test_command_queue.py +2 -2
  74. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/tests/test_device_capabilities.py +27 -19
  75. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/tests/test_device_info_cache.py +26 -26
  76. nwp500_python-7.2.0/tests/test_model_converters.py +365 -0
  77. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/tests/test_mqtt_client_init.py +1 -1
  78. nwp500_python-7.2.0/tests/test_temperature_converters.py +360 -0
  79. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/tox.ini +10 -4
  80. nwp500_python-7.1.0/examples/README.md +0 -158
  81. nwp500_python-7.1.0/src/nwp500/cli/__main__.py +0 -290
  82. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/.agent/workflows/pre-completion-testing.md +0 -0
  83. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/.coveragerc +0 -0
  84. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/.github/workflows/release.yml +0 -0
  85. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/.gitignore +0 -0
  86. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/.pre-commit-config.yaml +0 -0
  87. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/.readthedocs.yml +0 -0
  88. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/AUTHORS.rst +0 -0
  89. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/LICENSE.txt +0 -0
  90. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/Makefile +0 -0
  91. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/RELEASE.md +0 -0
  92. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/Makefile +0 -0
  93. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/_static/.gitignore +0 -0
  94. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/api/nwp500.rst +0 -0
  95. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/authors.rst +0 -0
  96. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/changelog.rst +0 -0
  97. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/conf.py +0 -0
  98. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/configuration.rst +0 -0
  99. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/development/contributing.rst +0 -0
  100. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/development/history.rst +0 -0
  101. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/enumerations.rst +0 -0
  102. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/guides/advanced_features_explained.rst +0 -0
  103. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/guides/auto_recovery.rst +0 -0
  104. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/guides/command_queue.rst +0 -0
  105. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/guides/energy_monitoring.rst +0 -0
  106. /nwp500_python-7.1.0/docs/MQTT_DIAGNOSTICS.rst → /nwp500_python-7.2.0/docs/guides/mqtt_diagnostics.rst +0 -0
  107. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/guides/reservations.rst +0 -0
  108. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/guides/scheduling_features.rst +0 -0
  109. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/guides/time_of_use.rst +0 -0
  110. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/installation.rst +0 -0
  111. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/license.rst +0 -0
  112. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/openapi.yaml +0 -0
  113. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/protocol/data_conversions.rst +0 -0
  114. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/protocol/device_status.rst +0 -0
  115. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/protocol/error_codes.rst +0 -0
  116. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/protocol/firmware_tracking.rst +0 -0
  117. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/protocol/mqtt_protocol.rst +0 -0
  118. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/protocol/rest_api.rst +0 -0
  119. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/python_api/api_client.rst +0 -0
  120. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/python_api/auth_client.rst +0 -0
  121. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/python_api/cli.rst +0 -0
  122. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/python_api/constants.rst +0 -0
  123. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/python_api/device_control.rst +0 -0
  124. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/python_api/events.rst +0 -0
  125. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/python_api/exceptions.rst +0 -0
  126. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/python_api/models.rst +0 -0
  127. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/python_api/mqtt_client.rst +0 -0
  128. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/quickstart.rst +0 -0
  129. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/docs/requirements.txt +0 -0
  130. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/examples/.ruff.toml +0 -0
  131. /nwp500_python-7.1.0/examples/air_filter_reset_example.py → /nwp500_python-7.2.0/examples/advanced/air_filter_reset.py +0 -0
  132. /nwp500_python-7.1.0/examples/anti_legionella_example.py → /nwp500_python-7.2.0/examples/advanced/anti_legionella.py +0 -0
  133. /nwp500_python-7.1.0/examples/demand_response_example.py → /nwp500_python-7.2.0/examples/advanced/demand_response.py +0 -0
  134. /nwp500_python-7.1.0/examples/energy_usage_example.py → /nwp500_python-7.2.0/examples/advanced/energy_analytics.py +0 -0
  135. {nwp500_python-7.1.0/examples → nwp500_python-7.2.0/examples/advanced}/error_code_demo.py +0 -0
  136. /nwp500_python-7.1.0/examples/power_control_example.py → /nwp500_python-7.2.0/examples/advanced/power_control.py +0 -0
  137. /nwp500_python-7.1.0/examples/recirculation_control_example.py → /nwp500_python-7.2.0/examples/advanced/recirculation_control.py +0 -0
  138. /nwp500_python-7.1.0/examples/reservation_schedule_example.py → /nwp500_python-7.2.0/examples/advanced/reservation_schedule.py +0 -0
  139. /nwp500_python-7.1.0/examples/token_restoration_example.py → /nwp500_python-7.2.0/examples/advanced/token_restoration.py +0 -0
  140. /nwp500_python-7.1.0/examples/tou_openei_example.py → /nwp500_python-7.2.0/examples/advanced/tou_openei.py +0 -0
  141. /nwp500_python-7.1.0/examples/tou_schedule_example.py → /nwp500_python-7.2.0/examples/advanced/tou_schedule.py +0 -0
  142. /nwp500_python-7.1.0/examples/water_program_reservation_example.py → /nwp500_python-7.2.0/examples/advanced/water_reservation.py +0 -0
  143. /nwp500_python-7.1.0/examples/set_dhw_temperature_example.py → /nwp500_python-7.2.0/examples/beginner/04_set_temperature.py +0 -0
  144. /nwp500_python-7.1.0/examples/improved_auth_pattern.py → /nwp500_python-7.2.0/examples/intermediate/improved_auth.py +0 -0
  145. /nwp500_python-7.1.0/examples/auth_constructor_example.py → /nwp500_python-7.2.0/examples/intermediate/legacy_auth_constructor.py +0 -0
  146. /nwp500_python-7.1.0/examples/set_mode_example.py → /nwp500_python-7.2.0/examples/intermediate/set_mode.py +0 -0
  147. /nwp500_python-7.1.0/examples/vacation_mode_example.py → /nwp500_python-7.2.0/examples/intermediate/vacation_mode.py +0 -0
  148. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/examples/mask.py +0 -0
  149. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/scripts/README.md +0 -0
  150. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/scripts/bump_version.py +0 -0
  151. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/scripts/diagnose_mqtt_connection.py +0 -0
  152. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/scripts/extract_changelog.py +0 -0
  153. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/scripts/format.py +0 -0
  154. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/scripts/setup-dev.py +0 -0
  155. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/scripts/validate_version.py +0 -0
  156. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/setup.py +0 -0
  157. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/api_client.py +0 -0
  158. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/cli/monitoring.py +0 -0
  159. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/cli/token_storage.py +0 -0
  160. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/config.py +0 -0
  161. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/exceptions.py +0 -0
  162. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/field_factory.py +0 -0
  163. /nwp500_python-7.1.0/src/nwp500/mqtt_diagnostics.py → /nwp500_python-7.2.0/src/nwp500/mqtt/diagnostics.py +0 -0
  164. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/py.typed +0 -0
  165. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/topic_builder.py +0 -0
  166. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500/utils.py +0 -0
  167. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500_python.egg-info/dependency_links.txt +0 -0
  168. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500_python.egg-info/entry_points.txt +0 -0
  169. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500_python.egg-info/not-zip-safe +0 -0
  170. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/src/nwp500_python.egg-info/top_level.txt +0 -0
  171. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/tests/conftest.py +0 -0
  172. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/tests/test_api_helpers.py +0 -0
  173. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/tests/test_auth.py +0 -0
  174. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/tests/test_cli_basic.py +0 -0
  175. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/tests/test_events.py +0 -0
  176. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/tests/test_exceptions.py +0 -0
  177. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/tests/test_models.py +0 -0
  178. {nwp500_python-7.1.0 → nwp500_python-7.2.0}/tests/test_utils.py +0 -0
@@ -45,6 +45,15 @@ The version bump script:
45
45
 
46
46
  **Validation**: Run `make validate-version` to check for version-related mistakes before committing.
47
47
 
48
+ ### Review Comments
49
+
50
+ When working on pull requests, use the GitHub CLI to access review comments:
51
+ - **List review comments**: `gh pr review-comment list --repo=<owner>/<repo>`
52
+ - **Get PR details with reviews**: `gh pr view <number> --repo=<owner>/<repo>`
53
+ - **Apply review feedback** before final submission
54
+
55
+ This ensures you can address all feedback from code reviewers systematically.
56
+
48
57
  ### Before Committing Changes
49
58
  Always run these checks before finalizing changes to ensure your code will pass CI:
50
59
  1. **Linting**: `make ci-lint` - Ensures code style matches CI requirements
@@ -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.10'
21
+ python-version: '3.13'
22
22
 
23
23
  - name: Install tox
24
24
  run: |
@@ -68,7 +68,7 @@ jobs:
68
68
  - name: Set up Python
69
69
  uses: actions/setup-python@v5
70
70
  with:
71
- python-version: '3.10'
71
+ python-version: '3.13'
72
72
 
73
73
  - name: Install build dependencies
74
74
  run: |
@@ -2,6 +2,243 @@
2
2
  Changelog
3
3
  =========
4
4
 
5
+ Version 7.2.0 (2025-12-23)
6
+ ==========================
7
+
8
+ **BREAKING CHANGES**: Class names renamed for consistency with MQTT-specific functionality
9
+
10
+ Removed
11
+ -------
12
+
13
+ - **Renamed Classes**: Updated class names to clarify MQTT-specific implementations
14
+
15
+ .. code-block:: python
16
+
17
+ # OLD (removed)
18
+ from nwp500 import DeviceCapabilityChecker, DeviceInfoCache
19
+
20
+ # NEW
21
+ from nwp500 import MqttDeviceCapabilityChecker, MqttDeviceInfoCache
22
+
23
+ **Rationale**: The original names were too generic. These classes are specifically designed
24
+ for MQTT client functionality (auto-fetching device info, caching, capability checking).
25
+ The new names make it clear they're MQTT-specific implementations, leaving room for future
26
+ REST API versions if needed.
27
+
28
+ **Migration**: Simple find-and-replace:
29
+
30
+ - ``DeviceCapabilityChecker`` → ``MqttDeviceCapabilityChecker``
31
+ - ``DeviceInfoCache`` → ``MqttDeviceInfoCache``
32
+
33
+ All functionality remains identical - only the class names changed.
34
+
35
+ Added
36
+ -----
37
+
38
+ - **Factory Function**: New ``create_navien_clients()`` factory for streamlined client initialization
39
+
40
+ .. code-block:: python
41
+
42
+ # Create both API and MQTT clients in one call
43
+ from nwp500 import create_navien_clients
44
+
45
+ async with create_navien_clients(email, password) as (api_client, mqtt_client):
46
+ devices = await api_client.get_devices()
47
+ await mqtt_client.connect()
48
+ # Both clients ready to use
49
+
50
+ - Automatic auth client management (created internally, shared by both clients)
51
+ - Simplified initialization for common use case (API + MQTT)
52
+ - Proper async context manager support
53
+ - Reduces boilerplate in application code
54
+ - Comprehensive documentation in ``docs/guides/authentication.rst``
55
+ - Example: ``examples/intermediate/advanced_auth_patterns.py``
56
+
57
+ - **VolumeCode Enum**: Tank capacity identification with gallon values
58
+
59
+ .. code-block:: python
60
+
61
+ from nwp500 import VolumeCode
62
+
63
+ # Enum values: VOLUME_50GAL = 65, VOLUME_65GAL = 66, VOLUME_80GAL = 67
64
+ # Human-readable text available in VOLUME_CODE_TEXT dict
65
+
66
+ - Maps device codes to actual tank capacities (50, 65, 80 gallons)
67
+ - Used in ``DeviceFeature.volume_code`` field with automatic validation
68
+ - Exported from main package for convenience
69
+ - Includes ``VOLUME_CODE_TEXT`` mapping for display purposes
70
+
71
+ - **Temperature Conversion Classes**: Type-safe temperature handling with clear precision
72
+
73
+ - ``HalfCelsius`` class: 0.5°C precision (value / 2.0)
74
+ - ``DeciCelsius`` class: 0.1°C precision (value / 10.0)
75
+ - Base ``Temperature`` ABC with ``to_celsius()`` and ``to_fahrenheit()`` methods
76
+ - ``from_fahrenheit()`` class methods for reverse conversions
77
+ - Validator functions for Pydantic integration
78
+ - Centralized in new ``temperature.py`` module
79
+ - Better type safety and clearer intent than raw number conversions
80
+
81
+ - **Protocol Converters Module**: Centralized device protocol conversion logic
82
+
83
+ - ``device_bool_to_python()``: Convert device boolean (1=False, 2=True)
84
+ - ``device_bool_from_python()``: Reverse conversion
85
+ - ``tou_status_to_python()``: Time of Use status conversion
86
+ - ``tou_override_to_python()``: TOU override status conversion
87
+ - ``div_10()``: Divide by 10.0 utility
88
+ - ``enum_validator()``: Generic enum factory
89
+ - Comprehensive documentation explaining device protocol quirks
90
+ - New ``converters.py`` module replacing scattered validators
91
+
92
+ - **MQTT Event System**: Structured event handling for MQTT operations
93
+
94
+ - ``MqttClientEvents`` class with type-safe event definitions
95
+ - Feature monitoring and capability detection events
96
+ - Enhanced device capability monitoring in MQTT control module
97
+ - New ``mqtt_events.py`` module for event infrastructure
98
+ - Improved separation of concerns for event-driven architectures
99
+
100
+ - **Pyright Type Checking**: Static type analysis integrated into CI/CD
101
+
102
+ - Added pyright>=1.1.0 to dev dependencies
103
+ - Configured in ``pyproject.toml`` with strict mode for ``src/nwp500``
104
+ - Integrated into tox lint environment and CI workflows
105
+ - Runs automatically with ``make ci-lint`` or ``python3 scripts/lint.py``
106
+ - All source code now passes strict type checking (0 errors)
107
+ - Improved type annotations across codebase
108
+
109
+ - **Dynamic Unit Extraction in CLI**: CLI output now dynamically extracts units from DeviceStatus model metadata
110
+
111
+ - New helper functions: ``_get_unit_suffix()`` and ``_add_numeric_item()``
112
+ - Eliminates hardcoded units in output formatter
113
+ - Single source of truth: model metadata drives CLI display
114
+
115
+ - **Comprehensive Protocol Documentation**: Complete protocol reference documentation
116
+
117
+ - New ``docs/protocol/quick_reference.rst`` with command codes, field formats, and conversions
118
+ - Converted protocol documentation to RST format for Sphinx integration
119
+ - Added protocol reference links in source code comments
120
+ - Improved cross-referencing between code and documentation
121
+
122
+ Changed
123
+ -------
124
+
125
+ - **MQTT Module Reorganization**: Consolidated 9 separate modules into cohesive ``mqtt`` package
126
+
127
+ .. code-block:: python
128
+
129
+ # OLD imports (still work via compatibility layer)
130
+ from nwp500.mqtt_client import NavienMqttClient
131
+ from nwp500.mqtt_diagnostics import MqttDiagnosticsCollector
132
+ from nwp500.mqtt_utils import MqttConnectionConfig
133
+
134
+ # NEW imports (preferred)
135
+ from nwp500.mqtt import NavienMqttClient, MqttDiagnosticsCollector, MqttConnectionConfig
136
+ # OR import from main package (recommended)
137
+ from nwp500 import NavienMqttClient, MqttDiagnosticsCollector, MqttConnectionConfig
138
+
139
+ - Created ``src/nwp500/mqtt/`` package with organized submodules
140
+ - Better package organization and structure
141
+ - Clearer public vs internal APIs
142
+ - New ``mqtt/__init__.py`` with clean public API exports
143
+ - Backward compatibility maintained via main package exports
144
+ - All 209 tests pass with zero type checking errors
145
+
146
+ - **CLI Framework Migration**: Migrated from argparse to Click framework
147
+
148
+ - Implemented ``async_command`` decorator for automatic loop and connection management
149
+ - Added support for command groups (reservations, tou)
150
+ - Improved argument and option parsing with built-in validation
151
+ - Enhanced help text and version reporting
152
+ - Centralized command registry in ``src/nwp500/cli/commands.py``
153
+ - Reorganized CLI handlers into ``src/nwp500/cli/handlers.py``
154
+ - Better separation of concerns between CLI framework and business logic
155
+ - Industry-standard CLI framework with better maintainability
156
+ - Added click>=8.0.0 dependency
157
+
158
+ - **Examples Reorganization**: Restructured examples into beginner/intermediate/advanced/testing categories
159
+
160
+ - Created structured hierarchy in ``examples/`` directory
161
+ - Renamed and moved 35+ example scripts for better discoverability
162
+ - Updated ``examples/README.md`` with 'Getting Started' guide and categorized index
163
+ - Added 01-04 beginner series for smooth onboarding:
164
+
165
+ - ``beginner/01_authentication.py`` - Basic authentication patterns
166
+ - ``beginner/02_list_devices.py`` - Retrieving device information
167
+ - ``beginner/03_get_status.py`` - Getting device status
168
+ - ``beginner/04_set_temperature.py`` - Basic device control
169
+
170
+ - Intermediate examples: event-driven control, error handling, MQTT monitoring
171
+ - Advanced examples: demand response, recirculation, TOU schedules, diagnostics
172
+ - Testing examples: connection testing, periodic updates, minimal examples
173
+ - All examples updated with correct imports for new package structure
174
+
175
+ - **Authentication Documentation**: Major improvements to authentication guide
176
+
177
+ - Complete rewrite of ``docs/guides/authentication.rst``
178
+ - Added factory function patterns and examples
179
+ - Improved context manager documentation
180
+ - Added best practices and common patterns
181
+ - More comprehensive code examples
182
+
183
+ - **Model Refactoring**: Updated to use new converter modules
184
+
185
+ - Replaced 53 lines of scattered validators with imports
186
+ - Updated ``fahrenheit_to_half_celsius()`` to use ``HalfCelsius`` class
187
+ - Cleaner model definitions with centralized conversion logic
188
+ - No breaking changes to public API
189
+
190
+ - **CLI Output Formatter Refactoring**: Restructured ``print_device_status()`` to use dynamic unit extraction
191
+
192
+ - Reduced code duplication by ~400 lines
193
+ - Improved maintainability: field additions automatically get correct units
194
+ - No breaking changes to CLI output format or behavior
195
+
196
+ - **Type Annotations**: Improved type safety across entire codebase
197
+
198
+ - Fixed datetime imports to use ``datetime.UTC`` (Python 3.13)
199
+ - Fixed type annotations in ``rich_output.py`` for optional dependencies
200
+ - Fixed type narrowing issues in ``encoding.py``
201
+ - Updated ``MqttConnection`` callback signature to use ``AwsCrtError``
202
+ - Added public properties and setters where needed for type checking
203
+
204
+ Fixed
205
+ -----
206
+
207
+ - **Superheat Temperature Units**: Target and Current SuperHeat now correctly display in °F instead of °C
208
+
209
+ - Both fields use ``DeciCelsiusToF`` conversion, now properly reflected in CLI output
210
+ - Fields were displaying inconsistent units compared to all other temperature readings
211
+
212
+ - **Missing CLI Output Units**: Multiple fields now display with proper units from model metadata
213
+
214
+ - ``current_dhw_flow_rate``: Now shows GPM unit
215
+ - ``total_energy_capacity``: Now shows Wh unit
216
+ - ``available_energy_capacity``: Now shows Wh unit
217
+ - ``dr_override_status``: Now shows hours unit
218
+ - ``vacation_day_setting``: Now shows days unit
219
+ - ``vacation_day_elapsed``: Now shows days unit
220
+ - ``anti_legionella_period``: Fixed to show days unit (was incorrectly h)
221
+ - ``wifi_rssi``: Now shows dBm unit
222
+
223
+ - **Invalid MQTT Topic Filter**: Fixed ``reservations get`` command subscription topic
224
+
225
+ - Changed invalid topic pattern ``cmd/52/navilink-+/#`` to valid ``cmd/52/+/#``
226
+ - AWS IoT Core MQTT does not support wildcards within topic segments
227
+ - Affected: ``handle_get_reservations_request()`` in commands.py
228
+
229
+ - **DeviceFeature Documentation**: Clarified field descriptions and fixed documentation errors
230
+
231
+ - Fixed ``country_code`` documentation (actual value is 3, not 1 as previously noted)
232
+ - Clarified ``model_type_code``, ``control_type_code``, ``recirc_model_type_code`` field purposes
233
+ - Updated ``volume_code`` to use new ``VolumeCode`` enum with validation
234
+
235
+ - **Type Checking Errors**: Resolved all pyright type checking errors in source code
236
+
237
+ - Fixed datetime imports and type annotations
238
+ - Added missing public properties and setters
239
+ - Removed unused imports and variables
240
+ - All source code now passes strict type checking
241
+
5
242
  Version 7.1.0 (2025-12-22)
6
243
  ==========================
7
244
 
@@ -85,6 +85,69 @@ The project is organized around a modular architecture:
85
85
 
86
86
  Design principles include separation of concerns, clear public APIs, and extensibility for new device features. Contributors should review the `src/nwp500/` directory for module structure and refer to the documentation for details on each component.
87
87
 
88
+ Naming Conventions
89
+ ------------------
90
+
91
+ Consistent naming conventions improve code readability and maintainability. Follow these patterns when adding new classes, methods, and exceptions.
92
+
93
+ **Classes**
94
+
95
+ - **Client classes**: Use ``Navien<Component>Client`` format for main client classes (e.g., ``NavienAuthClient``, ``NavienAPIClient``, ``NavienMqttClient``). This prefix clearly indicates these are the primary library clients.
96
+ - **Manager/Controller classes**: Use ``<Domain><Responsibility>`` format for classes managing specific functionality (e.g., ``MqttConnectionManager``, ``DeviceInfoCache``). Avoid Navien prefix for utility/internal classes.
97
+ - **Utility classes**: Use ``<Domain><Feature>`` or ``<Domain>Utilities`` format for helper classes (e.g., ``MqttDiagnostics``, ``DeviceCapabilityChecker``).
98
+
99
+ **Methods**
100
+
101
+ Follow these patterns for consistent method naming:
102
+
103
+ - **Getters**: Use ``get_<resource>()`` for single item retrieval (e.g., ``get_device_info()``, ``get_firmware_info()``)
104
+ - **Listers**: Use ``list_<resources>()`` for collection retrieval (e.g., ``list_devices()``)
105
+ - **Setters**: Use ``set_<field>(value)`` for direct assignment or ``configure_<feature>()`` for complex configuration (e.g., ``set_power()``, ``set_dhw_temperature()``)
106
+ - **Actions**: Use ``<action>_<resource>()`` format for operations that modify state (e.g., ``reset_filter()``, ``enable_anti_legionella()``)
107
+ - **Requesters**: Use ``request_<data>()`` for async data fetching from devices (e.g., ``request_device_status()``, ``request_device_info()``)
108
+
109
+ **Enums**
110
+
111
+ - **Enum names**: Use descriptive names that indicate the device state or protocol value (e.g., ``OnOffFlag``, ``CurrentOperationMode``, ``HeatSource``). These names should reflect the Navien protocol directly.
112
+ - **Enum values**: Document device protocol mappings in code comments. For example:
113
+
114
+ .. code-block:: python
115
+
116
+ class OnOffFlag(IntEnum):
117
+ """Device on/off state per Navien protocol."""
118
+ OFF = 0 # 0 = False per Navien protocol
119
+ ON = 1 # 1 = True per Navien protocol
120
+
121
+ **Exceptions**
122
+
123
+ Follow a clear exception hierarchy with consistent naming:
124
+
125
+ - **Pattern**: ``<Domain><Situation>Error`` (e.g., ``MqttConnectionError``, ``AuthenticationError``, ``DeviceCapabilityError``)
126
+ - **Grouping**: Group related errors under a base class that consumers can catch for broad error handling:
127
+
128
+ - ``AuthenticationError`` - Base for all authentication failures (covers ``InvalidCredentialsError``, ``TokenExpiredError``, ``TokenRefreshError``)
129
+ - ``MqttError`` - Base for all MQTT operations (covers ``MqttConnectionError``, ``MqttNotConnectedError``, ``MqttPublishError``, etc.)
130
+ - ``ValidationError`` - Base for all validation failures (covers ``ParameterValidationError``, ``RangeValidationError``)
131
+ - ``DeviceError`` - Base for all device operations (covers ``DeviceNotFoundError``, ``DeviceOfflineError``, ``DeviceCapabilityError``, etc.)
132
+
133
+ - **Example usage**:
134
+
135
+ .. code-block:: python
136
+
137
+ try:
138
+ await mqtt_client.control.set_temperature(device, 150)
139
+ except MqttNotConnectedError:
140
+ # Handle specific case: not connected
141
+ print("Connect to device first")
142
+ except MqttError:
143
+ # Handle other MQTT errors
144
+ print("MQTT operation failed")
145
+ except RangeValidationError as e:
146
+ print(f"Invalid {e.field}: must be {e.min_value}-{e.max_value}")
147
+ except ValidationError:
148
+ # Handle other validation errors
149
+ print("Invalid parameter")
150
+
88
151
  Submit an issue
89
152
  ---------------
90
153
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nwp500-python
3
- Version: 7.1.0
3
+ Version: 7.2.0
4
4
  Summary: A library for controlling Navien NWP500 Water Heaters via NaviLink
5
5
  Home-page: https://github.com/eman/nwp500-python
6
6
  Author: Emmanuel Levijarvi
@@ -21,6 +21,9 @@ License-File: LICENSE.txt
21
21
  Requires-Dist: aiohttp>=3.8.0
22
22
  Requires-Dist: awsiotsdk>=1.27.0
23
23
  Requires-Dist: pydantic>=2.0.0
24
+ Requires-Dist: click>=8.0.0
25
+ Provides-Extra: cli
26
+ Requires-Dist: rich>=13.0.0; extra == "cli"
24
27
  Provides-Extra: testing
25
28
  Requires-Dist: setuptools; extra == "testing"
26
29
  Requires-Dist: pytest; extra == "testing"
@@ -28,6 +31,7 @@ Requires-Dist: pytest-cov; extra == "testing"
28
31
  Requires-Dist: pytest-asyncio; extra == "testing"
29
32
  Provides-Extra: dev
30
33
  Requires-Dist: ruff>=0.1.0; extra == "dev"
34
+ Requires-Dist: pyright>=1.1.0; extra == "dev"
31
35
  Requires-Dist: setuptools; extra == "dev"
32
36
  Requires-Dist: pytest; extra == "dev"
33
37
  Requires-Dist: pytest-cov; extra == "dev"
@@ -98,6 +102,34 @@ Basic Usage
98
102
  # Change operation mode
99
103
  await api_client.set_device_mode(device, "heat_pump")
100
104
 
105
+ For more detailed authentication information, see the `Authentication & Session Management <https://nwp500-python.readthedocs.io/en/latest/guides/authentication.html>`_ guide.
106
+
107
+ MQTT Real-Time Monitoring
108
+ --------------------------
109
+
110
+ Monitor your device in real-time using MQTT:
111
+
112
+ .. code-block:: python
113
+
114
+ from nwp500 import NavienAuthClient, NavienMqttClient
115
+
116
+ async with NavienAuthClient("your_email@example.com", "your_password") as auth_client:
117
+ # Create MQTT client
118
+ mqtt_client = NavienMqttClient(auth_client=auth_client)
119
+ await mqtt_client.connect()
120
+
121
+ # Subscribe to device status updates
122
+ def on_status(status):
123
+ print(f"Temperature: {status.dhw_temperature}°F")
124
+ print(f"Mode: {status.operation_mode}")
125
+
126
+ device = (await api_client.list_devices())[0]
127
+ await mqtt_client.subscribe_device_status(device, on_status)
128
+
129
+ # Keep the connection alive
130
+ await mqtt_client.wait()
131
+
132
+
101
133
  Command Line Interface
102
134
  ======================
103
135
 
@@ -62,6 +62,34 @@ Basic Usage
62
62
  # Change operation mode
63
63
  await api_client.set_device_mode(device, "heat_pump")
64
64
 
65
+ For more detailed authentication information, see the `Authentication & Session Management <https://nwp500-python.readthedocs.io/en/latest/guides/authentication.html>`_ guide.
66
+
67
+ MQTT Real-Time Monitoring
68
+ --------------------------
69
+
70
+ Monitor your device in real-time using MQTT:
71
+
72
+ .. code-block:: python
73
+
74
+ from nwp500 import NavienAuthClient, NavienMqttClient
75
+
76
+ async with NavienAuthClient("your_email@example.com", "your_password") as auth_client:
77
+ # Create MQTT client
78
+ mqtt_client = NavienMqttClient(auth_client=auth_client)
79
+ await mqtt_client.connect()
80
+
81
+ # Subscribe to device status updates
82
+ def on_status(status):
83
+ print(f"Temperature: {status.dhw_temperature}°F")
84
+ print(f"Mode: {status.operation_mode}")
85
+
86
+ device = (await api_client.list_devices())[0]
87
+ await mqtt_client.subscribe_device_status(device, on_status)
88
+
89
+ # Keep the connection alive
90
+ await mqtt_client.wait()
91
+
92
+
65
93
  Command Line Interface
66
94
  ======================
67
95