mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +00:00
Allow homekit_controller to set Ecobee's mode (#65032)
This commit is contained in:
parent
70321ed795
commit
a65694457a
@ -1,4 +1,6 @@
|
|||||||
"""Constants for the homekit_controller component."""
|
"""Constants for the homekit_controller component."""
|
||||||
|
from typing import Final
|
||||||
|
|
||||||
from aiohomekit.model.characteristics import CharacteristicsTypes
|
from aiohomekit.model.characteristics import CharacteristicsTypes
|
||||||
|
|
||||||
DOMAIN = "homekit_controller"
|
DOMAIN = "homekit_controller"
|
||||||
@ -62,6 +64,7 @@ CHARACTERISTIC_PLATFORMS = {
|
|||||||
CharacteristicsTypes.Vendor.ECOBEE_SLEEP_TARGET_HEAT: "number",
|
CharacteristicsTypes.Vendor.ECOBEE_SLEEP_TARGET_HEAT: "number",
|
||||||
CharacteristicsTypes.Vendor.ECOBEE_AWAY_TARGET_COOL: "number",
|
CharacteristicsTypes.Vendor.ECOBEE_AWAY_TARGET_COOL: "number",
|
||||||
CharacteristicsTypes.Vendor.ECOBEE_AWAY_TARGET_HEAT: "number",
|
CharacteristicsTypes.Vendor.ECOBEE_AWAY_TARGET_HEAT: "number",
|
||||||
|
CharacteristicsTypes.Vendor.ECOBEE_CURRENT_MODE: "select",
|
||||||
CharacteristicsTypes.Vendor.EVE_ENERGY_WATT: "sensor",
|
CharacteristicsTypes.Vendor.EVE_ENERGY_WATT: "sensor",
|
||||||
CharacteristicsTypes.Vendor.EVE_DEGREE_AIR_PRESSURE: "sensor",
|
CharacteristicsTypes.Vendor.EVE_DEGREE_AIR_PRESSURE: "sensor",
|
||||||
CharacteristicsTypes.Vendor.EVE_DEGREE_ELEVATION: "number",
|
CharacteristicsTypes.Vendor.EVE_DEGREE_ELEVATION: "number",
|
||||||
@ -92,3 +95,7 @@ CHARACTERISTIC_PLATFORMS = {
|
|||||||
for k, v in list(CHARACTERISTIC_PLATFORMS.items()):
|
for k, v in list(CHARACTERISTIC_PLATFORMS.items()):
|
||||||
value = CHARACTERISTIC_PLATFORMS.pop(k)
|
value = CHARACTERISTIC_PLATFORMS.pop(k)
|
||||||
CHARACTERISTIC_PLATFORMS[CharacteristicsTypes.get_uuid(k)] = value
|
CHARACTERISTIC_PLATFORMS[CharacteristicsTypes.get_uuid(k)] = value
|
||||||
|
|
||||||
|
|
||||||
|
# Device classes
|
||||||
|
DEVICE_CLASS_ECOBEE_MODE: Final = "homekit_controller__ecobee_mode"
|
||||||
|
71
homeassistant/components/homekit_controller/select.py
Normal file
71
homeassistant/components/homekit_controller/select.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
"""Support for Homekit select entities."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from aiohomekit.model.characteristics import Characteristic, CharacteristicsTypes
|
||||||
|
|
||||||
|
from homeassistant.components.select import SelectEntity
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
|
from . import KNOWN_DEVICES, CharacteristicEntity
|
||||||
|
from .const import DEVICE_CLASS_ECOBEE_MODE
|
||||||
|
|
||||||
|
_ECOBEE_MODE_TO_TEXT = {
|
||||||
|
0: "home",
|
||||||
|
1: "sleep",
|
||||||
|
2: "away",
|
||||||
|
}
|
||||||
|
_ECOBEE_MODE_TO_NUMBERS = {v: k for (k, v) in _ECOBEE_MODE_TO_TEXT.items()}
|
||||||
|
|
||||||
|
|
||||||
|
class EcobeeModeSelect(CharacteristicEntity, SelectEntity):
|
||||||
|
"""Represents a ecobee mode select entity."""
|
||||||
|
|
||||||
|
_attr_options = ["home", "sleep", "away"]
|
||||||
|
_attr_device_class = DEVICE_CLASS_ECOBEE_MODE
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self) -> str:
|
||||||
|
"""Return the name of the device if any."""
|
||||||
|
if name := super().name:
|
||||||
|
return f"{name} Current Mode"
|
||||||
|
return "Current Mode"
|
||||||
|
|
||||||
|
def get_characteristic_types(self):
|
||||||
|
"""Define the homekit characteristics the entity cares about."""
|
||||||
|
return [
|
||||||
|
CharacteristicsTypes.Vendor.ECOBEE_CURRENT_MODE,
|
||||||
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_option(self) -> str | None:
|
||||||
|
"""Return the current selected option."""
|
||||||
|
return _ECOBEE_MODE_TO_TEXT.get(self._char.value)
|
||||||
|
|
||||||
|
async def async_select_option(self, option: str) -> None:
|
||||||
|
"""Set the current mode."""
|
||||||
|
option_int = _ECOBEE_MODE_TO_NUMBERS[option]
|
||||||
|
await self.async_put_characteristics(
|
||||||
|
{CharacteristicsTypes.Vendor.ECOBEE_SET_HOLD_SCHEDULE: option_int}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up Homekit select entities."""
|
||||||
|
hkid = config_entry.data["AccessoryPairingID"]
|
||||||
|
conn = hass.data[KNOWN_DEVICES][hkid]
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_add_characteristic(char: Characteristic):
|
||||||
|
if char.type == CharacteristicsTypes.Vendor.ECOBEE_CURRENT_MODE:
|
||||||
|
info = {"aid": char.service.accessory.aid, "iid": char.service.iid}
|
||||||
|
async_add_entities([EcobeeModeSelect(conn, info, char)])
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
conn.add_char_factory(async_add_characteristic)
|
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"state": {
|
||||||
|
"homekit_controller__ecobee_mode": {
|
||||||
|
"home": "Home",
|
||||||
|
"sleep": "Sleep",
|
||||||
|
"away": "Away"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -209,6 +209,13 @@ async def test_ecobee3_setup(hass):
|
|||||||
unit_of_measurement=TEMP_CELSIUS,
|
unit_of_measurement=TEMP_CELSIUS,
|
||||||
state="21.8",
|
state="21.8",
|
||||||
),
|
),
|
||||||
|
EntityTestInfo(
|
||||||
|
entity_id="select.homew_current_mode",
|
||||||
|
friendly_name="HomeW Current Mode",
|
||||||
|
unique_id="homekit-123456789012-aid:1-sid:16-cid:33",
|
||||||
|
capabilities={"options": ["home", "sleep", "away"]},
|
||||||
|
state="home",
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
90
tests/components/homekit_controller/test_select.py
Normal file
90
tests/components/homekit_controller/test_select.py
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
"""Basic checks for HomeKit select entities."""
|
||||||
|
from aiohomekit.model import Accessory
|
||||||
|
from aiohomekit.model.characteristics import CharacteristicsTypes
|
||||||
|
from aiohomekit.model.services import ServicesTypes
|
||||||
|
|
||||||
|
from tests.components.homekit_controller.common import Helper, setup_test_component
|
||||||
|
|
||||||
|
|
||||||
|
def create_service_with_ecobee_mode(accessory: Accessory):
|
||||||
|
"""Define a thermostat with ecobee mode characteristics."""
|
||||||
|
service = accessory.add_service(ServicesTypes.THERMOSTAT, add_required=True)
|
||||||
|
|
||||||
|
current_mode = service.add_char(CharacteristicsTypes.Vendor.ECOBEE_CURRENT_MODE)
|
||||||
|
current_mode.value = 0
|
||||||
|
|
||||||
|
service.add_char(CharacteristicsTypes.Vendor.ECOBEE_SET_HOLD_SCHEDULE)
|
||||||
|
|
||||||
|
return service
|
||||||
|
|
||||||
|
|
||||||
|
async def test_read_current_mode(hass, utcnow):
|
||||||
|
"""Test that Ecobee mode can be correctly read and show as human readable text."""
|
||||||
|
helper = await setup_test_component(hass, create_service_with_ecobee_mode)
|
||||||
|
service = helper.accessory.services.first(service_type=ServicesTypes.THERMOSTAT)
|
||||||
|
|
||||||
|
# Helper will be for the primary entity, which is the service. Make a helper for the sensor.
|
||||||
|
energy_helper = Helper(
|
||||||
|
hass,
|
||||||
|
"select.testdevice_current_mode",
|
||||||
|
helper.pairing,
|
||||||
|
helper.accessory,
|
||||||
|
helper.config_entry,
|
||||||
|
)
|
||||||
|
|
||||||
|
mode = service[CharacteristicsTypes.Vendor.ECOBEE_CURRENT_MODE]
|
||||||
|
|
||||||
|
state = await energy_helper.poll_and_get_state()
|
||||||
|
assert state.state == "home"
|
||||||
|
|
||||||
|
mode.value = 1
|
||||||
|
state = await energy_helper.poll_and_get_state()
|
||||||
|
assert state.state == "sleep"
|
||||||
|
|
||||||
|
mode.value = 2
|
||||||
|
state = await energy_helper.poll_and_get_state()
|
||||||
|
assert state.state == "away"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_write_current_mode(hass, utcnow):
|
||||||
|
"""Test can set a specific mode."""
|
||||||
|
helper = await setup_test_component(hass, create_service_with_ecobee_mode)
|
||||||
|
service = helper.accessory.services.first(service_type=ServicesTypes.THERMOSTAT)
|
||||||
|
|
||||||
|
# Helper will be for the primary entity, which is the service. Make a helper for the sensor.
|
||||||
|
energy_helper = Helper(
|
||||||
|
hass,
|
||||||
|
"select.testdevice_current_mode",
|
||||||
|
helper.pairing,
|
||||||
|
helper.accessory,
|
||||||
|
helper.config_entry,
|
||||||
|
)
|
||||||
|
|
||||||
|
service = energy_helper.accessory.services.first(
|
||||||
|
service_type=ServicesTypes.THERMOSTAT
|
||||||
|
)
|
||||||
|
mode = service[CharacteristicsTypes.Vendor.ECOBEE_SET_HOLD_SCHEDULE]
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"select",
|
||||||
|
"select_option",
|
||||||
|
{"entity_id": "select.testdevice_current_mode", "option": "home"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert mode.value == 0
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"select",
|
||||||
|
"select_option",
|
||||||
|
{"entity_id": "select.testdevice_current_mode", "option": "sleep"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert mode.value == 1
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
"select",
|
||||||
|
"select_option",
|
||||||
|
{"entity_id": "select.testdevice_current_mode", "option": "away"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert mode.value == 2
|
Loading…
x
Reference in New Issue
Block a user