diff --git a/docs/protocol/data_conversions.rst b/docs/protocol/data_conversions.rst index e97e372..582a92f 100644 --- a/docs/protocol/data_conversions.rst +++ b/docs/protocol/data_conversions.rst @@ -18,26 +18,25 @@ Raw Encoding Strategies The device uses several encoding schemes to minimize transmission overhead: -1. **Offset Encoding** (add_20) - - Applied to most temperature fields - - Formula: ``displayed_value = raw_value + 20`` - - Purpose: Negative temperatures stored as positive integers - - Range: Typically -4°F (-20°C) to 149°F (65°C) - - Example: Raw 100 → 120°F display value - -2. **Tenths Encoding** (div_10) +1. **Half-degree Celsius to Fahrenheit** (HalfCelsiusToF) + - Applied to most temperature fields that are not scaled by other factors. + - Formula: ``displayed_value = (raw_value / 2.0) * 9/5 + 32`` + - Purpose: Converts raw values, which are in half-degrees Celsius, to Fahrenheit. + - Example: Raw 122 -> (122 / 2) * 9/5 + 32 = 141.8°F + +2. **Scaled Celsius to Fahrenheit** (PentaCelsiusToF) + - Applied to refrigerant and evaporator temperatures. + - Formula: ``displayed_value = (raw_value / 5.0) * 9/5 + 32`` + - Purpose: Converts raw values, which are scaled by a factor of 5, to Fahrenheit. + - Example: Raw 250 -> (250 / 5) * 9/5 + 32 = 122°F + +3. **Tenths Encoding** (div_10) - Applied to decimal precision values - Formula: ``displayed_value = raw_value / 10.0`` - Purpose: Preserve decimal precision in integer storage - Common for flow rates and differential temperatures - Example: Raw 125 → 12.5 GPM -3. **Decicelsius to Fahrenheit** (decicelsius_to_f) - - Applied to refrigerant and evaporator temperatures - - Formula: ``displayed_value = (raw_value / 10) * 9/5 + 32`` - - Purpose: Convert Celsius tenths to Fahrenheit - - Example: Raw 250 (25°C) → 77°F - 4. **Boolean Encoding** (device_bool) - Applied to all status flags - Formula: ``displayed_value = (raw_value == 2)`` @@ -66,15 +65,15 @@ DHW (Domestic Hot Water) Temperatures - Display Unit - Description * - ``dhwTemperature`` - - add_20 + - HalfCelsiusToF - °F - **Current outlet temperature** of hot water being delivered to fixtures. Real-time measurement. Typically 90-150°F. * - ``dhwTemperature2`` - - add_20 + - HalfCelsiusToF - °F - **Secondary DHW temperature sensor** reading (redundancy/averaging). May differ slightly from primary sensor during temperature transitions. * - ``dhwTemperatureSetting`` - - add_20 + - HalfCelsiusToF - °F - **User-configured target temperature** for DHW delivery. Adjustable range: 95-150°F. Default: 120°F. This is the setpoint users configure in the app. * - ``currentInletTemperature`` @@ -82,7 +81,7 @@ DHW (Domestic Hot Water) Temperatures - °F - **Cold water inlet temperature** to the water heater. Affects heating performance and recovery time. Typically 40-80°F depending on season and location. * - ``dhwTargetTemperatureSetting`` - - add_20 + - HalfCelsiusToF - °F - **Duplicate of dhwTemperatureSetting** for legacy API compatibility. @@ -98,11 +97,11 @@ Tank Temperature Sensors - Display Unit - Description * - ``tankUpperTemperature`` - - decicelsius_to_f + - PentaCelsiusToF - °F - **Upper tank sensor temperature**. Indicates stratification - hot water at top for quick delivery. Typically hottest point in tank. * - ``tankLowerTemperature`` - - decicelsius_to_f + - PentaCelsiusToF - °F - **Lower tank sensor temperature**. Indicates bulk tank temperature and heating progress. Typically cooler than upper sensor. @@ -122,27 +121,27 @@ These temperatures monitor the heat pump refrigerant circuit health and performa - Display Unit - Description * - ``dischargeTemperature`` - - decicelsius_to_f + - PentaCelsiusToF - °F - **Compressor discharge temperature**. Temperature of refrigerant exiting the compressor. Typically 120-180°F. High values indicate high system pressure; low values indicate efficiency issues. * - ``suctionTemperature`` - - decicelsius_to_f + - PentaCelsiusToF - °F - **Compressor suction temperature**. Temperature of refrigerant entering the compressor. Typically 40-60°F. Affects superheat calculation. * - ``evaporatorTemperature`` - - decicelsius_to_f + - PentaCelsiusToF - °F - **Evaporator coil temperature**. Where heat is extracted from ambient air. Typically 20-50°F. Lower outdoor air temperature reduces evaporator efficiency. * - ``ambientTemperature`` - - decicelsius_to_f + - PentaCelsiusToF - °F - **Ambient air temperature** measured at heat pump inlet. Directly affects system performance. At freezing (32°F), heat pump efficiency drops significantly. * - ``targetSuperHeat`` - - decicelsius_to_f + - PentaCelsiusToF - °F - **Target superheat setpoint**. Desired temperature difference between suction and evaporator ensuring complete refrigerant vaporization. Typically 10-20°F. * - ``currentSuperHeat`` - - decicelsius_to_f + - PentaCelsiusToF - °F - **Measured superheat value**. Actual temperature difference. Deviation from target indicates EEV (Electronic Expansion Valve) control issues. @@ -166,19 +165,19 @@ Electric heating elements are controlled via thermostat ranges. Two sensors (upp - Display Unit - Description * - ``heUpperOnTempSetting`` - - add_20 + - HalfCelsiusToF - °F - **Upper element ON threshold**. Upper tank temp must fall below this to activate upper heating element. * - ``heUpperOffTempSetting`` - - add_20 + - HalfCelsiusToF - °F - **Upper element OFF threshold**. Upper tank temp rises above this to deactivate upper element (hysteresis). * - ``heLowerOnTempSetting`` - - add_20 + - HalfCelsiusToF - °F - **Lower element ON threshold**. Lower tank temp must fall below this to activate lower element. * - ``heLowerOffTempSetting`` - - add_20 + - HalfCelsiusToF - °F - **Lower element OFF threshold**. Lower tank temp rises above this to deactivate lower element. * - ``heUpperOnDiffTempSetting`` @@ -198,7 +197,7 @@ Electric heating elements are controlled via thermostat ranges. Two sensors (upp - °F - **Lower element differential** variation. * - ``heatMinOpTemperature`` - - add_20 + - HalfCelsiusToF - °F - **Minimum heat pump operation temperature**. Lowest tank temperature setpoint allowed in the current operating mode. Range: 95-113°F. Default: 95°F. When set, the user can only set the target tank temperature at or above this threshold, ensuring minimum system operating conditions. @@ -216,19 +215,19 @@ Heat pump stages are similarly controlled via thermostat ranges: - Display Unit - Description * - ``hpUpperOnTempSetting`` - - add_20 + - HalfCelsiusToF - °F - **Upper heat pump ON**. Upper tank falls below this to activate heat pump for upper tank heating. * - ``hpUpperOffTempSetting`` - - add_20 + - HalfCelsiusToF - °F - **Upper heat pump OFF**. Upper tank rises above this to stop upper tank heat pump operation. * - ``hpLowerOnTempSetting`` - - add_20 + - HalfCelsiusToF - °F - **Lower heat pump ON**. Lower tank falls below this to activate heat pump for lower tank heating. * - ``hpLowerOffTempSetting`` - - add_20 + - HalfCelsiusToF - °F - **Lower heat pump OFF**. Lower tank rises above this to stop lower tank heat pump operation. * - ``hpUpperOnDiffTempSetting`` @@ -264,15 +263,15 @@ Freeze Protection Temperatures - Boolean - **Freeze protection enabled flag**. When True, triggers anti-freeze operation below threshold. * - ``freezeProtectionTemperature`` - - add_20 + - HalfCelsiusToF - °F - **Freeze protection temperature setpoint**. Range: 43-50°F (6-10°C). Default: 43°F (6°C). When tank temperature drops below this, electric heating activates automatically to prevent freezing. * - ``freezeProtectionTempMin`` - - add_20 + - HalfCelsiusToF - °F - **Minimum freeze protection temperature limit** (lower boundary). Fixed at 43°F (6°C). * - ``freezeProtectionTempMax`` - - add_20 + - HalfCelsiusToF - °F - **Maximum freeze protection temperature limit** (upper boundary). Fixed at 50°F (10°C). @@ -290,18 +289,19 @@ For systems with recirculation pumps (optional feature): - Display Unit - Description * - ``recircTemperature`` - - add_20 + - HalfCelsiusToF - °F - **Recirculation loop current temperature**. Temperature of water being circulated back to tank. * - ``recircFaucetTemperature`` - - add_20 + - HalfCelsiusToF - °F - **Recirculation faucet outlet temperature**. How hot water is at the furthest fixture during recirculation. * - ``recircTempSetting`` - - add_20 + - HalfCelsiusToF - °F - **Recirculation target temperature**. What temperature to maintain in the recirculation line. + Flow Rate Fields ---------------- @@ -613,8 +613,8 @@ Temperature Unit Notes * **Fahrenheit** conversions assume target display is °F as configured in the device * **Celsius calculations** can be derived by reversing the conversions: - - From ``add_20`` fields: ``celsius = (fahrenheit - 20) * 5/9`` - - From ``decicelsius_to_f`` fields: ``celsius = (fahrenheit - 32) * 5/9`` + - From ``HalfCelsiusToF`` fields: ``celsius = (fahrenheit - 32) * 5/9 * 2`` + - From ``PentaCelsiusToF`` fields: ``celsius = (fahrenheit - 32) * 5/9 * 5`` - From ``div_10`` fields: ``celsius = value_celsius / 10.0`` * **Sensor Accuracy**: Typically ±2°F for tank sensors, ±3°F for refrigerant sensors diff --git a/docs/protocol/device_status.rst b/docs/protocol/device_status.rst index 870b04c..fa44679 100644 --- a/docs/protocol/device_status.rst +++ b/docs/protocol/device_status.rst @@ -77,12 +77,12 @@ This document lists the fields found in the ``status`` object of device status m - integer - °F - Current Domestic Hot Water (DHW) outlet temperature. - - ``raw + 20`` + - HalfCelsiusToF * - ``dhwTemperatureSetting`` - integer - °F - Target DHW temperature setting. Range: 95°F (35°C) to 150°F (65.5°C). Default: 120°F (49°C). - - ``raw + 20`` + - HalfCelsiusToF * - ``programReservationUse`` - bool - None @@ -117,42 +117,42 @@ This document lists the fields found in the ``status`` object of device status m - integer - °F - The target DHW temperature setting (same as dhwTemperatureSetting). - - ``raw + 20`` + - HalfCelsiusToF * - ``tankUpperTemperature`` - integer - °F - Temperature of the upper part of the tank. - - ``(raw / 10) * 9/5 + 32`` (decicelsius to Fahrenheit) + - PentaCelsiusToF * - ``tankLowerTemperature`` - integer - °F - Temperature of the lower part of the tank. - - ``(raw / 10) * 9/5 + 32`` (decicelsius to Fahrenheit) + - PentaCelsiusToF * - ``dischargeTemperature`` - integer - °F - Compressor discharge temperature - temperature of refrigerant leaving the compressor. - - ``(raw / 10) * 9/5 + 32`` (decicelsius to Fahrenheit) + - PentaCelsiusToF * - ``suctionTemperature`` - integer - °F - Compressor suction temperature - temperature of refrigerant entering the compressor. - - ``(raw / 10) * 9/5 + 32`` (decicelsius to Fahrenheit) + - PentaCelsiusToF * - ``evaporatorTemperature`` - integer - °F - Evaporator temperature - temperature where heat is absorbed from ambient air. - - ``(raw / 10) * 9/5 + 32`` (decicelsius to Fahrenheit) + - PentaCelsiusToF * - ``ambientTemperature`` - integer - °F - Ambient air temperature measured at the heat pump air intake. - - ``(raw / 10) * 9/5 + 32`` (decicelsius to Fahrenheit) + - PentaCelsiusToF * - ``targetSuperHeat`` - integer - °F - Target superheat value - the desired temperature difference ensuring complete refrigerant vaporization. - - ``(raw / 10) * 9/5 + 32`` (decicelsius to Fahrenheit) + - PentaCelsiusToF * - ``compUse`` - bool - None @@ -212,7 +212,7 @@ This document lists the fields found in the ``status`` object of device status m - integer - °F - Freeze protection temperature setpoint. Range: 43-50°F (6-10°C), Default: 43°F. When tank temperature drops below this, electric heating activates automatically to prevent freezing. - - ``raw + 20`` + - HalfCelsiusToF * - ``antiLegionellaUse`` - bool - None @@ -287,7 +287,7 @@ This document lists the fields found in the ``status`` object of device status m - integer - °F - Second DHW temperature reading. - - ``raw + 20`` + - HalfCelsiusToF * - ``currentDhwFlowRate`` - float - GPM @@ -307,7 +307,7 @@ This document lists the fields found in the ``status`` object of device status m - integer - °F - Current superheat value - actual temperature difference between suction and evaporator temperatures. - - ``(raw / 10) * 9/5 + 32`` (decicelsius to Fahrenheit) + - PentaCelsiusToF * - ``heatUpperUse`` - bool - None @@ -357,42 +357,42 @@ This document lists the fields found in the ``status`` object of device status m - integer - °F - Heat pump upper on temperature setting. - - ``raw + 20`` + - HalfCelsiusToF * - ``hpUpperOffTempSetting`` - integer - °F - Heat pump upper off temperature setting. - - ``raw + 20`` + - HalfCelsiusToF * - ``hpLowerOnTempSetting`` - integer - °F - Heat pump lower on temperature setting. - - ``raw + 20`` + - HalfCelsiusToF * - ``hpLowerOffTempSetting`` - integer - °F - Heat pump lower off temperature setting. - - ``raw + 20`` + - HalfCelsiusToF * - ``heUpperOnTempSetting`` - integer - °F - Heater element upper on temperature setting. - - ``raw + 20`` + - HalfCelsiusToF * - ``heUpperOffTempSetting`` - integer - °F - Heater element upper off temperature setting. - - ``raw + 20`` + - HalfCelsiusToF * - ``heLowerOnTempSetting`` - integer - °F - Heater element lower on temperature setting. - - ``raw + 20`` + - HalfCelsiusToF * - ``heLowerOffTempSetting`` - integer - °F - Heater element lower off temperature setting. - - ``raw + 20`` + - HalfCelsiusToF * - ``hpUpperOnDiffTempSetting`` - float - °F @@ -437,7 +437,7 @@ This document lists the fields found in the ``status`` object of device status m - float - °F - Minimum heat pump operation temperature. Lowest tank temperature setpoint allowed in the current operating mode (95-113°F, default 95°F). When set, users can only set the target tank temperature at or above this threshold. - - ``raw + 20`` + - HalfCelsiusToF * - ``drOverrideStatus`` - integer - None @@ -730,7 +730,7 @@ Technical Notes * Tank temperature sensors operate within -4°F to 149°F (-20°C to 65°C) * Outside normal range, system may operate with reduced capacity using opposite heating element -* All tank temperature readings use conversion formula: ``display_temp = raw + 20`` + **Heating Elements:** diff --git a/docs/python_api/models.rst b/docs/python_api/models.rst index 7c11d3f..dbf3f29 100644 --- a/docs/python_api/models.rst +++ b/docs/python_api/models.rst @@ -293,8 +293,7 @@ Complete real-time device status with 100+ fields. * ``ambient_temperature`` (float) - Ambient air temperature .. note:: - Temperature display values are 20°F higher than message values. - Display: 140°F = Message: 120°F + Temperature values from the device are automatically converted from their raw (scaled Celsius) representation to Fahrenheit or Celsius based on the device's settings. The library handles these conversions transparently. **Key Power/Energy Fields:** @@ -684,18 +683,7 @@ Best Practices # Device supports energy monitoring await mqtt.request_energy_usage(device, year, months) -3. **Handle temperature conversions:** - - .. code-block:: python - - # Display temperature is 20°F higher than message value - display_temp = 140 - message_value = display_temp - 20 # 120 - - # Or use convenience method - await mqtt.set_dhw_temperature_display(device, 140) - -4. **Monitor operation state:** +3. **Monitor operation state:** .. code-block:: python diff --git a/src/nwp500/models.py b/src/nwp500/models.py index 2f4d342..ff7acb1 100644 --- a/src/nwp500/models.py +++ b/src/nwp500/models.py @@ -26,33 +26,36 @@ def _device_bool_validator(v: Any) -> bool: return bool(v == 2) -def _add_20_validator(v: Any) -> float: - """Add 20 to the value (temperature offset).""" +def _div_10_validator(v: Any) -> float: + """Divide by 10.""" if isinstance(v, (int, float)): - return float(v) + 20.0 + return float(v) / 10.0 return float(v) -def _div_10_validator(v: Any) -> float: - """Divide by 10.""" +def _half_celsius_to_fahrenheit(v: Any) -> float: + """Convert half-degrees Celsius to Fahrenheit.""" if isinstance(v, (int, float)): - return float(v) / 10.0 + celsius = float(v) / 2.0 + return (celsius * 9 / 5) + 32 return float(v) -def _decicelsius_to_fahrenheit(v: Any) -> float: - """Convert decicelsius (tenths of Celsius) to Fahrenheit.""" +def _penta_celsius_to_fahrenheit(v: Any) -> float: + """Convert value scaled by 5 to Fahrenheit.""" if isinstance(v, (int, float)): - celsius = float(v) / 10.0 + celsius = float(v) / 5.0 return (celsius * 9 / 5) + 32 return float(v) # Reusable Annotated types for conversions DeviceBool = Annotated[bool, BeforeValidator(_device_bool_validator)] -Add20 = Annotated[float, BeforeValidator(_add_20_validator)] Div10 = Annotated[float, BeforeValidator(_div_10_validator)] -DeciCelsiusToF = Annotated[float, BeforeValidator(_decicelsius_to_fahrenheit)] +HalfCelsiusToF = Annotated[float, BeforeValidator(_half_celsius_to_fahrenheit)] +PentaCelsiusToF = Annotated[ + float, BeforeValidator(_penta_celsius_to_fahrenheit) +] class NavienBaseModel(BaseModel): @@ -252,24 +255,24 @@ class DeviceStatus(NavienBaseModel): recirc_operation_busy: DeviceBool recirc_reservation_use: DeviceBool - # Temperature fields with offset (raw + 20) - dhw_temperature: Add20 - dhw_temperature_setting: Add20 - dhw_target_temperature_setting: Add20 - freeze_protection_temperature: Add20 - dhw_temperature2: Add20 - hp_upper_on_temp_setting: Add20 - hp_upper_off_temp_setting: Add20 - hp_lower_on_temp_setting: Add20 - hp_lower_off_temp_setting: Add20 - he_upper_on_temp_setting: Add20 - he_upper_off_temp_setting: Add20 - he_lower_on_temp_setting: Add20 - he_lower_off_temp_setting: Add20 - heat_min_op_temperature: Add20 - recirc_temp_setting: Add20 - recirc_temperature: Add20 - recirc_faucet_temperature: Add20 + # Temperature fields that are likely half-degrees Celsius + dhw_temperature: HalfCelsiusToF + dhw_temperature_setting: HalfCelsiusToF + dhw_target_temperature_setting: HalfCelsiusToF + freeze_protection_temperature: HalfCelsiusToF + dhw_temperature2: HalfCelsiusToF + hp_upper_on_temp_setting: HalfCelsiusToF + hp_upper_off_temp_setting: HalfCelsiusToF + hp_lower_on_temp_setting: HalfCelsiusToF + hp_lower_off_temp_setting: HalfCelsiusToF + he_upper_on_temp_setting: HalfCelsiusToF + he_upper_off_temp_setting: HalfCelsiusToF + he_lower_on_temp_setting: HalfCelsiusToF + he_lower_off_temp_setting: HalfCelsiusToF + heat_min_op_temperature: HalfCelsiusToF + recirc_temp_setting: HalfCelsiusToF + recirc_temperature: HalfCelsiusToF + recirc_faucet_temperature: HalfCelsiusToF # Fields with scale division (raw / 10.0) current_inlet_temperature: Div10 @@ -286,15 +289,15 @@ class DeviceStatus(NavienBaseModel): he_lower_off_diff_temp_setting: Div10 recirc_dhw_flow_rate: Div10 - # Temperature fields with decicelsius to Fahrenheit conversion - tank_upper_temperature: DeciCelsiusToF - tank_lower_temperature: DeciCelsiusToF - discharge_temperature: DeciCelsiusToF - suction_temperature: DeciCelsiusToF - evaporator_temperature: DeciCelsiusToF - ambient_temperature: DeciCelsiusToF - target_super_heat: DeciCelsiusToF - current_super_heat: DeciCelsiusToF + # Temperature fields with 1/5 scaling + tank_upper_temperature: PentaCelsiusToF + tank_lower_temperature: PentaCelsiusToF + discharge_temperature: PentaCelsiusToF + suction_temperature: PentaCelsiusToF + evaporator_temperature: PentaCelsiusToF + ambient_temperature: PentaCelsiusToF + target_super_heat: PentaCelsiusToF + current_super_heat: PentaCelsiusToF # Enum fields operation_mode: CurrentOperationMode = Field( @@ -306,8 +309,8 @@ class DeviceStatus(NavienBaseModel): temperature_type: TemperatureUnit = Field( default=TemperatureUnit.FAHRENHEIT ) - freeze_protection_temp_min: Add20 = 43.0 - freeze_protection_temp_max: Add20 = 65.0 + freeze_protection_temp_min: HalfCelsiusToF = 43.0 + freeze_protection_temp_max: HalfCelsiusToF = 65.0 @classmethod def from_dict(cls, data: dict[str, Any]) -> "DeviceStatus": @@ -350,11 +353,11 @@ class DeviceFeature(NavienBaseModel): energy_saver_use: int high_demand_use: int - # Temperature limit fields with offset (raw + 20) - dhw_temperature_min: Add20 - dhw_temperature_max: Add20 - freeze_protection_temp_min: Add20 - freeze_protection_temp_max: Add20 + # Temperature limit fields with half-degree Celsius scaling + dhw_temperature_min: HalfCelsiusToF + dhw_temperature_max: HalfCelsiusToF + freeze_protection_temp_min: HalfCelsiusToF + freeze_protection_temp_max: HalfCelsiusToF # Enum field temperature_type: TemperatureUnit = Field( diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 0000000..5f4923a --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,132 @@ +import pytest + +from nwp500.models import DeviceStatus + + +@pytest.fixture +def default_status_data(): + """Provides a default dictionary for DeviceStatus model.""" + return { + "command": 0, + "outsideTemperature": 0.0, + "specialFunctionStatus": 0, + "errorCode": 0, + "subErrorCode": 0, + "smartDiagnostic": 0, + "faultStatus1": 0, + "faultStatus2": 0, + "wifiRssi": 0, + "dhwChargePer": 0.0, + "drEventStatus": 0, + "vacationDaySetting": 0, + "vacationDayElapsed": 0, + "antiLegionellaPeriod": 0, + "programReservationType": 0, + "tempFormulaType": 0, + "currentStatenum": 0, + "targetFanRpm": 0, + "currentFanRpm": 0, + "fanPwm": 0, + "mixingRate": 0.0, + "eevStep": 0, + "airFilterAlarmPeriod": 0, + "airFilterAlarmElapsed": 0, + "cumulatedOpTimeEvaFan": 0, + "cumulatedDhwFlowRate": 0.0, + "touStatus": 0, + "drOverrideStatus": 0, + "touOverrideStatus": 0, + "totalEnergyCapacity": 0.0, + "availableEnergyCapacity": 0.0, + "recircOperationMode": 0, + "recircPumpOperationStatus": 0, + "recircHotBtnReady": 0, + "recircOperationReason": 0, + "recircErrorStatus": 0, + "currentInstPower": 0.0, + "didReload": 0, + "operationBusy": 0, + "freezeProtectionUse": 0, + "dhwUse": 0, + "dhwUseSustained": 0, + "programReservationUse": 0, + "ecoUse": 0, + "compUse": 0, + "eevUse": 0, + "evaFanUse": 0, + "shutOffValveUse": 0, + "conOvrSensorUse": 0, + "wtrOvrSensorUse": 0, + "antiLegionellaUse": 0, + "antiLegionellaOperationBusy": 0, + "errorBuzzerUse": 0, + "currentHeatUse": 0, + "heatUpperUse": 0, + "heatLowerUse": 0, + "scaldUse": 0, + "airFilterAlarmUse": 0, + "recircOperationBusy": 0, + "recircReservationUse": 0, + "dhwTemperature": 0, + "dhwTemperatureSetting": 0, + "dhwTargetTemperatureSetting": 0, + "freezeProtectionTemperature": 0, + "dhwTemperature2": 0, + "hpUpperOnTempSetting": 0, + "hpUpperOffTempSetting": 0, + "hpLowerOnTempSetting": 0, + "hpLowerOffTempSetting": 0, + "heUpperOnTempSetting": 0, + "heUpperOffTempSetting": 0, + "heLowerOnTempSetting": 0, + "heLowerOffTempSetting": 0, + "heatMinOpTemperature": 0, + "recircTempSetting": 0, + "recircTemperature": 0, + "recircFaucetTemperature": 0, + "currentInletTemperature": 0, + "currentDhwFlowRate": 0, + "hpUpperOnDiffTempSetting": 0, + "hpUpperOffDiffTempSetting": 0, + "hpLowerOnDiffTempSetting": 0, + "hpLowerOffDiffTempSetting": 0, + "heUpperOnDiffTempSetting": 0, + "heUpperOffDiffTempSetting": 0, + "heLowerOnTDiffempSetting": 0, + "heLowerOffDiffTempSetting": 0, + "recircDhwFlowRate": 0, + "tankUpperTemperature": 0, + "tankLowerTemperature": 0, + "dischargeTemperature": 0, + "suctionTemperature": 0, + "evaporatorTemperature": 0, + "ambientTemperature": 0, + "targetSuperHeat": 0, + "currentSuperHeat": 0, + "operationMode": 0, + "dhwOperationSetting": 3, + "temperatureType": 2, + "freezeProtectionTempMin": 43.0, + "freezeProtectionTempMax": 65.0, + } + + +def test_device_status_half_celsius_to_fahrenheit(default_status_data): + """Test HalfCelsiusToF conversion.""" + default_status_data["dhwTemperature"] = 122 + status = DeviceStatus.model_validate(default_status_data) + assert status.dhw_temperature == pytest.approx(141.8) + + +def test_device_status_penta_celsius_to_fahrenheit(default_status_data): + """Test PentaCelsiusToF conversion.""" + default_status_data["tankUpperTemperature"] = 250 + status = DeviceStatus.model_validate(default_status_data) + assert status.tank_upper_temperature == pytest.approx(122.0) + + +def test_device_status_div10(default_status_data): + """Test Div10 conversion.""" + default_status_data["currentInletTemperature"] = 500 + status = DeviceStatus.model_validate(default_status_data) + assert status.current_inlet_temperature == 50.0