diff --git a/src/nwp500/api_client.py b/src/nwp500/api_client.py index dda12f6..bec1e5f 100644 --- a/src/nwp500/api_client.py +++ b/src/nwp500/api_client.py @@ -50,7 +50,7 @@ def __init__( auth_client: NavienAuthClient, base_url: str = API_BASE_URL, session: aiohttp.ClientSession | None = None, - unit_system: Literal["metric", "imperial"] | None = None, + unit_system: Literal["metric", "us_customary"] | None = None, ): """ Initialize Navien API client. @@ -63,7 +63,8 @@ def __init__( provided) unit_system: Preferred unit system: - "metric": Celsius, LPM, Liters - - "imperial": Fahrenheit, GPM, Gallons + - "us_customary": Fahrenheit, GPM, Gallons + - None: Auto-detect from device (default) Raises: diff --git a/src/nwp500/auth.py b/src/nwp500/auth.py index 8db9450..1a93bb7 100644 --- a/src/nwp500/auth.py +++ b/src/nwp500/auth.py @@ -289,7 +289,7 @@ def __init__( session: aiohttp.ClientSession | None = None, timeout: int = 30, stored_tokens: AuthTokens | None = None, - unit_system: Literal["metric", "imperial"] | None = None, + unit_system: Literal["metric", "us_customary"] | None = None, ): """ Initialize the authentication client. @@ -304,7 +304,8 @@ def __init__( If provided and valid, skips initial sign_in. unit_system: Preferred unit system: - "metric": Celsius, LPM, Liters - - "imperial": Fahrenheit, GPM, Gallons + - "us_customary": Fahrenheit, GPM, Gallons + - None: Auto-detect from device (default) Note: diff --git a/src/nwp500/cli/__main__.py b/src/nwp500/cli/__main__.py index 0bcf6ee..54b9430 100644 --- a/src/nwp500/cli/__main__.py +++ b/src/nwp500/cli/__main__.py @@ -129,8 +129,8 @@ async def runner() -> int: ) @click.option( "--unit-system", - type=click.Choice(["metric", "imperial"], case_sensitive=False), - help="Unit system: metric (C/LPM/L) or imperial (F/GPM/gal)", + type=click.Choice(["metric", "us_customary"], case_sensitive=False), + help="Unit system: metric (C/LPM/L) or us_customary (F/GPM/gal)", ) @click.option("-v", "--verbose", count=True, help="Increase verbosity") @click.version_option(version=__version__) diff --git a/src/nwp500/mqtt/client.py b/src/nwp500/mqtt/client.py index fa9d725..701274a 100644 --- a/src/nwp500/mqtt/client.py +++ b/src/nwp500/mqtt/client.py @@ -16,7 +16,7 @@ import logging import uuid from collections.abc import Callable -from typing import TYPE_CHECKING, Any, Literal, cast +from typing import TYPE_CHECKING, Any, cast from awscrt import mqtt from awscrt.exceptions import AwsCrtError @@ -31,15 +31,7 @@ MqttPublishError, TokenRefreshError, ) -from ..unit_system import set_unit_system - -if TYPE_CHECKING: - from ..models import ( - Device, - DeviceFeature, - DeviceStatus, - EnergyUsageResponse, - ) +from ..unit_system import UnitSystemType, set_unit_system from .command_queue import MqttCommandQueue from .connection import MqttConnection from .control import MqttDeviceController @@ -52,6 +44,14 @@ PeriodicRequestType, ) +if TYPE_CHECKING: + from ..models import ( + Device, + DeviceFeature, + DeviceStatus, + EnergyUsageResponse, + ) + __author__ = "Emmanuel Levijarvi" __copyright__ = "Emmanuel Levijarvi" __license__ = "MIT" @@ -136,7 +136,7 @@ def __init__( self, auth_client: NavienAuthClient, config: MqttConnectionConfig | None = None, - unit_system: Literal["metric", "imperial"] | None = None, + unit_system: UnitSystemType = None, ): """ Initialize the MQTT client. @@ -146,7 +146,8 @@ def __init__( config: Optional connection configuration unit_system: Preferred unit system: - "metric": Celsius, LPM, Liters - - "imperial": Fahrenheit, GPM, Gallons + - "us_customary": Fahrenheit, GPM, Gallons + - None: Auto-detect from device (default) Raises: @@ -184,7 +185,7 @@ def __init__( set_unit_system(unit_system) self._auth_client = auth_client - self._unit_system: Literal["metric", "imperial"] | None = unit_system + self._unit_system: UnitSystemType = unit_system self.config = config or MqttConnectionConfig() # Session tracking diff --git a/src/nwp500/mqtt/subscriptions.py b/src/nwp500/mqtt/subscriptions.py index 1a293ea..bfb5cf8 100644 --- a/src/nwp500/mqtt/subscriptions.py +++ b/src/nwp500/mqtt/subscriptions.py @@ -15,7 +15,7 @@ import json import logging from collections.abc import Callable -from typing import TYPE_CHECKING, Any, Literal +from typing import TYPE_CHECKING, Any from awscrt import mqtt from awscrt.exceptions import AwsCrtError @@ -25,7 +25,7 @@ from ..exceptions import MqttNotConnectedError from ..models import Device, DeviceFeature, DeviceStatus, EnergyUsageResponse from ..topic_builder import MqttTopicBuilder -from ..unit_system import set_unit_system +from ..unit_system import UnitSystemType, set_unit_system from .utils import redact_topic, topic_matches_pattern if TYPE_CHECKING: @@ -55,7 +55,7 @@ def __init__( event_emitter: EventEmitter, schedule_coroutine: Callable[[Any], None], device_info_cache: MqttDeviceInfoCache | None = None, - unit_system: Literal["metric", "imperial"] | None = None, + unit_system: UnitSystemType = None, ): """ Initialize subscription manager. @@ -67,14 +67,15 @@ def __init__( schedule_coroutine: Function to schedule async tasks device_info_cache: Optional MqttDeviceInfoCache for caching device features - unit_system: Preferred unit system ("metric", "imperial", or None) + unit_system: Preferred unit system ("metric", "us_customary", + or None) """ self._connection = connection self._client_id = client_id self._event_emitter = event_emitter self._schedule_coroutine = schedule_coroutine self._device_info_cache = device_info_cache - self._unit_system: Literal["metric", "imperial"] | None = unit_system + self._unit_system: UnitSystemType = unit_system # Track subscriptions and handlers self._subscriptions: dict[str, mqtt.QoS] = {} diff --git a/src/nwp500/unit_system.py b/src/nwp500/unit_system.py index c27f93d..093a1f9 100644 --- a/src/nwp500/unit_system.py +++ b/src/nwp500/unit_system.py @@ -22,16 +22,19 @@ _logger = logging.getLogger(__name__) +# Type alias for unit system preference +UnitSystemType = Literal["metric", "us_customary"] | None + # Context variable to store the preferred unit system # None means auto-detect from device -# "metric" means Celsius, "imperial" means Fahrenheit +# "metric" means Celsius, "us_customary" means Fahrenheit _unit_system_context: contextvars.ContextVar[ - Literal["metric", "imperial"] | None + Literal["metric", "us_customary"] | None ] = contextvars.ContextVar("unit_system", default=None) def set_unit_system( - unit_system: Literal["metric", "imperial"] | None, + unit_system: Literal["metric", "us_customary"] | None, ) -> None: """Set preferred unit system for temperature, flow, and volume conversions. @@ -41,12 +44,12 @@ def set_unit_system( Args: unit_system: Preferred unit system: - "metric": Use Celsius, LPM, and Liters - - "imperial": Use Fahrenheit, GPM, and Gallons + - "us_customary": Use Fahrenheit, GPM, and Gallons - None: Auto-detect from device's temperature_type (default) Example: >>> from nwp500 import set_unit_system - >>> set_unit_system("imperial") + >>> set_unit_system("us_customary") >>> # All values now in F, GPM, Gallons >>> set_unit_system(None) # Reset to auto-detect @@ -57,13 +60,13 @@ def set_unit_system( _unit_system_context.set(unit_system) -def get_unit_system() -> Literal["metric", "imperial"] | None: +def get_unit_system() -> Literal["metric", "us_customary"] | None: """Get the currently configured unit system preference. Returns: The current unit system preference: - "metric": Celsius, LPM, Liters - - "imperial": Fahrenheit, GPM, Gallons + - "us_customary": Fahrenheit, GPM, Gallons - None: Auto-detect from device (default) """ return _unit_system_context.get() @@ -79,29 +82,29 @@ def reset_unit_system() -> None: def unit_system_to_temperature_type( - unit_system: Literal["metric", "imperial"] | None, + unit_system: Literal["metric", "us_customary"] | None, ) -> TemperatureType | None: """Convert unit system preference to TemperatureType enum. Args: - unit_system: Unit system preference ("metric", "imperial", or None) + unit_system: Unit system preference ("metric", "us_customary", or None) Returns: - TemperatureType.CELSIUS for "metric" - - TemperatureType.FAHRENHEIT for "imperial" + - TemperatureType.FAHRENHEIT for "us_customary" - None for None (auto-detect) """ match unit_system: case "metric": return TemperatureType.CELSIUS - case "imperial": + case "us_customary": return TemperatureType.FAHRENHEIT case None: return None def is_metric_preferred( - override: Literal["metric", "imperial"] | None = None, + override: Literal["metric", "us_customary"] | None = None, ) -> bool: """Check if metric (Celsius) is preferred. @@ -113,7 +116,8 @@ def is_metric_preferred( over the context-configured unit system. Returns: - True if metric (Celsius) is preferred, False if imperial (Fahrenheit). + True if metric (Celsius) is preferred, False if us_customary + (Fahrenheit). """ # If override is provided, use it if override is not None: diff --git a/tests/test_unit_switching.py b/tests/test_unit_switching.py index 1ce4336..c62e94f 100644 --- a/tests/test_unit_switching.py +++ b/tests/test_unit_switching.py @@ -353,8 +353,8 @@ def test_unit_system_context_override_affects_field_units(): assert feature.get_field_unit("freeze_protection_temp_min") == " °C" assert feature.get_field_unit("recirc_temperature_min") == " °C" - # Test 3: Override to imperial - should return Fahrenheit units - set_unit_system("imperial") + # Test 3: Override to us_customary - should return Fahrenheit units + set_unit_system("us_customary") assert feature.get_field_unit("dhw_temperature_min") == " °F" assert feature.get_field_unit("freeze_protection_temp_min") == " °F" assert feature.get_field_unit("recirc_temperature_min") == " °F" @@ -478,8 +478,8 @@ def test_unit_system_context_override_with_flow_rate_units(): set_unit_system("metric") assert status.get_field_unit("current_dhw_flow_rate") == " LPM" - # Test 3: Override to imperial - should return GPM units - set_unit_system("imperial") + # Test 3: Override to us_customary - should return GPM units + set_unit_system("us_customary") assert status.get_field_unit("current_dhw_flow_rate") == " GPM" # Clean up @@ -601,8 +601,8 @@ def test_unit_system_context_override_with_volume_units(): set_unit_system("metric") assert status.get_field_unit("cumulated_dhw_flow_rate") == " L" - # Test 3: Override to imperial - should return Gallons units - set_unit_system("imperial") + # Test 3: Override to us_customary - should return Gallons units + set_unit_system("us_customary") assert status.get_field_unit("cumulated_dhw_flow_rate") == " gal" # Clean up