nwp500-python 1.1.2__tar.gz → 1.1.3__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 (91) hide show
  1. {nwp500_python-1.1.2/src/nwp500_python.egg-info → nwp500_python-1.1.3}/PKG-INFO +1 -1
  2. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/DEVICE_STATUS_FIELDS.rst +53 -53
  3. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/src/nwp500/cli.py +46 -0
  4. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/src/nwp500/models.py +45 -19
  5. {nwp500_python-1.1.2 → nwp500_python-1.1.3/src/nwp500_python.egg-info}/PKG-INFO +1 -1
  6. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/.coveragerc +0 -0
  7. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/.github/copilot-instructions.md +0 -0
  8. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/.github/workflows/ci.yml +0 -0
  9. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/.github/workflows/release.yml +0 -0
  10. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/.gitignore +0 -0
  11. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/.pre-commit-config.yaml +0 -0
  12. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/.readthedocs.yml +0 -0
  13. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/AUTHORS.rst +0 -0
  14. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/CHANGELOG.rst +0 -0
  15. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/CONTRIBUTING.rst +0 -0
  16. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/LICENSE.txt +0 -0
  17. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/Makefile +0 -0
  18. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/README.rst +0 -0
  19. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/RELEASE.md +0 -0
  20. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/API_CLIENT.rst +0 -0
  21. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/API_REFERENCE.rst +0 -0
  22. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/AUTHENTICATION.rst +0 -0
  23. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/COMMAND_QUEUE.rst +0 -0
  24. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/DEVELOPMENT.rst +0 -0
  25. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/DEVICE_FEATURE_FIELDS.rst +0 -0
  26. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/ENERGY_MONITORING.rst +0 -0
  27. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/ERROR_CODES.rst +0 -0
  28. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/EVENT_EMITTER.rst +0 -0
  29. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/MQTT_CLIENT.rst +0 -0
  30. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/MQTT_MESSAGES.rst +0 -0
  31. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/Makefile +0 -0
  32. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/_static/.gitignore +0 -0
  33. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/authors.rst +0 -0
  34. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/changelog.rst +0 -0
  35. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/conf.py +0 -0
  36. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/contributing.rst +0 -0
  37. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/index.rst +0 -0
  38. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/license.rst +0 -0
  39. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/openapi.yaml +0 -0
  40. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/readme.rst +0 -0
  41. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/docs/requirements.txt +0 -0
  42. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/.ruff.toml +0 -0
  43. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/README.md +0 -0
  44. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/api_client_example.py +0 -0
  45. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/auth_constructor_example.py +0 -0
  46. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/authenticate.py +0 -0
  47. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/combined_callbacks.py +0 -0
  48. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/command_queue_demo.py +0 -0
  49. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/device_feature_callback.py +0 -0
  50. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/device_status_callback.py +0 -0
  51. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/device_status_callback_debug.py +0 -0
  52. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/energy_usage_example.py +0 -0
  53. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/event_emitter_demo.py +0 -0
  54. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/improved_auth_pattern.py +0 -0
  55. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/mask.py +0 -0
  56. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/mqtt_client_example.py +0 -0
  57. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/periodic_device_info.py +0 -0
  58. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/periodic_requests.py +0 -0
  59. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/power_control_example.py +0 -0
  60. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/reconnection_demo.py +0 -0
  61. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/set_dhw_temperature_example.py +0 -0
  62. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/set_mode_example.py +0 -0
  63. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/simple_periodic_info.py +0 -0
  64. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/simple_periodic_status.py +0 -0
  65. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/test_api_client.py +0 -0
  66. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/test_mqtt_connection.py +0 -0
  67. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/test_mqtt_messaging.py +0 -0
  68. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/examples/test_periodic_minimal.py +0 -0
  69. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/pyproject.toml +0 -0
  70. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/scripts/format.py +0 -0
  71. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/scripts/lint.py +0 -0
  72. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/scripts/setup-dev.py +0 -0
  73. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/setup.cfg +0 -0
  74. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/setup.py +0 -0
  75. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/src/nwp500/__init__.py +0 -0
  76. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/src/nwp500/api_client.py +0 -0
  77. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/src/nwp500/auth.py +0 -0
  78. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/src/nwp500/config.py +0 -0
  79. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/src/nwp500/constants.py +0 -0
  80. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/src/nwp500/events.py +0 -0
  81. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/src/nwp500/mqtt_client.py +0 -0
  82. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/src/nwp500_python.egg-info/SOURCES.txt +0 -0
  83. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/src/nwp500_python.egg-info/dependency_links.txt +0 -0
  84. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/src/nwp500_python.egg-info/entry_points.txt +0 -0
  85. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/src/nwp500_python.egg-info/not-zip-safe +0 -0
  86. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/src/nwp500_python.egg-info/requires.txt +0 -0
  87. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/src/nwp500_python.egg-info/top_level.txt +0 -0
  88. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/tests/conftest.py +0 -0
  89. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/tests/test_command_queue.py +0 -0
  90. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/tests/test_events.py +0 -0
  91. {nwp500_python-1.1.2 → nwp500_python-1.1.3}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nwp500-python
3
- Version: 1.1.2
3
+ Version: 1.1.3
4
4
  Summary: Add a short description here!
5
5
  Home-page: https://github.com/pyscaffold/pyscaffold/
6
6
  Author: Emmanuel Levijarvi
@@ -29,10 +29,10 @@ This document lists the fields found in the ``status`` object of device status m
29
29
  - Status of special functions (e.g., freeze protection, anti-seize operations).
30
30
  - None
31
31
  * - ``didReload``
32
- - integer
32
+ - bool
33
33
  - None
34
34
  - Indicates if the device has recently reloaded or restarted.
35
- - None
35
+ - Converted from integer (1=OFF, 2=ON) to bool
36
36
  * - ``errorCode``
37
37
  - integer
38
38
  - None
@@ -49,25 +49,25 @@ This document lists the fields found in the ``status`` object of device status m
49
49
  - The current **actual operational state** of the device (what it's doing RIGHT NOW). Reports status values: 0=Standby, 32=Heat Pump active, 64=Energy Saver active, 96=High Demand active. See Operation Modes section below for the critical distinction between this and ``dhwOperationSetting``.
50
50
  - None
51
51
  * - ``operationBusy``
52
- - integer
53
- - None
54
- - Indicates if the device is currently performing heating operations (1=busy, 0=idle).
52
+ - bool
55
53
  - None
54
+ - Indicates if the device is currently performing heating operations (True=busy, False=idle).
55
+ - Converted from integer (1=OFF, 2=ON) to bool
56
56
  * - ``freezeProtectionUse``
57
- - integer
57
+ - bool
58
58
  - None
59
59
  - Whether freeze protection is active. When tank water temperature falls below 43°F (6°C), the electric heater activates to prevent freezing.
60
- - None
60
+ - Converted from integer (1=OFF, 2=ON) to bool
61
61
  * - ``dhwUse``
62
- - integer
62
+ - bool
63
63
  - None
64
64
  - Domestic Hot Water (DHW) usage status - indicates if hot water is currently being drawn from the tank.
65
- - None
65
+ - Converted from integer (1=OFF, 2=ON) to bool
66
66
  * - ``dhwUseSustained``
67
- - integer
67
+ - bool
68
68
  - None
69
69
  - Sustained DHW usage status - indicates prolonged hot water usage.
70
- - None
70
+ - Converted from integer (1=OFF, 2=ON) to bool
71
71
  * - ``dhwTemperature``
72
72
  - integer
73
73
  - °F
@@ -79,10 +79,10 @@ This document lists the fields found in the ``status`` object of device status m
79
79
  - Target DHW temperature setting. Range: 95°F (35°C) to 150°F (65.5°C). Default: 120°F (49°C).
80
80
  - ``raw + 20``
81
81
  * - ``programReservationUse``
82
- - integer
82
+ - bool
83
83
  - None
84
84
  - Whether a program reservation (scheduled operation) is in use.
85
- - None
85
+ - Converted from integer (1=OFF, 2=ON) to bool
86
86
  * - ``smartDiagnostic``
87
87
  - integer
88
88
  - None
@@ -104,10 +104,10 @@ This document lists the fields found in the ``status`` object of device status m
104
104
  - WiFi signal strength in dBm (decibel-milliwatts). Typical values: -30 (excellent) to -90 (poor).
105
105
  - None
106
106
  * - ``ecoUse``
107
- - integer
107
+ - bool
108
108
  - None
109
109
  - Whether ECO (Energy Cut Off) safety feature has been triggered. The ECO switch is a high-temperature safety limit.
110
- - None
110
+ - Converted from integer (1=OFF, 2=ON) to bool
111
111
  * - ``dhwTargetTemperatureSetting``
112
112
  - integer
113
113
  - °F
@@ -127,62 +127,62 @@ This document lists the fields found in the ``status`` object of device status m
127
127
  - integer
128
128
  - °F
129
129
  - Compressor discharge temperature - temperature of refrigerant leaving the compressor.
130
- - ``raw / 10.0``
130
+ - ``(raw / 10) * 9/5 + 32`` (decicelsius to Fahrenheit)
131
131
  * - ``suctionTemperature``
132
132
  - integer
133
133
  - °F
134
134
  - Compressor suction temperature - temperature of refrigerant entering the compressor.
135
- - ``raw / 10.0``
135
+ - ``(raw / 10) * 9/5 + 32`` (decicelsius to Fahrenheit)
136
136
  * - ``evaporatorTemperature``
137
137
  - integer
138
138
  - °F
139
139
  - Evaporator temperature - temperature where heat is absorbed from ambient air.
140
- - ``raw / 10.0``
140
+ - ``(raw / 10) * 9/5 + 32`` (decicelsius to Fahrenheit)
141
141
  * - ``ambientTemperature``
142
142
  - integer
143
143
  - °F
144
144
  - Ambient air temperature measured at the heat pump air intake.
145
- - ``(raw / 22.4) * 9/5 + 32``
145
+ - ``(raw / 10) * 9/5 + 32`` (decicelsius to Fahrenheit)
146
146
  * - ``targetSuperHeat``
147
147
  - integer
148
148
  - °F
149
149
  - Target superheat value - the desired temperature difference ensuring complete refrigerant vaporization.
150
150
  - ``raw / 10.0``
151
151
  * - ``compUse``
152
- - integer
153
- - None
154
- - Compressor usage status (1=On, 0=Off). The compressor is the main component of the heat pump.
152
+ - bool
155
153
  - None
154
+ - Compressor usage status (True=On, False=Off). The compressor is the main component of the heat pump.
155
+ - Converted from integer (1=OFF, 2=ON) to bool
156
156
  * - ``eevUse``
157
- - integer
158
- - None
159
- - Electronic Expansion Valve (EEV) usage status (1=active, 0=inactive). The EEV controls refrigerant flow.
157
+ - bool
160
158
  - None
159
+ - Electronic Expansion Valve (EEV) usage status (True=active, False=inactive). The EEV controls refrigerant flow.
160
+ - Converted from integer (1=OFF, 2=ON) to bool
161
161
  * - ``evaFanUse``
162
- - integer
163
- - None
164
- - Evaporator fan usage status (1=On, 0=Off). The fan pulls ambient air through the evaporator coil.
162
+ - bool
165
163
  - None
164
+ - Evaporator fan usage status (True=On, False=Off). The fan pulls ambient air through the evaporator coil.
165
+ - Converted from integer (1=OFF, 2=ON) to bool
166
166
  * - ``currentInstPower``
167
167
  - integer
168
168
  - W
169
169
  - Current instantaneous power consumption in Watts. Does not include heating element power when active.
170
170
  - None
171
171
  * - ``shutOffValveUse``
172
- - integer
172
+ - bool
173
173
  - None
174
174
  - Shut-off valve usage status. The valve controls refrigerant flow in the system.
175
- - None
175
+ - Converted from integer (1=OFF, 2=ON) to bool
176
176
  * - ``conOvrSensorUse``
177
- - integer
177
+ - bool
178
178
  - None
179
179
  - Condensate overflow sensor usage status.
180
- - None
180
+ - Converted from integer (1=OFF, 2=ON) to bool
181
181
  * - ``wtrOvrSensorUse``
182
- - integer
182
+ - bool
183
183
  - None
184
184
  - Water overflow/leak sensor usage status. Triggers error E799 if leak detected.
185
- - None
185
+ - Converted from integer (1=OFF, 2=ON) to bool
186
186
  * - ``dhwChargePer``
187
187
  - integer
188
188
  - %
@@ -209,20 +209,20 @@ This document lists the fields found in the ``status`` object of device status m
209
209
  - Freeze protection temperature setting.
210
210
  - ``raw + 20``
211
211
  * - ``antiLegionellaUse``
212
- - integer
212
+ - bool
213
213
  - None
214
214
  - Whether anti-legionella function is enabled.
215
- - None
215
+ - Converted from integer (1=OFF, 2=ON) to bool
216
216
  * - ``antiLegionellaPeriod``
217
217
  - integer
218
218
  - days
219
219
  - Anti-legionella function period.
220
220
  - None
221
221
  * - ``antiLegionellaOperationBusy``
222
- - integer
222
+ - bool
223
223
  - None
224
224
  - Whether the anti-legionella function is busy.
225
- - None
225
+ - Converted from integer (1=OFF, 2=ON) to bool
226
226
  * - ``programReservationType``
227
227
  - integer
228
228
  - None
@@ -244,15 +244,15 @@ This document lists the fields found in the ``status`` object of device status m
244
244
  - Temperature formula type.
245
245
  - None
246
246
  * - ``errorBuzzerUse``
247
- - integer
247
+ - bool
248
248
  - None
249
249
  - Whether the error buzzer is enabled.
250
- - None
250
+ - Converted from integer (1=OFF, 2=ON) to bool
251
251
  * - ``currentHeatUse``
252
- - integer
252
+ - bool
253
253
  - None
254
254
  - Current heat usage.
255
- - None
255
+ - Converted from integer (1=OFF, 2=ON) to bool
256
256
  * - ``currentInletTemperature``
257
257
  - float
258
258
  - °F
@@ -302,27 +302,27 @@ This document lists the fields found in the ``status`` object of device status m
302
302
  - integer
303
303
  - °F
304
304
  - Current superheat value - actual temperature difference between suction and evaporator temperatures.
305
- - ``raw / 10.0``
305
+ - ``(raw / 10) * 9/5 + 32`` (decicelsius to Fahrenheit)
306
306
  * - ``heatUpperUse``
307
- - integer
308
- - None
309
- - Upper electric heating element usage status (1=On, 0=Off). Power: 3,755W @ 208V or 5,000W @ 240V.
307
+ - bool
310
308
  - None
309
+ - Upper electric heating element usage status (True=On, False=Off). Power: 3,755W @ 208V or 5,000W @ 240V.
310
+ - Converted from integer (1=OFF, 2=ON) to bool
311
311
  * - ``heatLowerUse``
312
- - integer
313
- - None
314
- - Lower electric heating element usage status (1=On, 0=Off). Power: 3,755W @ 208V or 5,000W @ 240V.
312
+ - bool
315
313
  - None
314
+ - Lower electric heating element usage status (True=On, False=Off). Power: 3,755W @ 208V or 5,000W @ 240V.
315
+ - Converted from integer (1=OFF, 2=ON) to bool
316
316
  * - ``scaldUse``
317
- - integer
317
+ - bool
318
318
  - None
319
319
  - Scald protection active status. Displays warning when water temperature reaches levels that could cause scalding.
320
- - None
320
+ - Converted from integer (1=OFF, 2=ON) to bool
321
321
  * - ``airFilterAlarmUse``
322
- - integer
322
+ - bool
323
323
  - None
324
324
  - Air filter alarm usage - indicates if air filter maintenance reminder is enabled.
325
- - None
325
+ - Converted from integer (1=OFF, 2=ON) to bool
326
326
  * - ``airFilterAlarmPeriod``
327
327
  - integer
328
328
  - hours
@@ -205,6 +205,37 @@ async def handle_status_request(mqtt: NavienMqttClient, device: Device):
205
205
  _logger.error("Timed out waiting for device status response.")
206
206
 
207
207
 
208
+ async def handle_status_raw_request(mqtt: NavienMqttClient, device: Device):
209
+ """Request device status once and print raw MQTT data (no conversions)."""
210
+ future = asyncio.get_running_loop().create_future()
211
+
212
+ # Subscribe to the raw MQTT topic to capture data before conversion
213
+ def raw_callback(topic: str, message: dict):
214
+ if not future.done():
215
+ # Extract and print the raw status portion
216
+ if "response" in message and "status" in message["response"]:
217
+ print(
218
+ json.dumps(
219
+ message["response"]["status"], indent=2, default=_json_default_serializer
220
+ )
221
+ )
222
+ future.set_result(None)
223
+ elif "status" in message:
224
+ print(json.dumps(message["status"], indent=2, default=_json_default_serializer))
225
+ future.set_result(None)
226
+
227
+ # Subscribe to all device messages
228
+ await mqtt.subscribe_device(device, raw_callback)
229
+
230
+ _logger.info("Requesting device status (raw)...")
231
+ await mqtt.request_device_status(device)
232
+
233
+ try:
234
+ await asyncio.wait_for(future, timeout=10)
235
+ except asyncio.TimeoutError:
236
+ _logger.error("Timed out waiting for device status response.")
237
+
238
+
208
239
  async def handle_device_info_request(mqtt: NavienMqttClient, device: Device):
209
240
  """
210
241
  Request comprehensive device information via MQTT and print it.
@@ -504,6 +535,9 @@ async def async_main(args: argparse.Namespace):
504
535
  _logger.info("Getting updated status after temperature change...")
505
536
  await asyncio.sleep(2) # Brief pause for device to process
506
537
  await handle_status_request(mqtt, device)
538
+ elif args.status_raw:
539
+ # Raw status request (no conversions)
540
+ await handle_status_raw_request(mqtt, device)
507
541
  elif args.status:
508
542
  # Status-only request
509
543
  await handle_status_request(mqtt, device)
@@ -549,6 +583,12 @@ def parse_args(args):
549
583
  action="store_true",
550
584
  help="Fetch and print the current device status. Can be combined with control commands.",
551
585
  )
586
+ parser.add_argument(
587
+ "--status-raw",
588
+ action="store_true",
589
+ help="Fetch and print the raw device status as received from MQTT "
590
+ "(no conversions applied).",
591
+ )
552
592
 
553
593
  # Primary action modes (mutually exclusive)
554
594
  group = parser.add_mutually_exclusive_group()
@@ -635,6 +675,12 @@ def setup_logging(loglevel):
635
675
  def main(args):
636
676
  """Wrapper for the asynchronous main function."""
637
677
  args = parse_args(args)
678
+
679
+ # Validate that --status and --status-raw are not used together
680
+ if args.status and args.status_raw:
681
+ print("Error: --status and --status-raw cannot be used together.", file=sys.stderr)
682
+ return 1
683
+
638
684
  # Set default log level for libraries
639
685
  setup_logging(logging.WARNING)
640
686
  # Set user-defined log level for this script
@@ -13,6 +13,24 @@ from typing import Any, Optional, Union
13
13
  _logger = logging.getLogger(__name__)
14
14
 
15
15
 
16
+ def _decicelsius_to_fahrenheit(raw_value: float) -> float:
17
+ """
18
+ Convert a raw decicelsius value to Fahrenheit.
19
+
20
+ Args:
21
+ raw_value: Raw value in decicelsius (tenths of degrees Celsius)
22
+
23
+ Returns:
24
+ Temperature in Fahrenheit
25
+
26
+ Example:
27
+ >>> _decicelsius_to_fahrenheit(250) # 25.0°C
28
+ 77.0
29
+ """
30
+ celsius = raw_value / 10.0
31
+ return (celsius * 9 / 5) + 32
32
+
33
+
16
34
  class OperationMode(Enum):
17
35
  """Enumeration for the operation modes of the device.
18
36
 
@@ -306,6 +324,11 @@ class DeviceStatus:
306
324
  )
307
325
 
308
326
  # Convert integer-based booleans
327
+ # The device uses a non-standard encoding for boolean values:
328
+ # 0 = Not applicable/disabled (rarely used)
329
+ # 1 = OFF/Inactive/False
330
+ # 2 = ON/Active/True
331
+ # This applies to ALL boolean fields in the device status
309
332
  bool_fields = [
310
333
  "didReload",
311
334
  "operationBusy",
@@ -329,9 +352,11 @@ class DeviceStatus:
329
352
  "scaldUse",
330
353
  "airFilterAlarmUse",
331
354
  ]
355
+
356
+ # Convert using the device's encoding: 0 or 1=false, 2=true
332
357
  for field_name in bool_fields:
333
358
  if field_name in converted_data:
334
- converted_data[field_name] = bool(converted_data[field_name])
359
+ converted_data[field_name] = converted_data[field_name] == 2
335
360
 
336
361
  # Convert temperatures with 'raw + 20' formula
337
362
  add_20_fields = [
@@ -353,15 +378,11 @@ class DeviceStatus:
353
378
  if field_name in converted_data:
354
379
  converted_data[field_name] += 20
355
380
 
356
- # Convert fields with 'raw / 10.0' formula
381
+ # Convert fields with 'raw / 10.0' formula (non-temperature fields)
357
382
  div_10_fields = [
358
- "dischargeTemperature",
359
- "suctionTemperature",
360
- "evaporatorTemperature",
361
383
  "targetSuperHeat",
362
384
  "currentInletTemperature",
363
385
  "currentDhwFlowRate",
364
- "currentSuperHeat",
365
386
  "hpUpperOnDiffTempSetting",
366
387
  "hpUpperOffDiffTempSetting",
367
388
  "hpLowerOnDiffTempSetting",
@@ -375,23 +396,28 @@ class DeviceStatus:
375
396
  if field_name in converted_data:
376
397
  converted_data[field_name] /= 10.0
377
398
 
378
- # Special conversion for ambientTemperature
379
- if "ambientTemperature" in converted_data:
380
- raw_temp = converted_data["ambientTemperature"]
381
- # Based on observed data: raw 503.6 corresponds to 72.5°F
382
- # Convert raw value to Celsius first (raw / 22.4 ≈ Celsius)
383
- # Then convert Celsius to Fahrenheit
384
- celsius = raw_temp / 22.4
385
- converted_data["ambientTemperature"] = (celsius * 9 / 5) + 32
386
-
387
399
  # Special conversion for tank temperatures (decicelsius to Fahrenheit)
388
400
  tank_temp_fields = ["tankUpperTemperature", "tankLowerTemperature"]
389
401
  for field_name in tank_temp_fields:
390
402
  if field_name in converted_data:
391
- raw_temp = converted_data[field_name]
392
- # Convert from decicelsius (raw / 10.0) to Celsius, then to Fahrenheit
393
- celsius = raw_temp / 10.0
394
- converted_data[field_name] = (celsius * 9 / 5) + 32
403
+ converted_data[field_name] = _decicelsius_to_fahrenheit(converted_data[field_name])
404
+
405
+ # Special conversion for dischargeTemperature (decicelsius to Fahrenheit)
406
+ if "dischargeTemperature" in converted_data:
407
+ converted_data["dischargeTemperature"] = _decicelsius_to_fahrenheit(
408
+ converted_data["dischargeTemperature"]
409
+ )
410
+
411
+ # Special conversion for heat pump temperatures (decicelsius to Fahrenheit)
412
+ heat_pump_temp_fields = [
413
+ "suctionTemperature",
414
+ "evaporatorTemperature",
415
+ "ambientTemperature",
416
+ "currentSuperHeat",
417
+ ]
418
+ for field_name in heat_pump_temp_fields:
419
+ if field_name in converted_data:
420
+ converted_data[field_name] = _decicelsius_to_fahrenheit(converted_data[field_name])
395
421
 
396
422
  # Convert enum fields with error handling for unknown values
397
423
  if "operationMode" in converted_data:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nwp500-python
3
- Version: 1.1.2
3
+ Version: 1.1.3
4
4
  Summary: Add a short description here!
5
5
  Home-page: https://github.com/pyscaffold/pyscaffold/
6
6
  Author: Emmanuel Levijarvi
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes