mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Add preset mode to Comelit climate (#145195)
This commit is contained in:
parent
ce02a5544d
commit
526a8ee31f
@ -20,7 +20,12 @@ from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
from .const import (
|
||||
DOMAIN,
|
||||
PRESET_MODE_AUTO,
|
||||
PRESET_MODE_AUTO_TARGET_TEMP,
|
||||
PRESET_MODE_MANUAL,
|
||||
)
|
||||
from .coordinator import ComelitConfigEntry, ComelitSerialBridge
|
||||
from .entity import ComelitBridgeBaseEntity
|
||||
from .utils import bridge_api_call
|
||||
@ -41,11 +46,13 @@ class ClimaComelitMode(StrEnum):
|
||||
class ClimaComelitCommand(StrEnum):
|
||||
"""Serial Bridge clima commands."""
|
||||
|
||||
AUTO = "auto"
|
||||
MANUAL = "man"
|
||||
OFF = "off"
|
||||
ON = "on"
|
||||
MANUAL = "man"
|
||||
SET = "set"
|
||||
AUTO = "auto"
|
||||
SNOW = "lower"
|
||||
SUN = "upper"
|
||||
|
||||
|
||||
class ClimaComelitApiStatus(TypedDict):
|
||||
@ -67,11 +74,15 @@ API_STATUS: dict[str, ClimaComelitApiStatus] = {
|
||||
),
|
||||
}
|
||||
|
||||
MODE_TO_ACTION: dict[HVACMode, ClimaComelitCommand] = {
|
||||
HVACMODE_TO_ACTION: dict[HVACMode, ClimaComelitCommand] = {
|
||||
HVACMode.OFF: ClimaComelitCommand.OFF,
|
||||
HVACMode.AUTO: ClimaComelitCommand.AUTO,
|
||||
HVACMode.COOL: ClimaComelitCommand.MANUAL,
|
||||
HVACMode.HEAT: ClimaComelitCommand.MANUAL,
|
||||
HVACMode.COOL: ClimaComelitCommand.SNOW,
|
||||
HVACMode.HEAT: ClimaComelitCommand.SUN,
|
||||
}
|
||||
|
||||
PRESET_MODE_TO_ACTION: dict[str, ClimaComelitCommand] = {
|
||||
PRESET_MODE_MANUAL: ClimaComelitCommand.MANUAL,
|
||||
PRESET_MODE_AUTO: ClimaComelitCommand.AUTO,
|
||||
}
|
||||
|
||||
|
||||
@ -93,17 +104,20 @@ async def async_setup_entry(
|
||||
class ComelitClimateEntity(ComelitBridgeBaseEntity, ClimateEntity):
|
||||
"""Climate device."""
|
||||
|
||||
_attr_hvac_modes = [HVACMode.AUTO, HVACMode.COOL, HVACMode.HEAT, HVACMode.OFF]
|
||||
_attr_hvac_modes = [HVACMode.COOL, HVACMode.HEAT, HVACMode.OFF]
|
||||
_attr_preset_modes = [PRESET_MODE_AUTO, PRESET_MODE_MANUAL]
|
||||
_attr_max_temp = 30
|
||||
_attr_min_temp = 5
|
||||
_attr_supported_features = (
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE
|
||||
| ClimateEntityFeature.TURN_OFF
|
||||
| ClimateEntityFeature.TURN_ON
|
||||
| ClimateEntityFeature.PRESET_MODE
|
||||
)
|
||||
_attr_target_temperature_step = PRECISION_TENTHS
|
||||
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
_attr_name = None
|
||||
_attr_translation_key = "thermostat"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -132,6 +146,8 @@ class ComelitClimateEntity(ComelitBridgeBaseEntity, ClimateEntity):
|
||||
_mode = values[2] # Values from API: "O", "L", "U"
|
||||
_automatic = values[3] == ClimaComelitMode.AUTO
|
||||
|
||||
self._attr_preset_mode = PRESET_MODE_AUTO if _automatic else PRESET_MODE_MANUAL
|
||||
|
||||
self._attr_current_temperature = values[0] / 10
|
||||
|
||||
self._attr_hvac_action = None
|
||||
@ -141,10 +157,6 @@ class ComelitClimateEntity(ComelitBridgeBaseEntity, ClimateEntity):
|
||||
self._attr_hvac_action = API_STATUS[_mode]["hvac_action"]
|
||||
|
||||
self._attr_hvac_mode = None
|
||||
if _mode == ClimaComelitMode.OFF:
|
||||
self._attr_hvac_mode = HVACMode.OFF
|
||||
if _automatic:
|
||||
self._attr_hvac_mode = HVACMode.AUTO
|
||||
if _mode in API_STATUS:
|
||||
self._attr_hvac_mode = API_STATUS[_mode]["hvac_mode"]
|
||||
|
||||
@ -160,13 +172,12 @@ class ComelitClimateEntity(ComelitBridgeBaseEntity, ClimateEntity):
|
||||
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set new target temperature."""
|
||||
if (
|
||||
target_temp := kwargs.get(ATTR_TEMPERATURE)
|
||||
) is None or self.hvac_mode == HVACMode.OFF:
|
||||
(target_temp := kwargs.get(ATTR_TEMPERATURE)) is None
|
||||
or self.hvac_mode == HVACMode.OFF
|
||||
or self._attr_preset_mode == PRESET_MODE_AUTO
|
||||
):
|
||||
return
|
||||
|
||||
await self.coordinator.api.set_clima_status(
|
||||
self._device.index, ClimaComelitCommand.MANUAL
|
||||
)
|
||||
await self.coordinator.api.set_clima_status(
|
||||
self._device.index, ClimaComelitCommand.SET, target_temp
|
||||
)
|
||||
@ -177,12 +188,28 @@ class ComelitClimateEntity(ComelitBridgeBaseEntity, ClimateEntity):
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set hvac mode."""
|
||||
|
||||
if hvac_mode != HVACMode.OFF:
|
||||
if self._attr_hvac_mode == HVACMode.OFF:
|
||||
await self.coordinator.api.set_clima_status(
|
||||
self._device.index, ClimaComelitCommand.ON
|
||||
)
|
||||
await self.coordinator.api.set_clima_status(
|
||||
self._device.index, MODE_TO_ACTION[hvac_mode]
|
||||
self._device.index, HVACMODE_TO_ACTION[hvac_mode]
|
||||
)
|
||||
self._attr_hvac_mode = hvac_mode
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Set new target preset mode."""
|
||||
|
||||
if self._attr_hvac_mode == HVACMode.OFF:
|
||||
return
|
||||
|
||||
await self.coordinator.api.set_clima_status(
|
||||
self._device.index, PRESET_MODE_TO_ACTION[preset_mode]
|
||||
)
|
||||
self._attr_preset_mode = preset_mode
|
||||
|
||||
if preset_mode == PRESET_MODE_AUTO:
|
||||
self._attr_target_temperature = PRESET_MODE_AUTO_TARGET_TEMP
|
||||
|
||||
self.async_write_ha_state()
|
||||
|
@ -11,3 +11,8 @@ DEFAULT_PORT = 80
|
||||
DEVICE_TYPE_LIST = [BRIDGE, VEDO]
|
||||
|
||||
SCAN_INTERVAL = 5
|
||||
|
||||
PRESET_MODE_AUTO = "automatic"
|
||||
PRESET_MODE_MANUAL = "manual"
|
||||
|
||||
PRESET_MODE_AUTO_TARGET_TEMP = 20
|
||||
|
@ -4,6 +4,18 @@
|
||||
"zone_status": {
|
||||
"default": "mdi:shield-check"
|
||||
}
|
||||
},
|
||||
"climate": {
|
||||
"thermostat": {
|
||||
"state_attributes": {
|
||||
"preset_mode": {
|
||||
"state": {
|
||||
"automatic": "mdi:refresh-auto",
|
||||
"manual": "mdi:alpha-m"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,6 +74,18 @@
|
||||
"dehumidifier": {
|
||||
"name": "Dehumidifier"
|
||||
}
|
||||
},
|
||||
"climate": {
|
||||
"thermostat": {
|
||||
"state_attributes": {
|
||||
"preset_mode": {
|
||||
"state": {
|
||||
"automatic": "[%key:common::state::auto%]",
|
||||
"manual": "[%key:common::state::manual%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"exceptions": {
|
||||
|
@ -6,13 +6,16 @@
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'hvac_modes': list([
|
||||
<HVACMode.AUTO: 'auto'>,
|
||||
<HVACMode.COOL: 'cool'>,
|
||||
<HVACMode.HEAT: 'heat'>,
|
||||
<HVACMode.OFF: 'off'>,
|
||||
]),
|
||||
'max_temp': 30,
|
||||
'min_temp': 5,
|
||||
'preset_modes': list([
|
||||
'automatic',
|
||||
'manual',
|
||||
]),
|
||||
'target_temp_step': 0.1,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
@ -37,8 +40,8 @@
|
||||
'original_name': None,
|
||||
'platform': 'comelit',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': <ClimateEntityFeature: 385>,
|
||||
'translation_key': None,
|
||||
'supported_features': <ClimateEntityFeature: 401>,
|
||||
'translation_key': 'thermostat',
|
||||
'unique_id': 'serial_bridge_config_entry_id-0',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
@ -50,14 +53,18 @@
|
||||
'friendly_name': 'Climate0',
|
||||
'hvac_action': <HVACAction.IDLE: 'idle'>,
|
||||
'hvac_modes': list([
|
||||
<HVACMode.AUTO: 'auto'>,
|
||||
<HVACMode.COOL: 'cool'>,
|
||||
<HVACMode.HEAT: 'heat'>,
|
||||
<HVACMode.OFF: 'off'>,
|
||||
]),
|
||||
'max_temp': 30,
|
||||
'min_temp': 5,
|
||||
'supported_features': <ClimateEntityFeature: 385>,
|
||||
'preset_mode': 'manual',
|
||||
'preset_modes': list([
|
||||
'automatic',
|
||||
'manual',
|
||||
]),
|
||||
'supported_features': <ClimateEntityFeature: 401>,
|
||||
'target_temp_step': 0.1,
|
||||
'temperature': 5.0,
|
||||
}),
|
||||
|
@ -11,12 +11,19 @@ from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.climate import (
|
||||
ATTR_HVAC_MODE,
|
||||
ATTR_PRESET_MODE,
|
||||
DOMAIN as CLIMATE_DOMAIN,
|
||||
SERVICE_SET_HVAC_MODE,
|
||||
SERVICE_SET_PRESET_MODE,
|
||||
SERVICE_SET_TEMPERATURE,
|
||||
SERVICE_TURN_OFF,
|
||||
HVACMode,
|
||||
)
|
||||
from homeassistant.components.comelit.const import SCAN_INTERVAL
|
||||
from homeassistant.components.comelit.const import (
|
||||
PRESET_MODE_AUTO,
|
||||
PRESET_MODE_MANUAL,
|
||||
SCAN_INTERVAL,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
@ -273,10 +280,75 @@ async def test_climate_hvac_mode_when_off(
|
||||
await hass.services.async_call(
|
||||
CLIMATE_DOMAIN,
|
||||
SERVICE_SET_HVAC_MODE,
|
||||
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_HVAC_MODE: HVACMode.AUTO},
|
||||
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_HVAC_MODE: HVACMode.COOL},
|
||||
blocking=True,
|
||||
)
|
||||
mock_serial_bridge.set_clima_status.assert_called()
|
||||
|
||||
assert (state := hass.states.get(ENTITY_ID))
|
||||
assert state.state == HVACMode.AUTO
|
||||
assert state.state == HVACMode.COOL
|
||||
|
||||
|
||||
async def test_climate_preset_mode(
|
||||
hass: HomeAssistant,
|
||||
mock_serial_bridge: AsyncMock,
|
||||
mock_serial_bridge_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test climate preset mode service."""
|
||||
|
||||
await setup_integration(hass, mock_serial_bridge_config_entry)
|
||||
|
||||
assert (state := hass.states.get(ENTITY_ID))
|
||||
assert state.state == HVACMode.HEAT
|
||||
assert state.attributes[ATTR_TEMPERATURE] == 5.0
|
||||
assert state.attributes[ATTR_PRESET_MODE] == PRESET_MODE_MANUAL
|
||||
|
||||
await hass.services.async_call(
|
||||
CLIMATE_DOMAIN,
|
||||
SERVICE_SET_PRESET_MODE,
|
||||
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_PRESET_MODE: PRESET_MODE_AUTO},
|
||||
blocking=True,
|
||||
)
|
||||
mock_serial_bridge.set_clima_status.assert_called()
|
||||
|
||||
assert (state := hass.states.get(ENTITY_ID))
|
||||
assert state.state == HVACMode.HEAT
|
||||
assert state.attributes[ATTR_TEMPERATURE] == 20.0
|
||||
assert state.attributes[ATTR_PRESET_MODE] == PRESET_MODE_AUTO
|
||||
|
||||
|
||||
async def test_climate_preset_mode_when_off(
|
||||
hass: HomeAssistant,
|
||||
mock_serial_bridge: AsyncMock,
|
||||
mock_serial_bridge_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test climate preset mode service when off."""
|
||||
|
||||
await setup_integration(hass, mock_serial_bridge_config_entry)
|
||||
|
||||
assert (state := hass.states.get(ENTITY_ID))
|
||||
assert state.state == HVACMode.HEAT
|
||||
assert state.attributes[ATTR_TEMPERATURE] == 5.0
|
||||
assert state.attributes[ATTR_PRESET_MODE] == PRESET_MODE_MANUAL
|
||||
|
||||
await hass.services.async_call(
|
||||
CLIMATE_DOMAIN,
|
||||
SERVICE_TURN_OFF,
|
||||
{ATTR_ENTITY_ID: ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
mock_serial_bridge.set_clima_status.assert_called()
|
||||
|
||||
assert (state := hass.states.get(ENTITY_ID))
|
||||
assert state.state == HVACMode.OFF
|
||||
|
||||
await hass.services.async_call(
|
||||
CLIMATE_DOMAIN,
|
||||
SERVICE_SET_PRESET_MODE,
|
||||
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_PRESET_MODE: PRESET_MODE_AUTO},
|
||||
blocking=True,
|
||||
)
|
||||
mock_serial_bridge.set_clima_status.assert_called()
|
||||
|
||||
assert (state := hass.states.get(ENTITY_ID))
|
||||
assert state.state == HVACMode.OFF
|
||||
|
Loading…
x
Reference in New Issue
Block a user