Skip to content

Commit 46b7748

Browse files
committed
fix: Waterflow value retrieval and COP calculation
1 parent 9217fed commit 46b7748

File tree

2 files changed

+60
-13
lines changed

2 files changed

+60
-13
lines changed

custom_components/hitachi_yutaki/coordinator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ def convert_water_flow(self, value: int | None) -> float | None:
187187
"""Convert a raw water flow value to m³/h."""
188188
if value is None:
189189
return None
190-
return float(value) / 10.0 # Water flow is already in m³/h
190+
return float(value) / 10.0 # Convert from tenths of m³/h to m³/h
191191

192192
def convert_current(self, value: int | None) -> float | None:
193193
"""Convert a raw current value to amperes."""

custom_components/hitachi_yutaki/sensor.py

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,8 @@ def _calculate_cop_values(self) -> tuple[float | None, float | None]:
865865
water_outlet = self._get_temperature(
866866
"water_outlet_temp", CONF_WATER_OUTLET_TEMP_ENTITY
867867
)
868-
water_flow = self.coordinator.data.get("water_flow")
868+
water_flow_raw = self.coordinator.data.get("water_flow")
869+
water_flow = self.coordinator.convert_water_flow(water_flow_raw)
869870

870871
if None in (water_inlet, water_outlet, water_flow):
871872
_LOGGER.debug(
@@ -879,7 +880,9 @@ def _calculate_cop_values(self) -> tuple[float | None, float | None]:
879880
# Convert water flow and calculate thermal power
880881
water_flow_kgs = water_flow * WATER_FLOW_TO_KGS
881882
delta_t = water_outlet - water_inlet
882-
thermal_power = abs(water_flow_kgs * WATER_SPECIFIC_HEAT * delta_t)
883+
thermal_power = abs(
884+
water_flow_kgs * WATER_SPECIFIC_HEAT * delta_t
885+
) # Result is already in kW
883886

884887
_LOGGER.debug(
885888
"Thermal power calculation: %.2f kW (%.2f kg/s * %.2f kJ/kg·K * %.1f K) [flow=%.1f m³/h]",
@@ -962,44 +965,60 @@ def _is_compressor_running(self, is_r134a: bool = False) -> bool:
962965

963966
def _get_cop_value(self) -> StateType:
964967
"""Calculate and return COP value."""
968+
_LOGGER.debug(
969+
"Starting COP calculation for %s",
970+
self.entity_description.key,
971+
)
972+
965973
# Check if primary compressor is running
966974
if not self._is_compressor_running(False):
967975
_LOGGER.debug("Primary compressor not running, skipping COP calculation")
968976
return None
969977

970-
# For S80, also check R134a compressor
971-
if self.coordinator.is_s80_model() and not self._is_compressor_running(True):
972-
_LOGGER.debug("R134a compressor not running, skipping COP calculation")
973-
return None
974-
975978
# Check operation state
976979
operation_state = self.coordinator.data.get("operation_state")
980+
_LOGGER.debug(
981+
"Operation state for %s: %s",
982+
self.entity_description.key,
983+
operation_state,
984+
)
977985
if operation_state is None:
978986
_LOGGER.debug("Operation state not available")
979987
return None
980988

981989
# Skip if wrong state
982990
cop_state_map = {
983-
"cop_heating": OPERATION_STATE_MAP["heat_thermo_on"],
984-
"cop_cooling": OPERATION_STATE_MAP["cool_thermo_on"],
985-
"cop_dhw": OPERATION_STATE_MAP["dhw_on"],
986-
"cop_pool": OPERATION_STATE_MAP["pool_on"],
991+
"cop_heating": 6, # heat_thermo_on
992+
"cop_cooling": 3, # cool_thermo_on
993+
"cop_dhw": 8, # dhw_on
994+
"cop_pool": 10, # pool_on
987995
}
988996
expected_state = cop_state_map.get(self.entity_description.key)
989997
if operation_state != expected_state:
990998
_LOGGER.debug(
991-
"Wrong operation state for %s: expected %s, got %s",
999+
"Wrong operation state for %s: expected %s (%s), got %s (%s)",
9921000
self.entity_description.key,
9931001
expected_state,
1002+
OPERATION_STATE_MAP.get(expected_state, "unknown"),
9941003
operation_state,
1004+
OPERATION_STATE_MAP.get(operation_state, "unknown"),
9951005
)
9961006
return None
9971007

9981008
current_time = time()
9991009

10001010
# Add new measurement every minute
10011011
if current_time - self._last_measurement >= COP_UPDATE_INTERVAL:
1012+
_LOGGER.debug(
1013+
"Time since last measurement: %.1f seconds",
1014+
current_time - self._last_measurement,
1015+
)
10021016
thermal_power, electrical_power = self._calculate_cop_values()
1017+
_LOGGER.debug(
1018+
"Calculated powers: thermal=%.2f kW, electrical=%.2f kW",
1019+
thermal_power if thermal_power is not None else -1,
1020+
electrical_power if electrical_power is not None else -1,
1021+
)
10031022

10041023
if thermal_power is not None and electrical_power is not None:
10051024
cop = thermal_power / electrical_power
@@ -1016,6 +1035,9 @@ def _get_cop_value(self) -> StateType:
10161035
) and self.coordinator.config_entry.data.get(
10171036
CONF_WATER_OUTLET_TEMP_ENTITY
10181037
):
1038+
_LOGGER.debug(
1039+
"Using external temperature sensors for COP calculation"
1040+
)
10191041
if electrical_power > 0 and cop <= 8:
10201042
self._measurements.append(cop)
10211043
_LOGGER.debug(
@@ -1025,6 +1047,9 @@ def _get_cop_value(self) -> StateType:
10251047
)
10261048
# Otherwise use energy accumulation
10271049
else:
1050+
_LOGGER.debug(
1051+
"Using internal temperature sensors for COP calculation"
1052+
)
10281053
self._energy_accumulator.add_measurement(
10291054
thermal_power, electrical_power
10301055
)
@@ -1035,6 +1060,11 @@ def _get_cop_value(self) -> StateType:
10351060
)
10361061

10371062
self._last_measurement = current_time
1063+
else:
1064+
_LOGGER.debug(
1065+
"Skipping measurement, not enough time elapsed: %.1f seconds",
1066+
current_time - self._last_measurement,
1067+
)
10381068

10391069
# Return COP based on calculation method
10401070
if self.coordinator.config_entry.data.get(
@@ -1048,6 +1078,8 @@ def _get_cop_value(self) -> StateType:
10481078
len(self._measurements),
10491079
)
10501080
return cop
1081+
else:
1082+
_LOGGER.debug("No measurements available for median COP")
10511083
else:
10521084
cop = self._energy_accumulator.get_cop()
10531085
if cop is not None:
@@ -1059,6 +1091,8 @@ def _get_cop_value(self) -> StateType:
10591091
self._energy_accumulator.electrical_energy,
10601092
)
10611093
return cop
1094+
else:
1095+
_LOGGER.debug("No accumulated energy available for COP")
10621096
return None
10631097

10641098
async def async_update_timing(self) -> None:
@@ -1110,6 +1144,19 @@ def native_value(self) -> StateType:
11101144
):
11111145
return self._timing_values.get("rest_time")
11121146

1147+
# For COP sensors, use the COP calculation method
1148+
if self.entity_description.key in (
1149+
"cop_heating",
1150+
"cop_cooling",
1151+
"cop_dhw",
1152+
"cop_pool",
1153+
):
1154+
_LOGGER.debug(
1155+
"Calling _get_cop_value for %s",
1156+
self.entity_description.key,
1157+
)
1158+
return self._get_cop_value()
1159+
11131160
# For other sensors, use the standard value calculation
11141161
value = self.coordinator.data.get(self.entity_description.register_key)
11151162
if value is None:

0 commit comments

Comments
 (0)