### Setup Development Environment - Manual Setup Source: https://github.com/alepee/hass-hitachi_yutaki/blob/dev/README.md Command to execute the setup script for the hass-hitachi_yutaki development environment. This script installs necessary dependencies and configures the environment. ```bash chmod +x scripts/setup ./scripts/setup ``` -------------------------------- ### Start Home Assistant in Development Mode - Manual Setup Source: https://github.com/alepee/hass-hitachi_yutaki/blob/dev/README.md Command to start a Home Assistant instance in development mode using the provided script. This allows for testing changes made to the integration. ```bash ./scripts/develop ``` -------------------------------- ### Install Development Branch of Home Assistant - Manual Setup Source: https://github.com/alepee/hass-hitachi_yutaki/blob/dev/README.md Command to install the development branch of Home Assistant using a provided script. This is useful for testing the integration against the latest Home Assistant code. ```bash ./scripts/dev-branch ``` -------------------------------- ### Clone Repository - Manual Setup Source: https://github.com/alepee/hass-hitachi_yutaki/blob/dev/README.md Command to clone the hass-hitachi_yutaki project repository from GitHub. This is the first step in manually setting up the development environment. ```bash git clone https://github.com/alepee/hass-hitachi_yutaki.git ``` -------------------------------- ### Install Specific Home Assistant Version - Manual Setup Source: https://github.com/alepee/hass-hitachi_yutaki/blob/dev/README.md Command to install a specific version of Home Assistant using a provided script. This allows for testing the integration with particular Home Assistant releases. ```bash ./scripts/specific-version ``` -------------------------------- ### Navigate to Project Directory - Manual Setup Source: https://github.com/alepee/hass-hitachi_yutaki/blob/dev/README.md Command to change the current directory to the root of the cloned hass-hitachi_yutaki repository. This is necessary before running setup scripts. ```bash cd hitachi_yutaki ``` -------------------------------- ### Install Pre-commit Hooks Manually Source: https://github.com/alepee/hass-hitachi_yutaki/blob/dev/README.md Command to manually install the pre-commit hooks for the hass-hitachi_yutaki project. These hooks run checks on code before commits to maintain code quality. ```bash pre-commit install ``` -------------------------------- ### Upgrade to Latest Home Assistant Version - Manual Setup Source: https://github.com/alepee/hass-hitachi_yutaki/blob/dev/README.md Command to upgrade to the latest version of Home Assistant using a provided script. This ensures the development environment is up-to-date. ```bash ./scripts/upgrade ``` -------------------------------- ### Run Code Linting - Manual Setup Source: https://github.com/alepee/hass-hitachi_yutaki/blob/dev/README.md Command to execute the code linting script for the hass-hitachi_yutaki project. This helps ensure code quality and adherence to style guidelines. ```bash ./scripts/lint ``` -------------------------------- ### Hitachi Yutaki Configuration Flow - Python Source: https://context7.com/alepee/hass-hitachi_yutaki/llms.txt This Python code defines the configuration flow for the Hitachi Yutaki Home Assistant integration. It handles user input for connection details (host, port, name), validates Modbus connectivity, and reads unit and system configuration from the heat pump's Modbus gateway. It uses pymodbus for Modbus communication and Home Assistant's config_entries API for setup. ```python from homeassistant import config_entries from pymodbus.client import ModbusTcpClient from homeassistant.exceptions import ConfigEntryNotReady import voluptuous as vol from homeassistant import core from homeassistant.helpers import config_validation as cv # Configuration flow with validation class HitachiYutakiConfigFlow(config_entries.ConfigFlow, domain="hitachi_yutaki"): async def async_step_user(self, user_input=None): """Handle initial configuration step.""" if user_input is not None: self.basic_config = { "host": user_input["host"], "name": user_input["name"], "port": user_input["port"] } return await self.async_step_power() return self.async_show_form( step_id="user", data_schema=vol.Schema({ vol.Optional("name", default="Hitachi Yutaki"): str, vol.Required("host", default="192.168.0.4"): str, vol.Required("port", default=502): cv.port, vol.Required("show_advanced", default=False): bool, }) ) async def async_validate_connection(self, config): """Validate Modbus connection and retrieve unit configuration.""" client = ModbusTcpClient(host=config["host"], port=config["port"]) if not client.connect(): raise ConfigEntryNotReady("Cannot connect to gateway") # Read unit model from register 1218 result = await self.hass.async_add_executor_job( lambda: client.read_holding_registers( address=1218, # REGISTER_UNIT_MODEL count=1, device_id=config["slave"] ) ) unit_model = result.registers[0] # Read system configuration from register 1089 config_result = await self.hass.async_add_executor_job( lambda: client.read_holding_registers( address=1089, # REGISTER_SYSTEM_CONFIG count=1, device_id=config["slave"] ) ) config["unit_model"] = unit_model config["system_config"] = config_result.registers[0] client.close() return self.async_create_entry(title=config["name"], data=config) ``` -------------------------------- ### Project Structure Overview Source: https://github.com/alepee/hass-hitachi_yutaki/blob/dev/README.md This snippet displays the directory structure of the hass-hitachi_yutaki Home Assistant integration project. It outlines the organization of custom components, translation files, integration modules, development scripts, and test files. ```tree hitachi_yutaki/ ├── .github/ │ └── workflows/ # CI/CD workflows ├── custom_components/ │ └── hitachi_yutaki/ │ ├── translations/ # Language files (en.json, fr.json) │ ├── __init__.py # Integration setup │ ├── binary_sensor.py # Binary sensor platform │ ├── climate.py # Climate platform │ ├── config_flow.py # Configuration flow │ ├── const.py # Constants │ ├── coordinator.py # Data update coordinator │ ├── manifest.json # Integration manifest │ ├── number.py # Number platform │ ├── select.py # Select platform │ ├── sensor.py # Sensor platform │ └── switch.py # Switch platform ├── scripts/ # Development scripts │ ├── dev-branch # Install dev branch of Home Assistant │ ├── develop # Run Home Assistant with debug config │ ├── lint # Run code linting │ ├── setup # Install development dependencies │ ├── specific-version # Install specific HA version │ └── upgrade # Upgrade to latest HA version └── tests/ # Test files └── __init__.py # Tests package marker ``` -------------------------------- ### Calculate COP using Trapezoidal Integration (Python) Source: https://context7.com/alepee/hass-hitachi_yutaki/llms.txt This Python code calculates the Coefficient of Performance (COP) for a heat pump by integrating thermal and electrical power over time using the trapezoidal rule. It requires a list of PowerMeasurement objects, each containing a timestamp, thermal power, and electrical power. The function returns the COP within a valid range (0.5 to 8.0) or None if calculations cannot be performed. ```python self.measurements.append( PowerMeasurement(current_time, thermal_power, electrical_power) ) # Remove old measurements cutoff_time = current_time - self.period while self.measurements and self.measurements[0].timestamp < cutoff_time: self.measurements.popleft() def get_cop(self): """Calculate COP from accumulated energy using trapezoidal integration.""" if not self.measurements: return None thermal_energy = 0.0 electrical_energy = 0.0 for i in range(len(self.measurements) - 1): interval_hours = ( self.measurements[i + 1].timestamp - self.measurements[i].timestamp ).total_seconds() / 3600 avg_thermal = ( self.measurements[i].thermal_power + self.measurements[i + 1].thermal_power ) / 2 avg_electrical = ( self.measurements[i].electrical_power + self.measurements[i + 1].electrical_power ) / 2 thermal_energy += avg_thermal * interval_hours electrical_energy += avg_electrical * interval_hours if electrical_energy <= 0: return None cop = thermal_energy / electrical_energy # Validate range (0.5 - 8.0 for heat pumps) return cop if 0.5 <= cop <= 8.0 else None ``` -------------------------------- ### Python Modbus TCP Data Fetching and Writing for Hitachi Yutaki Source: https://context7.com/alepee/hass-hitachi_yutaki/llms.txt This Python code defines a DataUpdateCoordinator for fetching data from and writing to a Hitachi Yutaki heat pump using Modbus TCP. It establishes a connection, reads various sensor registers, and allows for writing control values to specific registers. Dependencies include Home Assistant's DataUpdateCoordinator and the pymodbus library. ```python from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from pymodbus.client import ModbusTcpClient from datetime import timedelta import logging class HitachiYutakiDataCoordinator(DataUpdateCoordinator): """Coordinator for fetching data from heat pump via Modbus.""" def __init__(self, hass, entry): self.modbus_client = ModbusTcpClient( host=entry.data["host"], port=entry.data["port"] ) self.slave = entry.data["slave"] self.model = entry.data.get("unit_model") self.system_config = entry.data.get("system_config", 0) super().__init__( hass, logger=logging.getLogger(__name__), name="hitachi_yutaki", update_interval=timedelta(seconds=entry.data["scan_interval"]) ) async def _async_update_data(self): """Fetch data from heat pump.""" if not self.modbus_client.connected: await self.hass.async_add_executor_job(self.modbus_client.connect) data = {"is_available": True} # Check system state (register 1094) preflight = await self.hass.async_add_executor_job( lambda: self.modbus_client.read_holding_registers( address=1094, # REGISTER_SYSTEM_STATE count=1, device_id=self.slave ) ) system_state = preflight.registers[0] data["system_state"] = system_state # 0=synchronized, 1=desynchronized, 2=initializing if system_state != 0: return data # Read all registers registers = { "outdoor_temp": 1091, "water_inlet_temp": 1092, "water_outlet_temp": 1093, "water_flow": 1220, "compressor_frequency": 1212, "system_status": 1222, # ... more registers } for name, address in registers.items(): result = await self.hass.async_add_executor_job( lambda addr=address: self.modbus_client.read_holding_registers( address=addr, count=1, device_id=self.slave ) ) data[name] = result.registers[0] return data async def async_write_register(self, register_key, value): """Write a value to a Modbus register.""" register_map = { "unit_power": 1000, "unit_mode": 1001, "circuit1_target_temp": 1011, "dhw_target_temp": 1025, # ... more registers } address = register_map[register_key] await self.hass.async_add_executor_job( lambda: self.modbus_client.write_register( address=address, value=value, device_id=self.slave ) ) await self.async_request_refresh() ``` -------------------------------- ### Hitachi Yutaki Switch Entity - Python Source: https://context7.com/alepee/hass-hitachi_yutaki/llms.txt Implements a switch entity for the Hitachi Yutaki integration in Home Assistant. It handles power control and configuration states, interacting with the coordinator to read and write register values. Dependencies include the SwitchEntity and CoordinatorEntity from Home Assistant's components. ```python from homeassistant.components.switch import SwitchEntity class HitachiYutakiSwitch(CoordinatorEntity, SwitchEntity): """Switch entity for power control and configuration.""" def __init__(self, coordinator, description, device_info, register_prefix=None): super().__init__(coordinator) self.entity_description = description self.register_prefix = register_prefix self._register_key = ( f"{register_prefix}_{description.register_key}" if register_prefix else description.register_key ) @property def is_on(self): """Return true if switch is on.""" value = self.coordinator.data.get(self._register_key) return int(value) == self.entity_description.state_on if value else None async def async_turn_on(self, **kwargs): """Turn switch on.""" await self.coordinator.async_write_register( self._register_key, int(self.entity_description.state_on) ) async def async_turn_off(self, **kwargs): """Turn switch off.""" await self.coordinator.async_write_register( self._register_key, int(self.entity_description.state_off) ) # Example switch configurations UNIT_SWITCHES = ( HitachiYutakiSwitchEntityDescription( key="power", translation_key="power", register_key="unit_power", state_on=1, state_off=0 ), ) CIRCUIT_SWITCHES = ( HitachiYutakiSwitchEntityDescription( key="thermostat", translation_key="thermostat", register_key="thermostat", state_on=1, state_off=0 ), HitachiYutakiSwitchEntityDescription( key="eco_mode", translation_key="eco_mode", register_key="eco_mode", state_on=0, # Note: inverted logic state_off=1 ), ) ``` -------------------------------- ### Python Climate Entity for Hitachi Yutaki HVAC Source: https://context7.com/alepee/hass-hitachi_yutaki/llms.txt Implements a Home Assistant ClimateEntity for Hitachi Yutaki heat pumps. It handles features like target temperature, preset modes, and on/off functionality. It retrieves data from a coordinator and updates the system's state based on sensor readings and user commands. Dependencies include Home Assistant's climate component and coordinator entity. ```python from homeassistant.components.climate import ClimateEntity, HVACMode, HVACAction class HitachiYutakiClimate(CoordinatorEntity, ClimateEntity): """Climate entity for heating/cooling circuits.""" def __init__(self, coordinator, description, device_info, circuit_id): super().__init__(coordinator) self._circuit_id = circuit_id self._register_prefix = f"circuit{circuit_id}" self._attr_supported_features = ( ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE | ClimateEntityFeature.TURN_ON | ClimateEntityFeature.TURN_OFF ) self._attr_min_temp = 5.0 self._attr_max_temp = 35.0 self._attr_hvac_modes = [HVACMode.OFF, HVACMode.HEAT, HVACMode.COOL, HVACMode.AUTO] self._attr_preset_modes = ["comfort", "eco"] @property def current_temperature(self): """Return current temperature from circuit sensor.""" temp = self.coordinator.data.get(f"{self._register_prefix}_current_temp") return float(temp) / 10 if temp else None @property def target_temperature(self): """Return target temperature setpoint.""" temp = self.coordinator.data.get(f"{self._register_prefix}_target_temp") return float(temp) / 10 if temp else None @property def hvac_action(self): """Return current HVAC action.""" if self.hvac_mode == HVACMode.OFF: return HVACAction.OFF system_status = self.coordinator.data.get("system_status", 0) # Check defrost mode (bit 0) if system_status & 0x0001: return HVACAction.DEFROSTING # Check compressor running (bit 5) if not (system_status & 0x0020): return HVACAction.IDLE unit_mode = self.coordinator.data.get("unit_mode") return HVACAction.COOLING if unit_mode == 0 else HVACAction.HEATING async def async_set_temperature(self, **kwargs): """Set new target temperature.""" temperature = kwargs.get("temperature") await self.coordinator.async_write_register( f"{self._register_prefix}_target_temp", int(temperature * 10) ) async def async_set_hvac_mode(self, hvac_mode): """Set HVAC mode (heat/cool/auto/off).""" if hvac_mode == HVACMode.OFF: await self.coordinator.async_write_register( f"{self._register_prefix}_power", 0 ) return # Turn on circuit await self.coordinator.async_write_register( f"{self._register_prefix}_power", 1 ) # Set unit mode: 0=cool, 1=heat, 2=auto mode_map = {HVACMode.COOL: 0, HVACMode.HEAT: 1, HVACMode.AUTO: 2} await self.coordinator.async_write_register( "unit_mode", mode_map[hvac_mode] ) async def async_set_preset_mode(self, preset_mode): """Set preset mode (comfort/eco).""" await self.coordinator.async_write_register( f"{self._register_prefix}_eco_mode", 0 if preset_mode == "eco" else 1 ) ``` -------------------------------- ### Python Sensor Entity with COP Calculation for Hitachi Yutaki Source: https://context7.com/alepee/hass-hitachi_yutaki/llms.txt Implements a Home Assistant sensor entity that calculates the Coefficient of Performance (COP) for a Hitachi Yutaki heat pump. It aggregates thermal and electrical power measurements over a specified period to determine COP, handling different power supply types and external power sensor inputs. It also returns quality indicators for the COP measurements. ```python from homeassistant.components.sensor import SensorEntity, SensorDeviceClass from collections import deque from datetime import datetime, timedelta class HitachiYutakiSensor(CoordinatorEntity, SensorEntity, RestoreEntity): """Sensor entity with advanced COP and energy calculations.""" def __init__(self, coordinator, description, device_info): super().__init__(coordinator) self.entity_description = description # Initialize COP calculation for performance sensors if description.key in ("cop_heating", "cop_cooling", "cop_dhw", "cop_pool"): self._energy_accumulator = EnergyAccumulator(timedelta(minutes=30)) self._last_measurement = 0 def _calculate_cop_values(self): """Calculate thermal and electrical power for COP.""" data = self.coordinator.data # Check compressor running (bit 5 in system_status) if not (data.get("system_status", 0) & 0x0020): return None, None # Get water temperatures (can use external sensors if configured) water_inlet = self._get_temperature( "water_inlet_temp", "water_inlet_temp_entity" ) water_outlet = self._get_temperature( "water_outlet_temp", "water_outlet_temp_entity" ) water_flow = self.coordinator.convert_water_flow( data.get("water_flow") ) if None in (water_inlet, water_outlet, water_flow): return None, None # Calculate thermal power: P_th = m * c * ΔT # m = water_flow (m³/h) * 1000/3600 (kg/s) # c = 4.18 kJ/kg·K water_flow_kgs = water_flow * (1000 / 3600) delta_t = water_outlet - water_inlet thermal_power = abs(water_flow_kgs * 4.18 * delta_t) # kW # Get electrical power from external sensor or calculate power_entity = self.coordinator.config_entry.data.get("power_entity") if power_entity: power_state = self.hass.states.get(power_entity) electrical_power = float(power_state.state) / 1000 # W to kW else: # Calculate from current: P = U * I * cos(φ) [* √3 for three-phase] current = data.get("compressor_current") voltage = 230 if self.coordinator.power_supply == "single" else 400 power_factor = 0.85 if self.coordinator.power_supply == "single": electrical_power = voltage * current * power_factor / 1000 else: electrical_power = voltage * current * power_factor * 1.732 / 1000 return thermal_power, electrical_power @property def native_value(self): """Return COP value from accumulated measurements.""" if self.entity_description.key not in ("cop_heating", "cop_cooling", "cop_dhw", "cop_pool"): # Standard sensor value value = self.coordinator.data.get(self.entity_description.register_key) return self.entity_description.value_fn(value, self.coordinator) if value else None # COP calculation current_time = time() if current_time - self._last_measurement >= 30: # Every 30 seconds thermal, electrical = self._calculate_cop_values() if thermal and electrical: self._energy_accumulator.add_measurement(thermal, electrical) self._last_measurement = current_time if len(self._energy_accumulator.measurements) < 6: return None cop = self._energy_accumulator.get_cop() return round(cop, 2) if cop else None @property def extra_state_attributes(self): """Return quality indicators for COP measurements.""" if self.entity_description.key in ("cop_heating", "cop_cooling", "cop_dhw", "cop_pool"): measurements = self._energy_accumulator.measurements if not measurements: return {"quality": "no_data"} time_span = (measurements[-1].timestamp - measurements[0].timestamp).total_seconds() / 60 num_measurements = len(measurements) if num_measurements < 6 or time_span < 3: quality = "insufficient_data" elif num_measurements < 10 or time_span < 15: quality = "preliminary" else: quality = "optimal" return { "quality": quality, "measurements": num_measurements, "time_span_minutes": round(time_span, 1) } return None class EnergyAccumulator: """Accumulate energy measurements for COP calculation.""" def __init__(self, period): self.period = period self.measurements = deque(maxlen=60) def add_measurement(self, thermal_power, electrical_power): """Add power measurement with timestamp.""" current_time = datetime.now() ``` -------------------------------- ### Water Heater Entity for DHW Control (Python) Source: https://context7.com/alepee/hass-hitachi_yutaki/llms.txt This Python code defines a Home Assistant WaterHeaterEntity for controlling the Domestic Hot Water (DHW) of a Hitachi Yutaki heat pump. It supports setting target temperature, operation mode ('off', 'heat_pump', 'high_demand'), and on/off state. The entity interacts with a coordinator to read current status and write configuration changes. ```python from homeassistant.components.water_heater import WaterHeaterEntity class HitachiYutakiWaterHeater(CoordinatorEntity, WaterHeaterEntity): """Water heater entity for domestic hot water.""" def __init__(self, coordinator, description, device_info): super().__init__(coordinator) self._attr_temperature_unit = UnitOfTemperature.CELSIUS self._attr_min_temp = 30 self._attr_max_temp = 60 self._attr_supported_features = ( WaterHeaterEntityFeature.TARGET_TEMPERATURE | WaterHeaterEntityFeature.OPERATION_MODE | WaterHeaterEntityFeature.ON_OFF ) self._attr_operation_list = ["off", "heat_pump", "high_demand"] @property def current_temperature(self): """Return current DHW temperature.""" temp = self.coordinator.data.get("dhw_current_temp") return float(self.coordinator.convert_temperature(temp)) if temp else None @property def current_operation(self): """Return current operation mode.""" if self.coordinator.data.get("dhw_power") == 0: return "off" if self.coordinator.data.get("dhw_high_demand") == 1: return "high_demand" return "heat_pump" async def async_set_temperature(self, **kwargs): """Set DHW target temperature.""" temperature = kwargs.get("temperature") await self.coordinator.async_write_register( "dhw_target_temp", int(temperature) ) async def async_set_operation_mode(self, operation_mode): """Set DHW operation mode.""" if operation_mode == "off": await self.coordinator.async_write_register("dhw_high_demand", 0) await self.coordinator.async_write_register("dhw_power", 0) elif operation_mode == "high_demand": if self.coordinator.data.get("dhw_power", 0) == 0: await self.coordinator.async_write_register("dhw_power", 1) await self.coordinator.async_write_register("dhw_high_demand", 1) elif operation_mode == "heat_pump": await self.coordinator.async_write_register("dhw_power", 1) await self.coordinator.async_write_register("dhw_high_demand", 0) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.