Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,74 @@ Changelog
Unreleased
==========

**BREAKING CHANGES**: Public API surface trimmed and dead code removed.
These changes require a major version bump.

Removed
-------
- **Deprecated ``.control`` property**: removed
``NavienMqttClient.control`` (deprecated shim slated for v9.0.0; the
project policy is to remove rather than deprecate). Use the delegated
methods on the client directly:

.. code-block:: python

# OLD (removed)
await client.control.set_power(device, True)

# NEW
await client.set_power(device, True)

- **Unused exception classes**: removed ``TokenExpiredError``,
``MqttSubscriptionError``, ``DeviceNotFoundError``,
``DeviceOfflineError``, and ``DeviceOperationError``. None of them was
ever raised by the library, so no working error handling can break;
catch the parent classes (``AuthenticationError``, ``MqttError``,
``DeviceError``) instead.
- **Internal plumbing removed from the top-level namespace**: the
package no longer re-exports ``requires_capability``,
``MqttDeviceInfoCache``, ``MqttDeviceCapabilityChecker``,
``log_performance``, or the bit-encoding helpers
(``encode_week_bitfield``, ``decode_week_bitfield``,
``encode_season_bitfield``, ``decode_season_bitfield``,
``encode_price``, ``decode_price``, ``build_reservation_entry``,
``build_tou_period``). Import them from their owning modules:

.. code-block:: python

# OLD (removed)
from nwp500 import build_reservation_entry, encode_price

# NEW
from nwp500.encoding import build_reservation_entry, encode_price

- **Dead code**: removed the never-imported ``nwp500.cli.commands``
module (its metadata had drifted from the real click commands), the
unused ``converters.str_enum_validator``, the unused module-level
``temperature.half_celsius_to_fahrenheit`` /
``deci_celsius_to_fahrenheit`` wrappers, the no-op
``NavienMqttClient._on_message_received`` placeholder, and unused
width calculations in the CLI formatters.

Changed
-------
- **Temperature classes deduplicated**: ``HalfCelsius``, ``DeciCelsius``,
``RawCelsius``, and ``DeciCelsiusDelta`` were four near-identical
copies differing only in a scale constant. All conversions are now
implemented once on the ``Temperature`` base class with a per-class
``_scale``; only special rounding (``RawCelsius``) and delta semantics
(``DeciCelsiusDelta``) are overridden. Behavior is unchanged
(~200 lines removed).
- **field_factory deduplicated**: the four field factories shared a
copy-pasted metadata-merge block, now extracted into a single private
helper. Behavior is unchanged.
- **Device boolean encoding centralized**: ``mqtt/control.py`` now uses
``converters.device_bool_from_python()`` instead of inline
``2 if enabled else 1`` literals.
- **Version resolution decoupled**: ``auth.py`` resolves the package
version from distribution metadata instead of ``from . import
__version__``, removing an order-dependent near-circular import.

Bug Fixes
---------
- **Fix malformed weekly reservation and recirculation schedule
Expand Down
13 changes: 7 additions & 6 deletions docs/how-to/optimize-tou.rst
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ Encodes a floating-point price into an integer for transmission.

.. code-block:: python

from nwp500 import encode_price
from nwp500.encoding import encode_price

# Encode $0.45000 per kWh
encoded = encode_price(0.45, decimal_point=5)
Expand All @@ -437,7 +437,7 @@ Decodes an integer price back to floating-point.

.. code-block:: python

from nwp500 import decode_price
from nwp500.encoding import decode_price

# Decode price from device
price = decode_price(45000, decimal_point=5)
Expand Down Expand Up @@ -466,7 +466,7 @@ Encodes a list of day names into a bitfield.

.. code-block:: python

from nwp500 import encode_week_bitfield
from nwp500.encoding import encode_week_bitfield

# Weekdays only
bitfield = encode_week_bitfield([
Expand All @@ -487,7 +487,7 @@ Decodes a bitfield back into a list of day names.

.. code-block:: python

from nwp500 import decode_week_bitfield
from nwp500.encoding import decode_week_bitfield

# Decode weekday bitfield
days = decode_week_bitfield(62)
Expand All @@ -504,7 +504,8 @@ Configure two rate periods - off-peak and peak pricing:
.. code-block:: python

import asyncio
from nwp500 import NavienAPIClient, NavienAuthClient, NavienMqttClient, build_tou_period
from nwp500 import NavienAPIClient, NavienAuthClient, NavienMqttClient
from nwp500.encoding import build_tou_period

async def configure_simple_tou():
async with NavienAuthClient("user@example.com", "password") as auth_client:
Expand Down Expand Up @@ -654,7 +655,7 @@ Query the device for its current TOU configuration:

.. code-block:: python

from nwp500 import decode_week_bitfield, decode_price
from nwp500.encoding import decode_week_bitfield, decode_price

async def check_tou_settings():
async with NavienAuthClient("user@example.com", "password") as auth_client:
Expand Down
6 changes: 3 additions & 3 deletions docs/how-to/schedule-operation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ Quick Example
NavienAuthClient,
NavienAPIClient,
NavienMqttClient,
build_reservation_entry,
)
from nwp500.encoding import build_reservation_entry

async def main():
async with NavienAuthClient(
Expand Down Expand Up @@ -279,7 +279,7 @@ Helper Functions

.. code-block:: python

from nwp500 import build_reservation_entry
from nwp500.encoding import build_reservation_entry

entry = build_reservation_entry(
enabled=True,
Expand Down Expand Up @@ -589,8 +589,8 @@ want to send the whole weekly program as one typed object.
from nwp500 import (
WeeklyReservationEntry,
WeeklyReservationSchedule,
build_reservation_entry,
)
from nwp500.encoding import build_reservation_entry

morning = WeeklyReservationEntry.model_validate(
build_reservation_entry(
Expand Down
4 changes: 0 additions & 4 deletions docs/reference/python_api/auth_client.rst
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,6 @@ Error Handling

from nwp500 import (
InvalidCredentialsError,
TokenExpiredError,
TokenRefreshError,
AuthenticationError
)
Expand All @@ -543,9 +542,6 @@ Error Handling
except InvalidCredentialsError:
print("Wrong email or password")

except TokenExpiredError:
print("Token expired and refresh failed")

except TokenRefreshError:
print("Could not refresh token - sign in again")

Expand Down
57 changes: 0 additions & 57 deletions docs/reference/python_api/exceptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,17 @@ All library exceptions inherit from ``Nwp500Error``::
Nwp500Error (base)
├── AuthenticationError
│ ├── InvalidCredentialsError
│ ├── TokenExpiredError
│ └── TokenRefreshError
├── APIError
├── MqttError
│ ├── MqttConnectionError
│ ├── MqttNotConnectedError
│ ├── MqttPublishError
│ ├── MqttSubscriptionError
│ └── MqttCredentialsError
├── ValidationError
│ ├── ParameterValidationError
│ └── RangeValidationError
└── DeviceError
├── DeviceNotFoundError
├── DeviceOfflineError
├── DeviceOperationError
└── DeviceCapabilityError

Base Exception
Expand Down Expand Up @@ -134,16 +129,6 @@ InvalidCredentialsError
print("Please check your email and password")
# Prompt user to re-enter credentials

TokenExpiredError
-----------------

.. py:class:: TokenExpiredError

Raised when an authentication token has expired.

Subclass of :py:class:`AuthenticationError`. Tokens have a limited lifetime
and must be refreshed periodically.

TokenRefreshError
-----------------

Expand Down Expand Up @@ -305,16 +290,6 @@ MqttPublishError
else:
raise # Not retriable or max retries reached

MqttSubscriptionError
---------------------

.. py:class:: MqttSubscriptionError

Failed to subscribe to MQTT topic.

Raised when subscription to an MQTT topic fails. This may occur if the
connection is interrupted or if the client lacks permissions for the topic.

MqttCredentialsError
--------------------

Expand Down Expand Up @@ -409,38 +384,6 @@ DeviceError

All device-related errors inherit from this base class.

DeviceNotFoundError
-------------------

.. py:class:: DeviceNotFoundError

Requested device not found.

Raised when a device cannot be found in the user's device list or when
attempting to access a non-existent device.

DeviceOfflineError
------------------

.. py:class:: DeviceOfflineError

Device is offline or unreachable.

Raised when a device is offline and cannot respond to commands or status
requests. The device may be powered off, disconnected from the network,
or experiencing connectivity issues.

DeviceOperationError
--------------------

.. py:class:: DeviceOperationError

Device operation failed.

Raised when a device operation (mode change, temperature setting, etc.)
fails. This may occur due to invalid commands, device restrictions, or
device-side errors.

DeviceCapabilityError
---------------------

Expand Down
2 changes: 1 addition & 1 deletion docs/reference/python_api/mqtt_client.rst
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ update_reservations()

.. code-block:: python

from nwp500 import build_reservation_entry
from nwp500.encoding import build_reservation_entry

reservations = [
build_reservation_entry(
Expand Down
2 changes: 2 additions & 0 deletions examples/advanced/tou_openei.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
NavienAuthClient,
NavienMqttClient,
OpenEIClient,
)
from nwp500.encoding import (
decode_price,
decode_week_bitfield,
)
Expand Down
48 changes: 1 addition & 47 deletions src/nwp500/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,6 @@
authenticate,
refresh_access_token,
)
from nwp500.command_decorators import (
requires_capability,
)
from nwp500.device_capabilities import (
MqttDeviceCapabilityChecker,
)
from nwp500.device_info_cache import (
MqttDeviceInfoCache,
)
from nwp500.encoding import (
build_reservation_entry,
build_tou_period,
decode_price,
decode_season_bitfield,
decode_week_bitfield,
encode_price,
encode_season_bitfield,
encode_week_bitfield,
)
from nwp500.enums import (
CommandCode,
CurrentOperationMode,
Expand Down Expand Up @@ -79,20 +60,15 @@
AuthenticationError,
DeviceCapabilityError,
DeviceError,
DeviceNotFoundError,
DeviceOfflineError,
DeviceOperationError,
InvalidCredentialsError,
MqttConnectionError,
MqttCredentialsError,
MqttError,
MqttNotConnectedError,
MqttPublishError,
MqttSubscriptionError,
Nwp500Error,
ParameterValidationError,
RangeValidationError,
TokenExpiredError,
TokenRefreshError,
ValidationError,
)
Expand Down Expand Up @@ -154,17 +130,11 @@
reset_unit_system,
set_unit_system,
)
from nwp500.utils import (
log_performance,
)

__all__ = [
"__version__",
# Device Capabilities & Caching
"MqttDeviceCapabilityChecker",
# Device Capabilities
"DeviceCapabilityError",
"MqttDeviceInfoCache",
"requires_capability",
# Factory functions
"create_navien_clients",
# Models
Expand Down Expand Up @@ -225,22 +195,17 @@
"Nwp500Error",
"AuthenticationError",
"InvalidCredentialsError",
"TokenExpiredError",
"TokenRefreshError",
"APIError",
"MqttError",
"MqttConnectionError",
"MqttNotConnectedError",
"MqttPublishError",
"MqttSubscriptionError",
"MqttCredentialsError",
"ValidationError",
"ParameterValidationError",
"RangeValidationError",
"DeviceError",
"DeviceNotFoundError",
"DeviceOfflineError",
"DeviceOperationError",
# API Client
"NavienAPIClient",
# OpenEI Client
Expand All @@ -262,17 +227,6 @@
"EventEmitter",
"EventListener",
"MqttClientEvents",
# Encoding utilities
"encode_week_bitfield",
"decode_week_bitfield",
"encode_season_bitfield",
"decode_season_bitfield",
"encode_price",
"decode_price",
"build_reservation_entry",
"build_tou_period",
# Utilities
"log_performance",
# Unit system management
"set_unit_system",
"get_unit_system",
Expand Down
Loading
Loading