nwp500-python 7.1.0__tar.gz → 7.2.1__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.1}/.github/copilot-instructions.md +9 -0
  2. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/.github/workflows/ci.yml +2 -2
  3. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/CHANGELOG.rst +297 -0
  4. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/CONTRIBUTING.rst +63 -0
  5. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/PKG-INFO +37 -2
  6. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/README.rst +32 -1
  7. nwp500_python-7.2.1/docs/guides/authentication.rst +304 -0
  8. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/guides/event_system.rst +62 -4
  9. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/index.rst +3 -2
  10. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/protocol/device_features.rst +1 -1
  11. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/protocol/mqtt_protocol.rst +11 -8
  12. nwp500_python-7.2.1/docs/protocol/quick_reference.rst +161 -0
  13. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/protocol/rest_api.rst +7 -0
  14. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/python_api/models.rst +4 -1
  15. nwp500_python-7.2.1/examples/README.md +96 -0
  16. nwp500_python-7.1.0/examples/auto_recovery_example.py → nwp500_python-7.2.1/examples/advanced/auto_recovery.py +3 -2
  17. {nwp500_python-7.1.0/examples → nwp500_python-7.2.1/examples/advanced}/combined_callbacks.py +3 -2
  18. nwp500_python-7.1.0/examples/device_feature_callback.py → nwp500_python-7.2.1/examples/advanced/device_capabilities.py +4 -3
  19. nwp500_python-7.1.0/examples/device_status_callback_debug.py → nwp500_python-7.2.1/examples/advanced/device_status_debug.py +5 -4
  20. nwp500_python-7.1.0/examples/mqtt_diagnostics_example.py → nwp500_python-7.2.1/examples/advanced/mqtt_diagnostics.py +1 -1
  21. {nwp500_python-7.1.0/examples → nwp500_python-7.2.1/examples/advanced}/reconnection_demo.py +3 -2
  22. {nwp500_python-7.1.0/examples → nwp500_python-7.2.1/examples/advanced}/simple_auto_recovery.py +3 -2
  23. nwp500_python-7.1.0/examples/authenticate.py → nwp500_python-7.2.1/examples/beginner/01_authentication.py +2 -1
  24. nwp500_python-7.1.0/examples/api_client_example.py → nwp500_python-7.2.1/examples/beginner/02_list_devices.py +5 -4
  25. nwp500_python-7.1.0/examples/simple_periodic_status.py → nwp500_python-7.2.1/examples/beginner/03_get_status.py +2 -1
  26. nwp500_python-7.2.1/examples/intermediate/advanced_auth_patterns.py +179 -0
  27. nwp500_python-7.1.0/examples/command_queue_demo.py → nwp500_python-7.2.1/examples/intermediate/command_queue.py +1 -1
  28. {nwp500_python-7.1.0/examples → nwp500_python-7.2.1/examples/intermediate}/device_status_callback.py +4 -3
  29. nwp500_python-7.1.0/examples/exception_handling_example.py → nwp500_python-7.2.1/examples/intermediate/error_handling.py +2 -1
  30. nwp500_python-7.1.0/examples/event_emitter_demo.py → nwp500_python-7.2.1/examples/intermediate/event_driven_control.py +31 -23
  31. nwp500_python-7.1.0/examples/mqtt_client_example.py → nwp500_python-7.2.1/examples/intermediate/mqtt_realtime_monitoring.py +5 -4
  32. {nwp500_python-7.1.0/examples → nwp500_python-7.2.1/examples/intermediate}/periodic_requests.py +3 -2
  33. {nwp500_python-7.1.0/examples → nwp500_python-7.2.1/examples/testing}/periodic_device_info.py +3 -2
  34. {nwp500_python-7.1.0/examples → nwp500_python-7.2.1/examples/testing}/simple_periodic_info.py +2 -1
  35. {nwp500_python-7.1.0/examples → nwp500_python-7.2.1/examples/testing}/test_api_client.py +1 -1
  36. {nwp500_python-7.1.0/examples → nwp500_python-7.2.1/examples/testing}/test_mqtt_connection.py +1 -1
  37. {nwp500_python-7.1.0/examples → nwp500_python-7.2.1/examples/testing}/test_mqtt_messaging.py +3 -3
  38. {nwp500_python-7.1.0/examples → nwp500_python-7.2.1/examples/testing}/test_periodic_minimal.py +2 -1
  39. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/pyproject.toml +47 -0
  40. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/scripts/lint.py +17 -3
  41. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/setup.cfg +4 -0
  42. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/__init__.py +21 -9
  43. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/auth.py +30 -10
  44. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/cli/__init__.py +3 -1
  45. nwp500_python-7.2.1/src/nwp500/cli/__main__.py +367 -0
  46. nwp500_python-7.2.1/src/nwp500/cli/commands.py +89 -0
  47. nwp500_python-7.1.0/src/nwp500/cli/commands.py → nwp500_python-7.2.1/src/nwp500/cli/handlers.py +45 -6
  48. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/cli/output_formatters.py +368 -327
  49. nwp500_python-7.2.1/src/nwp500/cli/rich_output.py +523 -0
  50. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/command_decorators.py +3 -3
  51. nwp500_python-7.2.1/src/nwp500/converters.py +165 -0
  52. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/device_capabilities.py +2 -2
  53. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/device_info_cache.py +3 -3
  54. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/encoding.py +2 -3
  55. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/enums.py +49 -2
  56. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/events.py +2 -4
  57. nwp500_python-7.2.1/src/nwp500/factory.py +82 -0
  58. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/models.py +60 -53
  59. nwp500_python-7.2.1/src/nwp500/mqtt/__init__.py +31 -0
  60. nwp500_python-7.1.0/src/nwp500/mqtt_client.py → nwp500_python-7.2.1/src/nwp500/mqtt/client.py +47 -40
  61. nwp500_python-7.1.0/src/nwp500/mqtt_command_queue.py → nwp500_python-7.2.1/src/nwp500/mqtt/command_queue.py +2 -2
  62. nwp500_python-7.1.0/src/nwp500/mqtt_connection.py → nwp500_python-7.2.1/src/nwp500/mqtt/connection.py +20 -22
  63. nwp500_python-7.1.0/src/nwp500/mqtt_device_control.py → nwp500_python-7.2.1/src/nwp500/mqtt/control.py +27 -17
  64. nwp500_python-7.1.0/src/nwp500/mqtt_periodic.py → nwp500_python-7.2.1/src/nwp500/mqtt/periodic.py +2 -2
  65. nwp500_python-7.1.0/src/nwp500/mqtt_reconnection.py → nwp500_python-7.2.1/src/nwp500/mqtt/reconnection.py +1 -1
  66. nwp500_python-7.1.0/src/nwp500/mqtt_subscriptions.py → nwp500_python-7.2.1/src/nwp500/mqtt/subscriptions.py +8 -8
  67. nwp500_python-7.1.0/src/nwp500/mqtt_utils.py → nwp500_python-7.2.1/src/nwp500/mqtt/utils.py +1 -1
  68. nwp500_python-7.2.1/src/nwp500/mqtt_events.py +344 -0
  69. nwp500_python-7.2.1/src/nwp500/temperature.py +187 -0
  70. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500_python.egg-info/PKG-INFO +37 -2
  71. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500_python.egg-info/SOURCES.txt +61 -52
  72. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500_python.egg-info/requires.txt +5 -0
  73. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/tests/test_cli_commands.py +1 -1
  74. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/tests/test_command_decorators.py +13 -13
  75. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/tests/test_command_queue.py +2 -2
  76. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/tests/test_device_capabilities.py +27 -19
  77. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/tests/test_device_info_cache.py +26 -26
  78. nwp500_python-7.2.1/tests/test_model_converters.py +318 -0
  79. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/tests/test_mqtt_client_init.py +1 -1
  80. nwp500_python-7.2.1/tests/test_temperature_converters.py +360 -0
  81. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/tox.ini +10 -4
  82. nwp500_python-7.1.0/docs/protocol/firmware_tracking.rst +0 -176
  83. nwp500_python-7.1.0/docs/python_api/constants.rst +0 -353
  84. nwp500_python-7.1.0/examples/README.md +0 -158
  85. nwp500_python-7.1.0/src/nwp500/cli/__main__.py +0 -290
  86. nwp500_python-7.1.0/src/nwp500/constants.py +0 -34
  87. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/.agent/workflows/pre-completion-testing.md +0 -0
  88. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/.coveragerc +0 -0
  89. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/.github/workflows/release.yml +0 -0
  90. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/.gitignore +0 -0
  91. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/.pre-commit-config.yaml +0 -0
  92. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/.readthedocs.yml +0 -0
  93. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/AUTHORS.rst +0 -0
  94. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/LICENSE.txt +0 -0
  95. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/Makefile +0 -0
  96. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/RELEASE.md +0 -0
  97. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/Makefile +0 -0
  98. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/_static/.gitignore +0 -0
  99. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/api/nwp500.rst +0 -0
  100. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/authors.rst +0 -0
  101. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/changelog.rst +0 -0
  102. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/conf.py +0 -0
  103. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/configuration.rst +0 -0
  104. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/development/contributing.rst +0 -0
  105. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/development/history.rst +0 -0
  106. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/enumerations.rst +0 -0
  107. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/guides/advanced_features_explained.rst +0 -0
  108. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/guides/auto_recovery.rst +0 -0
  109. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/guides/command_queue.rst +0 -0
  110. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/guides/energy_monitoring.rst +0 -0
  111. /nwp500_python-7.1.0/docs/MQTT_DIAGNOSTICS.rst → /nwp500_python-7.2.1/docs/guides/mqtt_diagnostics.rst +0 -0
  112. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/guides/reservations.rst +0 -0
  113. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/guides/scheduling_features.rst +0 -0
  114. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/guides/time_of_use.rst +0 -0
  115. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/installation.rst +0 -0
  116. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/license.rst +0 -0
  117. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/openapi.yaml +0 -0
  118. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/protocol/data_conversions.rst +0 -0
  119. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/protocol/device_status.rst +0 -0
  120. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/protocol/error_codes.rst +0 -0
  121. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/python_api/api_client.rst +0 -0
  122. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/python_api/auth_client.rst +0 -0
  123. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/python_api/cli.rst +0 -0
  124. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/python_api/device_control.rst +0 -0
  125. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/python_api/events.rst +0 -0
  126. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/python_api/exceptions.rst +0 -0
  127. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/python_api/mqtt_client.rst +0 -0
  128. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/quickstart.rst +0 -0
  129. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/docs/requirements.txt +0 -0
  130. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/examples/.ruff.toml +0 -0
  131. /nwp500_python-7.1.0/examples/air_filter_reset_example.py → /nwp500_python-7.2.1/examples/advanced/air_filter_reset.py +0 -0
  132. /nwp500_python-7.1.0/examples/anti_legionella_example.py → /nwp500_python-7.2.1/examples/advanced/anti_legionella.py +0 -0
  133. /nwp500_python-7.1.0/examples/demand_response_example.py → /nwp500_python-7.2.1/examples/advanced/demand_response.py +0 -0
  134. /nwp500_python-7.1.0/examples/energy_usage_example.py → /nwp500_python-7.2.1/examples/advanced/energy_analytics.py +0 -0
  135. {nwp500_python-7.1.0/examples → nwp500_python-7.2.1/examples/advanced}/error_code_demo.py +0 -0
  136. /nwp500_python-7.1.0/examples/power_control_example.py → /nwp500_python-7.2.1/examples/advanced/power_control.py +0 -0
  137. /nwp500_python-7.1.0/examples/recirculation_control_example.py → /nwp500_python-7.2.1/examples/advanced/recirculation_control.py +0 -0
  138. /nwp500_python-7.1.0/examples/reservation_schedule_example.py → /nwp500_python-7.2.1/examples/advanced/reservation_schedule.py +0 -0
  139. /nwp500_python-7.1.0/examples/token_restoration_example.py → /nwp500_python-7.2.1/examples/advanced/token_restoration.py +0 -0
  140. /nwp500_python-7.1.0/examples/tou_openei_example.py → /nwp500_python-7.2.1/examples/advanced/tou_openei.py +0 -0
  141. /nwp500_python-7.1.0/examples/tou_schedule_example.py → /nwp500_python-7.2.1/examples/advanced/tou_schedule.py +0 -0
  142. /nwp500_python-7.1.0/examples/water_program_reservation_example.py → /nwp500_python-7.2.1/examples/advanced/water_reservation.py +0 -0
  143. /nwp500_python-7.1.0/examples/set_dhw_temperature_example.py → /nwp500_python-7.2.1/examples/beginner/04_set_temperature.py +0 -0
  144. /nwp500_python-7.1.0/examples/improved_auth_pattern.py → /nwp500_python-7.2.1/examples/intermediate/improved_auth.py +0 -0
  145. /nwp500_python-7.1.0/examples/auth_constructor_example.py → /nwp500_python-7.2.1/examples/intermediate/legacy_auth_constructor.py +0 -0
  146. /nwp500_python-7.1.0/examples/set_mode_example.py → /nwp500_python-7.2.1/examples/intermediate/set_mode.py +0 -0
  147. /nwp500_python-7.1.0/examples/vacation_mode_example.py → /nwp500_python-7.2.1/examples/intermediate/vacation_mode.py +0 -0
  148. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/examples/mask.py +0 -0
  149. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/scripts/README.md +0 -0
  150. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/scripts/bump_version.py +0 -0
  151. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/scripts/diagnose_mqtt_connection.py +0 -0
  152. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/scripts/extract_changelog.py +0 -0
  153. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/scripts/format.py +0 -0
  154. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/scripts/setup-dev.py +0 -0
  155. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/scripts/validate_version.py +0 -0
  156. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/setup.py +0 -0
  157. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/api_client.py +0 -0
  158. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/cli/monitoring.py +0 -0
  159. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/cli/token_storage.py +0 -0
  160. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/config.py +0 -0
  161. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/exceptions.py +0 -0
  162. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/field_factory.py +0 -0
  163. /nwp500_python-7.1.0/src/nwp500/mqtt_diagnostics.py → /nwp500_python-7.2.1/src/nwp500/mqtt/diagnostics.py +0 -0
  164. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/py.typed +0 -0
  165. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/topic_builder.py +0 -0
  166. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500/utils.py +0 -0
  167. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500_python.egg-info/dependency_links.txt +0 -0
  168. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500_python.egg-info/entry_points.txt +0 -0
  169. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500_python.egg-info/not-zip-safe +0 -0
  170. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/src/nwp500_python.egg-info/top_level.txt +0 -0
  171. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/tests/conftest.py +0 -0
  172. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/tests/test_api_helpers.py +0 -0
  173. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/tests/test_auth.py +0 -0
  174. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/tests/test_cli_basic.py +0 -0
  175. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/tests/test_events.py +0 -0
  176. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/tests/test_exceptions.py +0 -0
  177. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/tests/test_models.py +0 -0
  178. {nwp500_python-7.1.0 → nwp500_python-7.2.1}/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,303 @@
2
2
  Changelog
3
3
  =========
4
4
 
5
+ Version 7.2.1 (2025-12-25)
6
+ ==========================
7
+
8
+ Added
9
+ -----
10
+ - **CLI Command**: New ``device-info`` command to retrieve basic device information from REST API
11
+
12
+ .. code-block:: bash
13
+
14
+ # Get basic device info (DeviceInfo model)
15
+ python3 -m nwp500.cli device-info
16
+ python3 -m nwp500.cli device-info --raw
17
+
18
+ - **ConnectionStatus Enum**: New ``ConnectionStatus`` enum for device cloud connection state
19
+
20
+ - ``ConnectionStatus.DISCONNECTED`` = 1 - Device offline/not connected
21
+ - ``ConnectionStatus.CONNECTED`` = 2 - Device online and reachable
22
+ - Used in ``DeviceInfo.connected`` field with automatic validation
23
+
24
+ - **InstallType Enum**: New ``InstallType`` enum for device installation classification
25
+
26
+ - ``InstallType.RESIDENTIAL`` = "R" - Residential use
27
+ - ``InstallType.COMMERCIAL`` = "C" - Commercial use
28
+ - Used in ``DeviceInfo.install_type`` field with automatic validation
29
+ - Includes ``INSTALL_TYPE_TEXT`` mapping for display purposes
30
+
31
+ - **String Enum Validator**: New ``str_enum_validator()`` converter for string-based enums
32
+
33
+ Changed
34
+ -------
35
+ - **DeviceInfo Model**:
36
+ - ``connected`` field now uses ``ConnectionStatus`` enum instead of plain int
37
+ - ``install_type`` field now uses ``InstallType`` enum instead of plain string
38
+
39
+ - **TOU Status Conversion**: Simplified TOU status to use standard ``device_bool_to_python`` converter (consistent with other OnOffFlag fields)
40
+ - Removed special-case ``tou_status_to_python()`` converter
41
+ - ``TouStatus`` annotated type now uses ``device_bool_to_python`` validator
42
+ - Device encoding: 1=OFF/disabled, 2=ON/enabled (consistent with all other boolean fields)
43
+
44
+ - **CLI Documentation**: Clarified distinction between ``info`` (DeviceFeature via MQTT) and ``device-info`` (DeviceInfo via REST API) commands
45
+
46
+ - **Type Annotations**: Fixed CLI rich_output console type annotation to declare at class level
47
+
48
+ Removed
49
+ -------
50
+ - **constants.py Module**: Removed empty ``constants.py`` module. ``CommandCode`` enum was already moved to ``enums.py`` in version 4.2.0.
51
+
52
+ .. code-block:: python
53
+
54
+ # OLD (removed)
55
+ from nwp500.constants import CommandCode
56
+
57
+ # NEW (use this)
58
+ from nwp500.enums import CommandCode
59
+
60
+ - **Firmware Tracking**: Removed unused firmware tracking constants and documentation (``KNOWN_FIRMWARE_FIELD_CHANGES``, ``LATEST_KNOWN_FIRMWARE``, ``docs/protocol/firmware_tracking.rst``)
61
+
62
+ - **TOU Status Converter**: Removed redundant ``tou_status_to_python()`` converter function and associated tests
63
+
64
+
65
+ Version 7.2.0 (2025-12-23)
66
+ ==========================
67
+
68
+ **BREAKING CHANGES**: Class names renamed for consistency with MQTT-specific functionality
69
+
70
+ Removed
71
+ -------
72
+
73
+ - **Renamed Classes**: Updated class names to clarify MQTT-specific implementations
74
+
75
+ .. code-block:: python
76
+
77
+ # OLD (removed)
78
+ from nwp500 import DeviceCapabilityChecker, DeviceInfoCache
79
+
80
+ # NEW
81
+ from nwp500 import MqttDeviceCapabilityChecker, MqttDeviceInfoCache
82
+
83
+ **Rationale**: The original names were too generic. These classes are specifically designed
84
+ for MQTT client functionality (auto-fetching device info, caching, capability checking).
85
+ The new names make it clear they're MQTT-specific implementations, leaving room for future
86
+ REST API versions if needed.
87
+
88
+ **Migration**: Simple find-and-replace:
89
+
90
+ - ``DeviceCapabilityChecker`` → ``MqttDeviceCapabilityChecker``
91
+ - ``DeviceInfoCache`` → ``MqttDeviceInfoCache``
92
+
93
+ All functionality remains identical - only the class names changed.
94
+
95
+ Added
96
+ -----
97
+
98
+ - **Factory Function**: New ``create_navien_clients()`` factory for streamlined client initialization
99
+
100
+ .. code-block:: python
101
+
102
+ # Create both API and MQTT clients in one call
103
+ from nwp500 import create_navien_clients
104
+
105
+ async with create_navien_clients(email, password) as (api_client, mqtt_client):
106
+ devices = await api_client.get_devices()
107
+ await mqtt_client.connect()
108
+ # Both clients ready to use
109
+
110
+ - Automatic auth client management (created internally, shared by both clients)
111
+ - Simplified initialization for common use case (API + MQTT)
112
+ - Proper async context manager support
113
+ - Reduces boilerplate in application code
114
+ - Comprehensive documentation in ``docs/guides/authentication.rst``
115
+ - Example: ``examples/intermediate/advanced_auth_patterns.py``
116
+
117
+ - **VolumeCode Enum**: Tank capacity identification with gallon values
118
+
119
+ .. code-block:: python
120
+
121
+ from nwp500 import VolumeCode
122
+
123
+ # Enum values: VOLUME_50GAL = 65, VOLUME_65GAL = 66, VOLUME_80GAL = 67
124
+ # Human-readable text available in VOLUME_CODE_TEXT dict
125
+
126
+ - Maps device codes to actual tank capacities (50, 65, 80 gallons)
127
+ - Used in ``DeviceFeature.volume_code`` field with automatic validation
128
+ - Exported from main package for convenience
129
+ - Includes ``VOLUME_CODE_TEXT`` mapping for display purposes
130
+
131
+ - **Temperature Conversion Classes**: Type-safe temperature handling with clear precision
132
+
133
+ - ``HalfCelsius`` class: 0.5°C precision (value / 2.0)
134
+ - ``DeciCelsius`` class: 0.1°C precision (value / 10.0)
135
+ - Base ``Temperature`` ABC with ``to_celsius()`` and ``to_fahrenheit()`` methods
136
+ - ``from_fahrenheit()`` class methods for reverse conversions
137
+ - Validator functions for Pydantic integration
138
+ - Centralized in new ``temperature.py`` module
139
+ - Better type safety and clearer intent than raw number conversions
140
+
141
+ - **Protocol Converters Module**: Centralized device protocol conversion logic
142
+
143
+ - ``device_bool_to_python()``: Convert device boolean (1=False, 2=True)
144
+ - ``device_bool_from_python()``: Reverse conversion
145
+ - ``tou_status_to_python()``: Time of Use status conversion
146
+ - ``tou_override_to_python()``: TOU override status conversion
147
+ - ``div_10()``: Divide by 10.0 utility
148
+ - ``enum_validator()``: Generic enum factory
149
+ - Comprehensive documentation explaining device protocol quirks
150
+ - New ``converters.py`` module replacing scattered validators
151
+
152
+ - **MQTT Event System**: Structured event handling for MQTT operations
153
+
154
+ - ``MqttClientEvents`` class with type-safe event definitions
155
+ - Feature monitoring and capability detection events
156
+ - Enhanced device capability monitoring in MQTT control module
157
+ - New ``mqtt_events.py`` module for event infrastructure
158
+ - Improved separation of concerns for event-driven architectures
159
+
160
+ - **Pyright Type Checking**: Static type analysis integrated into CI/CD
161
+
162
+ - Added pyright>=1.1.0 to dev dependencies
163
+ - Configured in ``pyproject.toml`` with strict mode for ``src/nwp500``
164
+ - Integrated into tox lint environment and CI workflows
165
+ - Runs automatically with ``make ci-lint`` or ``python3 scripts/lint.py``
166
+ - All source code now passes strict type checking (0 errors)
167
+ - Improved type annotations across codebase
168
+
169
+ - **Dynamic Unit Extraction in CLI**: CLI output now dynamically extracts units from DeviceStatus model metadata
170
+
171
+ - New helper functions: ``_get_unit_suffix()`` and ``_add_numeric_item()``
172
+ - Eliminates hardcoded units in output formatter
173
+ - Single source of truth: model metadata drives CLI display
174
+
175
+ - **Comprehensive Protocol Documentation**: Complete protocol reference documentation
176
+
177
+ - New ``docs/protocol/quick_reference.rst`` with command codes, field formats, and conversions
178
+ - Converted protocol documentation to RST format for Sphinx integration
179
+ - Added protocol reference links in source code comments
180
+ - Improved cross-referencing between code and documentation
181
+
182
+ Changed
183
+ -------
184
+
185
+ - **MQTT Module Reorganization**: Consolidated 9 separate modules into cohesive ``mqtt`` package
186
+
187
+ .. code-block:: python
188
+
189
+ # OLD imports (still work via compatibility layer)
190
+ from nwp500.mqtt_client import NavienMqttClient
191
+ from nwp500.mqtt_diagnostics import MqttDiagnosticsCollector
192
+ from nwp500.mqtt_utils import MqttConnectionConfig
193
+
194
+ # NEW imports (preferred)
195
+ from nwp500.mqtt import NavienMqttClient, MqttDiagnosticsCollector, MqttConnectionConfig
196
+ # OR import from main package (recommended)
197
+ from nwp500 import NavienMqttClient, MqttDiagnosticsCollector, MqttConnectionConfig
198
+
199
+ - Created ``src/nwp500/mqtt/`` package with organized submodules
200
+ - Better package organization and structure
201
+ - Clearer public vs internal APIs
202
+ - New ``mqtt/__init__.py`` with clean public API exports
203
+ - Backward compatibility maintained via main package exports
204
+ - All 209 tests pass with zero type checking errors
205
+
206
+ - **CLI Framework Migration**: Migrated from argparse to Click framework
207
+
208
+ - Implemented ``async_command`` decorator for automatic loop and connection management
209
+ - Added support for command groups (reservations, tou)
210
+ - Improved argument and option parsing with built-in validation
211
+ - Enhanced help text and version reporting
212
+ - Centralized command registry in ``src/nwp500/cli/commands.py``
213
+ - Reorganized CLI handlers into ``src/nwp500/cli/handlers.py``
214
+ - Better separation of concerns between CLI framework and business logic
215
+ - Industry-standard CLI framework with better maintainability
216
+ - Added click>=8.0.0 dependency
217
+
218
+ - **Examples Reorganization**: Restructured examples into beginner/intermediate/advanced/testing categories
219
+
220
+ - Created structured hierarchy in ``examples/`` directory
221
+ - Renamed and moved 35+ example scripts for better discoverability
222
+ - Updated ``examples/README.md`` with 'Getting Started' guide and categorized index
223
+ - Added 01-04 beginner series for smooth onboarding:
224
+
225
+ - ``beginner/01_authentication.py`` - Basic authentication patterns
226
+ - ``beginner/02_list_devices.py`` - Retrieving device information
227
+ - ``beginner/03_get_status.py`` - Getting device status
228
+ - ``beginner/04_set_temperature.py`` - Basic device control
229
+
230
+ - Intermediate examples: event-driven control, error handling, MQTT monitoring
231
+ - Advanced examples: demand response, recirculation, TOU schedules, diagnostics
232
+ - Testing examples: connection testing, periodic updates, minimal examples
233
+ - All examples updated with correct imports for new package structure
234
+
235
+ - **Authentication Documentation**: Major improvements to authentication guide
236
+
237
+ - Complete rewrite of ``docs/guides/authentication.rst``
238
+ - Added factory function patterns and examples
239
+ - Improved context manager documentation
240
+ - Added best practices and common patterns
241
+ - More comprehensive code examples
242
+
243
+ - **Model Refactoring**: Updated to use new converter modules
244
+
245
+ - Replaced 53 lines of scattered validators with imports
246
+ - Updated ``fahrenheit_to_half_celsius()`` to use ``HalfCelsius`` class
247
+ - Cleaner model definitions with centralized conversion logic
248
+ - No breaking changes to public API
249
+
250
+ - **CLI Output Formatter Refactoring**: Restructured ``print_device_status()`` to use dynamic unit extraction
251
+
252
+ - Reduced code duplication by ~400 lines
253
+ - Improved maintainability: field additions automatically get correct units
254
+ - No breaking changes to CLI output format or behavior
255
+
256
+ - **Type Annotations**: Improved type safety across entire codebase
257
+
258
+ - Fixed datetime imports to use ``datetime.UTC`` (Python 3.13)
259
+ - Fixed type annotations in ``rich_output.py`` for optional dependencies
260
+ - Fixed type narrowing issues in ``encoding.py``
261
+ - Updated ``MqttConnection`` callback signature to use ``AwsCrtError``
262
+ - Added public properties and setters where needed for type checking
263
+
264
+ Fixed
265
+ -----
266
+
267
+ - **Superheat Temperature Units**: Target and Current SuperHeat now correctly display in °F instead of °C
268
+
269
+ - Both fields use ``DeciCelsiusToF`` conversion, now properly reflected in CLI output
270
+ - Fields were displaying inconsistent units compared to all other temperature readings
271
+
272
+ - **Missing CLI Output Units**: Multiple fields now display with proper units from model metadata
273
+
274
+ - ``current_dhw_flow_rate``: Now shows GPM unit
275
+ - ``total_energy_capacity``: Now shows Wh unit
276
+ - ``available_energy_capacity``: Now shows Wh unit
277
+ - ``dr_override_status``: Now shows hours unit
278
+ - ``vacation_day_setting``: Now shows days unit
279
+ - ``vacation_day_elapsed``: Now shows days unit
280
+ - ``anti_legionella_period``: Fixed to show days unit (was incorrectly h)
281
+ - ``wifi_rssi``: Now shows dBm unit
282
+
283
+ - **Invalid MQTT Topic Filter**: Fixed ``reservations get`` command subscription topic
284
+
285
+ - Changed invalid topic pattern ``cmd/52/navilink-+/#`` to valid ``cmd/52/+/#``
286
+ - AWS IoT Core MQTT does not support wildcards within topic segments
287
+ - Affected: ``handle_get_reservations_request()`` in commands.py
288
+
289
+ - **DeviceFeature Documentation**: Clarified field descriptions and fixed documentation errors
290
+
291
+ - Fixed ``country_code`` documentation (actual value is 3, not 1 as previously noted)
292
+ - Clarified ``model_type_code``, ``control_type_code``, ``recirc_model_type_code`` field purposes
293
+ - Updated ``volume_code`` to use new ``VolumeCode`` enum with validation
294
+
295
+ - **Type Checking Errors**: Resolved all pyright type checking errors in source code
296
+
297
+ - Fixed datetime imports and type annotations
298
+ - Added missing public properties and setters
299
+ - Removed unused imports and variables
300
+ - All source code now passes strict type checking
301
+
5
302
  Version 7.1.0 (2025-12-22)
6
303
  ==========================
7
304
 
@@ -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.1
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
 
@@ -112,9 +144,12 @@ The library includes a command line interface for monitoring and controlling you
112
144
  # Get current device status
113
145
  python3 -m nwp500.cli status
114
146
 
115
- # Get device information and firmware
147
+ # Get device information and firmware (via MQTT - DeviceFeature)
116
148
  python3 -m nwp500.cli info
117
149
 
150
+ # Get basic device info from REST API (DeviceInfo)
151
+ python3 -m nwp500.cli device-info
152
+
118
153
  # Get controller serial number
119
154
  python3 -m nwp500.cli serial
120
155
 
@@ -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
 
@@ -76,9 +104,12 @@ The library includes a command line interface for monitoring and controlling you
76
104
  # Get current device status
77
105
  python3 -m nwp500.cli status
78
106
 
79
- # Get device information and firmware
107
+ # Get device information and firmware (via MQTT - DeviceFeature)
80
108
  python3 -m nwp500.cli info
81
109
 
110
+ # Get basic device info from REST API (DeviceInfo)
111
+ python3 -m nwp500.cli device-info
112
+
82
113
  # Get controller serial number
83
114
  python3 -m nwp500.cli serial
84
115