Refactor homekit_controller entity update to work more like update coordinator (#32670)
* Clean up use of get_characteristic_types * Get rid of get_hk_char_value helper * Get rid of _update_fn callbacks * Call async_write_has_state directly as async_state_changed doesnt do anything any more
This commit is contained in:
parent
4248893007
commit
647d137daa
12 changed files with 159 additions and 358 deletions
|
@ -4,10 +4,9 @@ import os
|
||||||
|
|
||||||
import aiohomekit
|
import aiohomekit
|
||||||
from aiohomekit.model import Accessory
|
from aiohomekit.model import Accessory
|
||||||
from aiohomekit.model.characteristics import CharacteristicsTypes
|
from aiohomekit.model.characteristics import Characteristic, CharacteristicsTypes
|
||||||
from aiohomekit.model.services import Service, ServicesTypes
|
from aiohomekit.model.services import Service, ServicesTypes
|
||||||
|
|
||||||
from homeassistant.core import callback
|
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
from homeassistant.helpers import device_registry as dr
|
from homeassistant.helpers import device_registry as dr
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
|
@ -60,7 +59,7 @@ class HomeKitEntity(Entity):
|
||||||
"""Entity added to hass."""
|
"""Entity added to hass."""
|
||||||
self._signals.append(
|
self._signals.append(
|
||||||
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
self.hass.helpers.dispatcher.async_dispatcher_connect(
|
||||||
self._accessory.signal_state_updated, self.async_state_changed
|
self._accessory.signal_state_updated, self.async_write_ha_state
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -86,93 +85,53 @@ class HomeKitEntity(Entity):
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
"""Configure an entity baed on its HomeKit characteristics metadata."""
|
"""Configure an entity baed on its HomeKit characteristics metadata."""
|
||||||
get_uuid = CharacteristicsTypes.get_uuid
|
|
||||||
characteristic_types = [get_uuid(c) for c in self.get_characteristic_types()]
|
|
||||||
|
|
||||||
self.pollable_characteristics = []
|
self.pollable_characteristics = []
|
||||||
self.watchable_characteristics = []
|
self.watchable_characteristics = []
|
||||||
self._chars = {}
|
self._chars = {}
|
||||||
self._char_names = {}
|
self._char_names = {}
|
||||||
|
|
||||||
|
char_types = self.get_characteristic_types()
|
||||||
|
|
||||||
# Setup events and/or polling for characteristics directly attached to this entity
|
# Setup events and/or polling for characteristics directly attached to this entity
|
||||||
for char in self.service.characteristics:
|
for char in self.service.characteristics.filter(char_types=char_types):
|
||||||
if char.type not in characteristic_types:
|
self._setup_characteristic(char)
|
||||||
continue
|
|
||||||
self._setup_characteristic(char.to_accessory_and_service_list())
|
|
||||||
|
|
||||||
# Setup events and/or polling for characteristics attached to sub-services of this
|
# Setup events and/or polling for characteristics attached to sub-services of this
|
||||||
# entity (like an INPUT_SOURCE).
|
# entity (like an INPUT_SOURCE).
|
||||||
for service in self.accessory.services.filter(parent_service=self.service):
|
for service in self.accessory.services.filter(parent_service=self.service):
|
||||||
for char in service.characteristics:
|
for char in service.characteristics.filter(char_types=char_types):
|
||||||
if char.type not in characteristic_types:
|
self._setup_characteristic(char)
|
||||||
continue
|
|
||||||
self._setup_characteristic(char.to_accessory_and_service_list())
|
|
||||||
|
|
||||||
def _setup_characteristic(self, char):
|
def _setup_characteristic(self, char: Characteristic):
|
||||||
"""Configure an entity based on a HomeKit characteristics metadata."""
|
"""Configure an entity based on a HomeKit characteristics metadata."""
|
||||||
# Build up a list of (aid, iid) tuples to poll on update()
|
# Build up a list of (aid, iid) tuples to poll on update()
|
||||||
if "pr" in char["perms"]:
|
if "pr" in char.perms:
|
||||||
self.pollable_characteristics.append((self._aid, char["iid"]))
|
self.pollable_characteristics.append((self._aid, char.iid))
|
||||||
|
|
||||||
# Build up a list of (aid, iid) tuples to subscribe to
|
# Build up a list of (aid, iid) tuples to subscribe to
|
||||||
if "ev" in char["perms"]:
|
if "ev" in char.perms:
|
||||||
self.watchable_characteristics.append((self._aid, char["iid"]))
|
self.watchable_characteristics.append((self._aid, char.iid))
|
||||||
|
|
||||||
# Build a map of ctype -> iid
|
# Build a map of ctype -> iid
|
||||||
short_name = CharacteristicsTypes.get_short(char["type"])
|
self._chars[char.type_name] = char.iid
|
||||||
self._chars[short_name] = char["iid"]
|
self._char_names[char.iid] = char.type_name
|
||||||
self._char_names[char["iid"]] = short_name
|
|
||||||
|
|
||||||
# Callback to allow entity to configure itself based on this
|
# Callback to allow entity to configure itself based on this
|
||||||
# characteristics metadata (valid values, value ranges, features, etc)
|
# characteristics metadata (valid values, value ranges, features, etc)
|
||||||
setup_fn_name = escape_characteristic_name(short_name)
|
setup_fn_name = escape_characteristic_name(char.type_name)
|
||||||
setup_fn = getattr(self, f"_setup_{setup_fn_name}", None)
|
setup_fn = getattr(self, f"_setup_{setup_fn_name}", None)
|
||||||
if not setup_fn:
|
if not setup_fn:
|
||||||
return
|
return
|
||||||
setup_fn(char)
|
setup_fn(char.to_accessory_and_service_list())
|
||||||
|
|
||||||
def get_hk_char_value(self, characteristic_type):
|
|
||||||
"""Return the value for a given characteristic type enum."""
|
|
||||||
state = self._accessory.current_state.get(self._aid)
|
|
||||||
if not state:
|
|
||||||
return None
|
|
||||||
char = self._chars.get(CharacteristicsTypes.get_short(characteristic_type))
|
|
||||||
if not char:
|
|
||||||
return None
|
|
||||||
return state.get(char, {}).get("value")
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def async_state_changed(self):
|
|
||||||
"""Collect new data from bridge and update the entity state in hass."""
|
|
||||||
accessory_state = self._accessory.current_state.get(self._aid, {})
|
|
||||||
for iid, result in accessory_state.items():
|
|
||||||
# No value so don't process this result
|
|
||||||
if "value" not in result:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Unknown iid - this is probably for a sibling service that is part
|
|
||||||
# of the same physical accessory. Ignore it.
|
|
||||||
if iid not in self._char_names:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Callback to update the entity with this characteristic value
|
|
||||||
char_name = escape_characteristic_name(self._char_names[iid])
|
|
||||||
update_fn = getattr(self, f"_update_{char_name}", None)
|
|
||||||
if not update_fn:
|
|
||||||
continue
|
|
||||||
|
|
||||||
update_fn(result["value"])
|
|
||||||
|
|
||||||
self.async_write_ha_state()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self) -> str:
|
||||||
"""Return the ID of this device."""
|
"""Return the ID of this device."""
|
||||||
serial = self.accessory_info.value(CharacteristicsTypes.SERIAL_NUMBER)
|
serial = self.accessory_info.value(CharacteristicsTypes.SERIAL_NUMBER)
|
||||||
return f"homekit-{serial}-{self._iid}"
|
return f"homekit-{serial}-{self._iid}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self) -> str:
|
||||||
"""Return the name of the device if any."""
|
"""Return the name of the device if any."""
|
||||||
return self.accessory_info.value(CharacteristicsTypes.NAME)
|
return self.accessory_info.value(CharacteristicsTypes.NAME)
|
||||||
|
|
||||||
|
|
|
@ -34,38 +34,38 @@ class HomeAirQualitySensor(HomeKitEntity, AirQualityEntity):
|
||||||
@property
|
@property
|
||||||
def particulate_matter_2_5(self):
|
def particulate_matter_2_5(self):
|
||||||
"""Return the particulate matter 2.5 level."""
|
"""Return the particulate matter 2.5 level."""
|
||||||
return self.get_hk_char_value(CharacteristicsTypes.DENSITY_PM25)
|
return self.service.value(CharacteristicsTypes.DENSITY_PM25)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def particulate_matter_10(self):
|
def particulate_matter_10(self):
|
||||||
"""Return the particulate matter 10 level."""
|
"""Return the particulate matter 10 level."""
|
||||||
return self.get_hk_char_value(CharacteristicsTypes.DENSITY_PM10)
|
return self.service.value(CharacteristicsTypes.DENSITY_PM10)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def ozone(self):
|
def ozone(self):
|
||||||
"""Return the O3 (ozone) level."""
|
"""Return the O3 (ozone) level."""
|
||||||
return self.get_hk_char_value(CharacteristicsTypes.DENSITY_OZONE)
|
return self.service.value(CharacteristicsTypes.DENSITY_OZONE)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def sulphur_dioxide(self):
|
def sulphur_dioxide(self):
|
||||||
"""Return the SO2 (sulphur dioxide) level."""
|
"""Return the SO2 (sulphur dioxide) level."""
|
||||||
return self.get_hk_char_value(CharacteristicsTypes.DENSITY_SO2)
|
return self.service.value(CharacteristicsTypes.DENSITY_SO2)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nitrogen_dioxide(self):
|
def nitrogen_dioxide(self):
|
||||||
"""Return the NO2 (nitrogen dioxide) level."""
|
"""Return the NO2 (nitrogen dioxide) level."""
|
||||||
return self.get_hk_char_value(CharacteristicsTypes.DENSITY_NO2)
|
return self.service.value(CharacteristicsTypes.DENSITY_NO2)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def air_quality_text(self):
|
def air_quality_text(self):
|
||||||
"""Return the Air Quality Index (AQI)."""
|
"""Return the Air Quality Index (AQI)."""
|
||||||
air_quality = self.get_hk_char_value(CharacteristicsTypes.AIR_QUALITY)
|
air_quality = self.service.value(CharacteristicsTypes.AIR_QUALITY)
|
||||||
return AIR_QUALITY_TEXT.get(air_quality, "unknown")
|
return AIR_QUALITY_TEXT.get(air_quality, "unknown")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def volatile_organic_compounds(self):
|
def volatile_organic_compounds(self):
|
||||||
"""Return the volatile organic compounds (VOC) level."""
|
"""Return the volatile organic compounds (VOC) level."""
|
||||||
return self.get_hk_char_value(CharacteristicsTypes.DENSITY_VOC)
|
return self.service.value(CharacteristicsTypes.DENSITY_VOC)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
|
|
|
@ -60,12 +60,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
class HomeKitAlarmControlPanel(HomeKitEntity, AlarmControlPanel):
|
class HomeKitAlarmControlPanel(HomeKitEntity, AlarmControlPanel):
|
||||||
"""Representation of a Homekit Alarm Control Panel."""
|
"""Representation of a Homekit Alarm Control Panel."""
|
||||||
|
|
||||||
def __init__(self, *args):
|
|
||||||
"""Initialise the Alarm Control Panel."""
|
|
||||||
super().__init__(*args)
|
|
||||||
self._state = None
|
|
||||||
self._battery_level = None
|
|
||||||
|
|
||||||
def get_characteristic_types(self):
|
def get_characteristic_types(self):
|
||||||
"""Define the homekit characteristics the entity cares about."""
|
"""Define the homekit characteristics the entity cares about."""
|
||||||
return [
|
return [
|
||||||
|
@ -74,12 +68,6 @@ class HomeKitAlarmControlPanel(HomeKitEntity, AlarmControlPanel):
|
||||||
CharacteristicsTypes.BATTERY_LEVEL,
|
CharacteristicsTypes.BATTERY_LEVEL,
|
||||||
]
|
]
|
||||||
|
|
||||||
def _update_security_system_state_current(self, value):
|
|
||||||
self._state = CURRENT_STATE_MAP[value]
|
|
||||||
|
|
||||||
def _update_battery_level(self, value):
|
|
||||||
self._battery_level = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def icon(self):
|
def icon(self):
|
||||||
"""Return icon."""
|
"""Return icon."""
|
||||||
|
@ -88,7 +76,9 @@ class HomeKitAlarmControlPanel(HomeKitEntity, AlarmControlPanel):
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the state of the device."""
|
"""Return the state of the device."""
|
||||||
return self._state
|
return CURRENT_STATE_MAP[
|
||||||
|
self.service.value(CharacteristicsTypes.SECURITY_SYSTEM_STATE_CURRENT)
|
||||||
|
]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self) -> int:
|
def supported_features(self) -> int:
|
||||||
|
@ -125,7 +115,10 @@ class HomeKitAlarmControlPanel(HomeKitEntity, AlarmControlPanel):
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
"""Return the optional state attributes."""
|
"""Return the optional state attributes."""
|
||||||
if self._battery_level is None:
|
attributes = {}
|
||||||
return None
|
|
||||||
|
|
||||||
return {ATTR_BATTERY_LEVEL: self._battery_level}
|
battery_level = self.service.value(CharacteristicsTypes.BATTERY_LEVEL)
|
||||||
|
if battery_level:
|
||||||
|
attributes[ATTR_BATTERY_LEVEL] = battery_level
|
||||||
|
|
||||||
|
return attributes
|
||||||
|
|
|
@ -20,18 +20,10 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
class HomeKitMotionSensor(HomeKitEntity, BinarySensorDevice):
|
class HomeKitMotionSensor(HomeKitEntity, BinarySensorDevice):
|
||||||
"""Representation of a Homekit motion sensor."""
|
"""Representation of a Homekit motion sensor."""
|
||||||
|
|
||||||
def __init__(self, *args):
|
|
||||||
"""Initialise the entity."""
|
|
||||||
super().__init__(*args)
|
|
||||||
self._on = False
|
|
||||||
|
|
||||||
def get_characteristic_types(self):
|
def get_characteristic_types(self):
|
||||||
"""Define the homekit characteristics the entity is tracking."""
|
"""Define the homekit characteristics the entity is tracking."""
|
||||||
return [CharacteristicsTypes.MOTION_DETECTED]
|
return [CharacteristicsTypes.MOTION_DETECTED]
|
||||||
|
|
||||||
def _update_motion_detected(self, value):
|
|
||||||
self._on = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_class(self):
|
def device_class(self):
|
||||||
"""Define this binary_sensor as a motion sensor."""
|
"""Define this binary_sensor as a motion sensor."""
|
||||||
|
@ -40,24 +32,16 @@ class HomeKitMotionSensor(HomeKitEntity, BinarySensorDevice):
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
"""Has motion been detected."""
|
"""Has motion been detected."""
|
||||||
return self._on
|
return self.service.value(CharacteristicsTypes.MOTION_DETECTED)
|
||||||
|
|
||||||
|
|
||||||
class HomeKitContactSensor(HomeKitEntity, BinarySensorDevice):
|
class HomeKitContactSensor(HomeKitEntity, BinarySensorDevice):
|
||||||
"""Representation of a Homekit contact sensor."""
|
"""Representation of a Homekit contact sensor."""
|
||||||
|
|
||||||
def __init__(self, *args):
|
|
||||||
"""Initialise the entity."""
|
|
||||||
super().__init__(*args)
|
|
||||||
self._state = None
|
|
||||||
|
|
||||||
def get_characteristic_types(self):
|
def get_characteristic_types(self):
|
||||||
"""Define the homekit characteristics the entity is tracking."""
|
"""Define the homekit characteristics the entity is tracking."""
|
||||||
return [CharacteristicsTypes.CONTACT_STATE]
|
return [CharacteristicsTypes.CONTACT_STATE]
|
||||||
|
|
||||||
def _update_contact_state(self, value):
|
|
||||||
self._state = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_class(self):
|
def device_class(self):
|
||||||
"""Define this binary_sensor as a opening sensor."""
|
"""Define this binary_sensor as a opening sensor."""
|
||||||
|
@ -66,17 +50,12 @@ class HomeKitContactSensor(HomeKitEntity, BinarySensorDevice):
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
"""Return true if the binary sensor is on/open."""
|
"""Return true if the binary sensor is on/open."""
|
||||||
return self._state == 1
|
return self.service.value(CharacteristicsTypes.CONTACT_STATE) == 1
|
||||||
|
|
||||||
|
|
||||||
class HomeKitSmokeSensor(HomeKitEntity, BinarySensorDevice):
|
class HomeKitSmokeSensor(HomeKitEntity, BinarySensorDevice):
|
||||||
"""Representation of a Homekit smoke sensor."""
|
"""Representation of a Homekit smoke sensor."""
|
||||||
|
|
||||||
def __init__(self, *args):
|
|
||||||
"""Initialise the entity."""
|
|
||||||
super().__init__(*args)
|
|
||||||
self._state = None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_class(self) -> str:
|
def device_class(self) -> str:
|
||||||
"""Return the class of this sensor."""
|
"""Return the class of this sensor."""
|
||||||
|
@ -86,22 +65,14 @@ class HomeKitSmokeSensor(HomeKitEntity, BinarySensorDevice):
|
||||||
"""Define the homekit characteristics the entity is tracking."""
|
"""Define the homekit characteristics the entity is tracking."""
|
||||||
return [CharacteristicsTypes.SMOKE_DETECTED]
|
return [CharacteristicsTypes.SMOKE_DETECTED]
|
||||||
|
|
||||||
def _update_smoke_detected(self, value):
|
|
||||||
self._state = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
"""Return true if smoke is currently detected."""
|
"""Return true if smoke is currently detected."""
|
||||||
return self._state == 1
|
return self.service.value(CharacteristicsTypes.SMOKE_DETECTED) == 1
|
||||||
|
|
||||||
|
|
||||||
class HomeKitOccupancySensor(HomeKitEntity, BinarySensorDevice):
|
class HomeKitOccupancySensor(HomeKitEntity, BinarySensorDevice):
|
||||||
"""Representation of a Homekit smoke sensor."""
|
"""Representation of a Homekit occupancy sensor."""
|
||||||
|
|
||||||
def __init__(self, *args):
|
|
||||||
"""Initialise the entity."""
|
|
||||||
super().__init__(*args)
|
|
||||||
self._state = None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_class(self) -> str:
|
def device_class(self) -> str:
|
||||||
|
@ -112,13 +83,10 @@ class HomeKitOccupancySensor(HomeKitEntity, BinarySensorDevice):
|
||||||
"""Define the homekit characteristics the entity is tracking."""
|
"""Define the homekit characteristics the entity is tracking."""
|
||||||
return [CharacteristicsTypes.OCCUPANCY_DETECTED]
|
return [CharacteristicsTypes.OCCUPANCY_DETECTED]
|
||||||
|
|
||||||
def _update_occupancy_detected(self, value):
|
|
||||||
self._state = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
"""Return true if smoke is currently detected."""
|
"""Return true if occupancy is currently detected."""
|
||||||
return self._state == 1
|
return self.service.value(CharacteristicsTypes.OCCUPANCY_DETECTED) == 1
|
||||||
|
|
||||||
|
|
||||||
ENTITY_TYPES = {
|
ENTITY_TYPES = {
|
||||||
|
|
|
@ -67,14 +67,7 @@ class HomeKitClimateDevice(HomeKitEntity, ClimateDevice):
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
"""Initialise the device."""
|
"""Initialise the device."""
|
||||||
self._state = None
|
|
||||||
self._target_mode = None
|
|
||||||
self._current_mode = None
|
|
||||||
self._valid_modes = []
|
self._valid_modes = []
|
||||||
self._current_temp = None
|
|
||||||
self._target_temp = None
|
|
||||||
self._current_humidity = None
|
|
||||||
self._target_humidity = None
|
|
||||||
self._min_target_temp = None
|
self._min_target_temp = None
|
||||||
self._max_target_temp = None
|
self._max_target_temp = None
|
||||||
self._min_target_humidity = DEFAULT_MIN_HUMIDITY
|
self._min_target_humidity = DEFAULT_MIN_HUMIDITY
|
||||||
|
@ -130,31 +123,6 @@ class HomeKitClimateDevice(HomeKitEntity, ClimateDevice):
|
||||||
if "maxValue" in characteristic:
|
if "maxValue" in characteristic:
|
||||||
self._max_target_humidity = characteristic["maxValue"]
|
self._max_target_humidity = characteristic["maxValue"]
|
||||||
|
|
||||||
def _update_heating_cooling_current(self, value):
|
|
||||||
# This characteristic describes the current mode of a device,
|
|
||||||
# e.g. a thermostat is "heating" a room to 75 degrees Fahrenheit.
|
|
||||||
# Can be 0 - 2 (Off, Heat, Cool)
|
|
||||||
self._current_mode = CURRENT_MODE_HOMEKIT_TO_HASS.get(value)
|
|
||||||
|
|
||||||
def _update_heating_cooling_target(self, value):
|
|
||||||
# This characteristic describes the target mode
|
|
||||||
# E.g. should the device start heating a room if the temperature
|
|
||||||
# falls below the target temperature.
|
|
||||||
# Can be 0 - 3 (Off, Heat, Cool, Auto)
|
|
||||||
self._target_mode = MODE_HOMEKIT_TO_HASS.get(value)
|
|
||||||
|
|
||||||
def _update_temperature_current(self, value):
|
|
||||||
self._current_temp = value
|
|
||||||
|
|
||||||
def _update_temperature_target(self, value):
|
|
||||||
self._target_temp = value
|
|
||||||
|
|
||||||
def _update_relative_humidity_current(self, value):
|
|
||||||
self._current_humidity = value
|
|
||||||
|
|
||||||
def _update_relative_humidity_target(self, value):
|
|
||||||
self._target_humidity = value
|
|
||||||
|
|
||||||
async def async_set_temperature(self, **kwargs):
|
async def async_set_temperature(self, **kwargs):
|
||||||
"""Set new target temperature."""
|
"""Set new target temperature."""
|
||||||
temp = kwargs.get(ATTR_TEMPERATURE)
|
temp = kwargs.get(ATTR_TEMPERATURE)
|
||||||
|
@ -189,12 +157,12 @@ class HomeKitClimateDevice(HomeKitEntity, ClimateDevice):
|
||||||
@property
|
@property
|
||||||
def current_temperature(self):
|
def current_temperature(self):
|
||||||
"""Return the current temperature."""
|
"""Return the current temperature."""
|
||||||
return self._current_temp
|
return self.service.value(CharacteristicsTypes.TEMPERATURE_CURRENT)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target_temperature(self):
|
def target_temperature(self):
|
||||||
"""Return the temperature we try to reach."""
|
"""Return the temperature we try to reach."""
|
||||||
return self._target_temp
|
return self.service.value(CharacteristicsTypes.TEMPERATURE_TARGET)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def min_temp(self):
|
def min_temp(self):
|
||||||
|
@ -213,12 +181,12 @@ class HomeKitClimateDevice(HomeKitEntity, ClimateDevice):
|
||||||
@property
|
@property
|
||||||
def current_humidity(self):
|
def current_humidity(self):
|
||||||
"""Return the current humidity."""
|
"""Return the current humidity."""
|
||||||
return self._current_humidity
|
return self.service.value(CharacteristicsTypes.RELATIVE_HUMIDITY_CURRENT)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target_humidity(self):
|
def target_humidity(self):
|
||||||
"""Return the humidity we try to reach."""
|
"""Return the humidity we try to reach."""
|
||||||
return self._target_humidity
|
return self.service.value(CharacteristicsTypes.RELATIVE_HUMIDITY_TARGET)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def min_humidity(self):
|
def min_humidity(self):
|
||||||
|
@ -233,12 +201,21 @@ class HomeKitClimateDevice(HomeKitEntity, ClimateDevice):
|
||||||
@property
|
@property
|
||||||
def hvac_action(self):
|
def hvac_action(self):
|
||||||
"""Return the current running hvac operation."""
|
"""Return the current running hvac operation."""
|
||||||
return self._current_mode
|
# This characteristic describes the current mode of a device,
|
||||||
|
# e.g. a thermostat is "heating" a room to 75 degrees Fahrenheit.
|
||||||
|
# Can be 0 - 2 (Off, Heat, Cool)
|
||||||
|
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_CURRENT)
|
||||||
|
return CURRENT_MODE_HOMEKIT_TO_HASS.get(value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hvac_mode(self):
|
def hvac_mode(self):
|
||||||
"""Return hvac operation ie. heat, cool mode."""
|
"""Return hvac operation ie. heat, cool mode."""
|
||||||
return self._target_mode
|
# This characteristic describes the target mode
|
||||||
|
# E.g. should the device start heating a room if the temperature
|
||||||
|
# falls below the target temperature.
|
||||||
|
# Can be 0 - 3 (Off, Heat, Cool, Auto)
|
||||||
|
value = self.service.value(CharacteristicsTypes.HEATING_COOLING_TARGET)
|
||||||
|
return MODE_HOMEKIT_TO_HASS.get(value)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hvac_modes(self):
|
def hvac_modes(self):
|
||||||
|
|
|
@ -61,13 +61,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
class HomeKitGarageDoorCover(HomeKitEntity, CoverDevice):
|
class HomeKitGarageDoorCover(HomeKitEntity, CoverDevice):
|
||||||
"""Representation of a HomeKit Garage Door."""
|
"""Representation of a HomeKit Garage Door."""
|
||||||
|
|
||||||
def __init__(self, accessory, discovery_info):
|
|
||||||
"""Initialise the Cover."""
|
|
||||||
super().__init__(accessory, discovery_info)
|
|
||||||
self._state = None
|
|
||||||
self._obstruction_detected = None
|
|
||||||
self.lock_state = None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_class(self):
|
def device_class(self):
|
||||||
"""Define this cover as a garage door."""
|
"""Define this cover as a garage door."""
|
||||||
|
@ -81,31 +74,31 @@ class HomeKitGarageDoorCover(HomeKitEntity, CoverDevice):
|
||||||
CharacteristicsTypes.OBSTRUCTION_DETECTED,
|
CharacteristicsTypes.OBSTRUCTION_DETECTED,
|
||||||
]
|
]
|
||||||
|
|
||||||
def _update_door_state_current(self, value):
|
|
||||||
self._state = CURRENT_GARAGE_STATE_MAP[value]
|
|
||||||
|
|
||||||
def _update_obstruction_detected(self, value):
|
|
||||||
self._obstruction_detected = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
"""Flag supported features."""
|
"""Flag supported features."""
|
||||||
return SUPPORT_OPEN | SUPPORT_CLOSE
|
return SUPPORT_OPEN | SUPPORT_CLOSE
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
"""Return the current state of the garage door."""
|
||||||
|
value = self.service.value(CharacteristicsTypes.DOOR_STATE_CURRENT)
|
||||||
|
return CURRENT_GARAGE_STATE_MAP[value]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_closed(self):
|
def is_closed(self):
|
||||||
"""Return true if cover is closed, else False."""
|
"""Return true if cover is closed, else False."""
|
||||||
return self._state == STATE_CLOSED
|
return self.state == STATE_CLOSED
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_closing(self):
|
def is_closing(self):
|
||||||
"""Return if the cover is closing or not."""
|
"""Return if the cover is closing or not."""
|
||||||
return self._state == STATE_CLOSING
|
return self.state == STATE_CLOSING
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_opening(self):
|
def is_opening(self):
|
||||||
"""Return if the cover is opening or not."""
|
"""Return if the cover is opening or not."""
|
||||||
return self._state == STATE_OPENING
|
return self.state == STATE_OPENING
|
||||||
|
|
||||||
async def async_open_cover(self, **kwargs):
|
async def async_open_cover(self, **kwargs):
|
||||||
"""Send open command."""
|
"""Send open command."""
|
||||||
|
@ -129,10 +122,15 @@ class HomeKitGarageDoorCover(HomeKitEntity, CoverDevice):
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
"""Return the optional state attributes."""
|
"""Return the optional state attributes."""
|
||||||
if self._obstruction_detected is None:
|
attributes = {}
|
||||||
return None
|
|
||||||
|
|
||||||
return {"obstruction-detected": self._obstruction_detected}
|
obstruction_detected = self.service.value(
|
||||||
|
CharacteristicsTypes.OBSTRUCTION_DETECTED
|
||||||
|
)
|
||||||
|
if obstruction_detected:
|
||||||
|
attributes["obstruction-detected"] = obstruction_detected
|
||||||
|
|
||||||
|
return attributes
|
||||||
|
|
||||||
|
|
||||||
class HomeKitWindowCover(HomeKitEntity, CoverDevice):
|
class HomeKitWindowCover(HomeKitEntity, CoverDevice):
|
||||||
|
@ -141,11 +139,7 @@ class HomeKitWindowCover(HomeKitEntity, CoverDevice):
|
||||||
def __init__(self, accessory, discovery_info):
|
def __init__(self, accessory, discovery_info):
|
||||||
"""Initialise the Cover."""
|
"""Initialise the Cover."""
|
||||||
super().__init__(accessory, discovery_info)
|
super().__init__(accessory, discovery_info)
|
||||||
self._state = None
|
|
||||||
self._position = None
|
|
||||||
self._tilt_position = None
|
|
||||||
self._obstruction_detected = None
|
|
||||||
self.lock_state = None
|
|
||||||
self._features = SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_SET_POSITION
|
self._features = SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_SET_POSITION
|
||||||
|
|
||||||
def get_characteristic_types(self):
|
def get_characteristic_types(self):
|
||||||
|
@ -175,21 +169,6 @@ class HomeKitWindowCover(HomeKitEntity, CoverDevice):
|
||||||
SUPPORT_OPEN_TILT | SUPPORT_CLOSE_TILT | SUPPORT_SET_TILT_POSITION
|
SUPPORT_OPEN_TILT | SUPPORT_CLOSE_TILT | SUPPORT_SET_TILT_POSITION
|
||||||
)
|
)
|
||||||
|
|
||||||
def _update_position_state(self, value):
|
|
||||||
self._state = CURRENT_WINDOW_STATE_MAP[value]
|
|
||||||
|
|
||||||
def _update_position_current(self, value):
|
|
||||||
self._position = value
|
|
||||||
|
|
||||||
def _update_vertical_tilt_current(self, value):
|
|
||||||
self._tilt_position = value
|
|
||||||
|
|
||||||
def _update_horizontal_tilt_current(self, value):
|
|
||||||
self._tilt_position = value
|
|
||||||
|
|
||||||
def _update_obstruction_detected(self, value):
|
|
||||||
self._obstruction_detected = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
"""Flag supported features."""
|
"""Flag supported features."""
|
||||||
|
@ -198,22 +177,36 @@ class HomeKitWindowCover(HomeKitEntity, CoverDevice):
|
||||||
@property
|
@property
|
||||||
def current_cover_position(self):
|
def current_cover_position(self):
|
||||||
"""Return the current position of cover."""
|
"""Return the current position of cover."""
|
||||||
return self._position
|
return self.service.value(CharacteristicsTypes.POSITION_CURRENT)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_closed(self):
|
def is_closed(self):
|
||||||
"""Return true if cover is closed, else False."""
|
"""Return true if cover is closed, else False."""
|
||||||
return self._position == 0
|
return self.current_cover_position == 0
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_closing(self):
|
def is_closing(self):
|
||||||
"""Return if the cover is closing or not."""
|
"""Return if the cover is closing or not."""
|
||||||
return self._state == STATE_CLOSING
|
value = self.service.value(CharacteristicsTypes.POSITION_STATE)
|
||||||
|
state = CURRENT_WINDOW_STATE_MAP[value]
|
||||||
|
return state == STATE_CLOSING
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_opening(self):
|
def is_opening(self):
|
||||||
"""Return if the cover is opening or not."""
|
"""Return if the cover is opening or not."""
|
||||||
return self._state == STATE_OPENING
|
value = self.service.value(CharacteristicsTypes.POSITION_STATE)
|
||||||
|
state = CURRENT_WINDOW_STATE_MAP[value]
|
||||||
|
return state == STATE_OPENING
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_cover_tilt_position(self):
|
||||||
|
"""Return current position of cover tilt."""
|
||||||
|
tilt_position = self.service.value(CharacteristicsTypes.VERTICAL_TILT_CURRENT)
|
||||||
|
if not tilt_position:
|
||||||
|
tilt_position = self.service.value(
|
||||||
|
CharacteristicsTypes.HORIZONTAL_TILT_CURRENT
|
||||||
|
)
|
||||||
|
return tilt_position
|
||||||
|
|
||||||
async def async_stop_cover(self, **kwargs):
|
async def async_stop_cover(self, **kwargs):
|
||||||
"""Send hold command."""
|
"""Send hold command."""
|
||||||
|
@ -238,11 +231,6 @@ class HomeKitWindowCover(HomeKitEntity, CoverDevice):
|
||||||
]
|
]
|
||||||
await self._accessory.put_characteristics(characteristics)
|
await self._accessory.put_characteristics(characteristics)
|
||||||
|
|
||||||
@property
|
|
||||||
def current_cover_tilt_position(self):
|
|
||||||
"""Return current position of cover tilt."""
|
|
||||||
return self._tilt_position
|
|
||||||
|
|
||||||
async def async_set_cover_tilt_position(self, **kwargs):
|
async def async_set_cover_tilt_position(self, **kwargs):
|
||||||
"""Move the cover tilt to a specific position."""
|
"""Move the cover tilt to a specific position."""
|
||||||
tilt_position = kwargs[ATTR_TILT_POSITION]
|
tilt_position = kwargs[ATTR_TILT_POSITION]
|
||||||
|
@ -268,8 +256,12 @@ class HomeKitWindowCover(HomeKitEntity, CoverDevice):
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
"""Return the optional state attributes."""
|
"""Return the optional state attributes."""
|
||||||
state_attributes = {}
|
attributes = {}
|
||||||
if self._obstruction_detected is not None:
|
|
||||||
state_attributes["obstruction-detected"] = self._obstruction_detected
|
|
||||||
|
|
||||||
return state_attributes
|
obstruction_detected = self.service.value(
|
||||||
|
CharacteristicsTypes.OBSTRUCTION_DETECTED
|
||||||
|
)
|
||||||
|
if obstruction_detected:
|
||||||
|
attributes["obstruction-detected"] = obstruction_detected
|
||||||
|
|
||||||
|
return attributes
|
||||||
|
|
|
@ -46,12 +46,7 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
"""Initialise the fan."""
|
"""Initialise the fan."""
|
||||||
self._on = None
|
|
||||||
self._features = 0
|
self._features = 0
|
||||||
self._rotation_direction = 0
|
|
||||||
self._rotation_speed = 0
|
|
||||||
self._swing_mode = 0
|
|
||||||
|
|
||||||
super().__init__(*args)
|
super().__init__(*args)
|
||||||
|
|
||||||
def get_characteristic_types(self):
|
def get_characteristic_types(self):
|
||||||
|
@ -71,31 +66,23 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
|
||||||
def _setup_swing_mode(self, char):
|
def _setup_swing_mode(self, char):
|
||||||
self._features |= SUPPORT_OSCILLATE
|
self._features |= SUPPORT_OSCILLATE
|
||||||
|
|
||||||
def _update_rotation_direction(self, value):
|
|
||||||
self._rotation_direction = value
|
|
||||||
|
|
||||||
def _update_rotation_speed(self, value):
|
|
||||||
self._rotation_speed = value
|
|
||||||
|
|
||||||
def _update_swing_mode(self, value):
|
|
||||||
self._swing_mode = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def is_on(self):
|
|
||||||
"""Return true if device is on."""
|
|
||||||
return self._on
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def speed(self):
|
def speed(self):
|
||||||
"""Return the current speed."""
|
"""Return the current speed."""
|
||||||
if not self.is_on:
|
if not self.is_on:
|
||||||
return SPEED_OFF
|
return SPEED_OFF
|
||||||
if self._rotation_speed > SPEED_TO_PCNT[SPEED_MEDIUM]:
|
|
||||||
|
rotation_speed = self.service.value(CharacteristicsTypes.ROTATION_SPEED)
|
||||||
|
|
||||||
|
if rotation_speed > SPEED_TO_PCNT[SPEED_MEDIUM]:
|
||||||
return SPEED_HIGH
|
return SPEED_HIGH
|
||||||
if self._rotation_speed > SPEED_TO_PCNT[SPEED_LOW]:
|
|
||||||
|
if rotation_speed > SPEED_TO_PCNT[SPEED_LOW]:
|
||||||
return SPEED_MEDIUM
|
return SPEED_MEDIUM
|
||||||
if self._rotation_speed > SPEED_TO_PCNT[SPEED_OFF]:
|
|
||||||
|
if rotation_speed > SPEED_TO_PCNT[SPEED_OFF]:
|
||||||
return SPEED_LOW
|
return SPEED_LOW
|
||||||
|
|
||||||
return SPEED_OFF
|
return SPEED_OFF
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -108,12 +95,14 @@ class BaseHomeKitFan(HomeKitEntity, FanEntity):
|
||||||
@property
|
@property
|
||||||
def current_direction(self):
|
def current_direction(self):
|
||||||
"""Return the current direction of the fan."""
|
"""Return the current direction of the fan."""
|
||||||
return HK_DIRECTION_TO_HA[self._rotation_direction]
|
direction = self.service.value(CharacteristicsTypes.ROTATION_DIRECTION)
|
||||||
|
return HK_DIRECTION_TO_HA[direction]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def oscillating(self):
|
def oscillating(self):
|
||||||
"""Return whether or not the fan is currently oscillating."""
|
"""Return whether or not the fan is currently oscillating."""
|
||||||
return self._swing_mode == 1
|
oscillating = self.service.value(CharacteristicsTypes.SWING_MODE)
|
||||||
|
return oscillating == 1
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
|
@ -208,8 +197,10 @@ class HomeKitFanV1(BaseHomeKitFan):
|
||||||
"""Define the homekit characteristics the entity cares about."""
|
"""Define the homekit characteristics the entity cares about."""
|
||||||
return [CharacteristicsTypes.ON] + super().get_characteristic_types()
|
return [CharacteristicsTypes.ON] + super().get_characteristic_types()
|
||||||
|
|
||||||
def _update_on(self, value):
|
@property
|
||||||
self._on = value == 1
|
def is_on(self):
|
||||||
|
"""Return true if device is on."""
|
||||||
|
return self.service.value(CharacteristicsTypes.ON) == 1
|
||||||
|
|
||||||
|
|
||||||
class HomeKitFanV2(BaseHomeKitFan):
|
class HomeKitFanV2(BaseHomeKitFan):
|
||||||
|
@ -221,8 +212,10 @@ class HomeKitFanV2(BaseHomeKitFan):
|
||||||
"""Define the homekit characteristics the entity cares about."""
|
"""Define the homekit characteristics the entity cares about."""
|
||||||
return [CharacteristicsTypes.ACTIVE] + super().get_characteristic_types()
|
return [CharacteristicsTypes.ACTIVE] + super().get_characteristic_types()
|
||||||
|
|
||||||
def _update_active(self, value):
|
@property
|
||||||
self._on = value == 1
|
def is_on(self):
|
||||||
|
"""Return true if device is on."""
|
||||||
|
return self.service.value(CharacteristicsTypes.ACTIVE) == 1
|
||||||
|
|
||||||
|
|
||||||
ENTITY_TYPES = {
|
ENTITY_TYPES = {
|
||||||
|
|
|
@ -38,15 +38,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
class HomeKitLight(HomeKitEntity, Light):
|
class HomeKitLight(HomeKitEntity, Light):
|
||||||
"""Representation of a Homekit light."""
|
"""Representation of a Homekit light."""
|
||||||
|
|
||||||
def __init__(self, *args):
|
|
||||||
"""Initialise the light."""
|
|
||||||
super().__init__(*args)
|
|
||||||
self._on = False
|
|
||||||
self._brightness = 0
|
|
||||||
self._color_temperature = 0
|
|
||||||
self._hue = 0
|
|
||||||
self._saturation = 0
|
|
||||||
|
|
||||||
def get_characteristic_types(self):
|
def get_characteristic_types(self):
|
||||||
"""Define the homekit characteristics the entity cares about."""
|
"""Define the homekit characteristics the entity cares about."""
|
||||||
return [
|
return [
|
||||||
|
@ -69,40 +60,28 @@ class HomeKitLight(HomeKitEntity, Light):
|
||||||
def _setup_saturation(self, char):
|
def _setup_saturation(self, char):
|
||||||
self._features |= SUPPORT_COLOR
|
self._features |= SUPPORT_COLOR
|
||||||
|
|
||||||
def _update_on(self, value):
|
|
||||||
self._on = value
|
|
||||||
|
|
||||||
def _update_brightness(self, value):
|
|
||||||
self._brightness = value
|
|
||||||
|
|
||||||
def _update_color_temperature(self, value):
|
|
||||||
self._color_temperature = value
|
|
||||||
|
|
||||||
def _update_hue(self, value):
|
|
||||||
self._hue = value
|
|
||||||
|
|
||||||
def _update_saturation(self, value):
|
|
||||||
self._saturation = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
"""Return true if device is on."""
|
"""Return true if device is on."""
|
||||||
return self._on
|
return self.service.value(CharacteristicsTypes.ON)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def brightness(self):
|
def brightness(self):
|
||||||
"""Return the brightness of this light between 0..255."""
|
"""Return the brightness of this light between 0..255."""
|
||||||
return self._brightness * 255 / 100
|
return self.service.value(CharacteristicsTypes.BRIGHTNESS) * 255 / 100
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def hs_color(self):
|
def hs_color(self):
|
||||||
"""Return the color property."""
|
"""Return the color property."""
|
||||||
return (self._hue, self._saturation)
|
return (
|
||||||
|
self.service.value(CharacteristicsTypes.HUE),
|
||||||
|
self.service.value(CharacteristicsTypes.SATURATION),
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def color_temp(self):
|
def color_temp(self):
|
||||||
"""Return the color temperature."""
|
"""Return the color temperature."""
|
||||||
return self._color_temperature
|
return self.service.value(CharacteristicsTypes.COLOR_TEMPERATURE)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
|
|
|
@ -37,12 +37,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
class HomeKitLock(HomeKitEntity, LockDevice):
|
class HomeKitLock(HomeKitEntity, LockDevice):
|
||||||
"""Representation of a HomeKit Controller Lock."""
|
"""Representation of a HomeKit Controller Lock."""
|
||||||
|
|
||||||
def __init__(self, accessory, discovery_info):
|
|
||||||
"""Initialise the Lock."""
|
|
||||||
super().__init__(accessory, discovery_info)
|
|
||||||
self._state = None
|
|
||||||
self._battery_level = None
|
|
||||||
|
|
||||||
def get_characteristic_types(self):
|
def get_characteristic_types(self):
|
||||||
"""Define the homekit characteristics the entity cares about."""
|
"""Define the homekit characteristics the entity cares about."""
|
||||||
return [
|
return [
|
||||||
|
@ -51,16 +45,11 @@ class HomeKitLock(HomeKitEntity, LockDevice):
|
||||||
CharacteristicsTypes.BATTERY_LEVEL,
|
CharacteristicsTypes.BATTERY_LEVEL,
|
||||||
]
|
]
|
||||||
|
|
||||||
def _update_lock_mechanism_current_state(self, value):
|
|
||||||
self._state = CURRENT_STATE_MAP[value]
|
|
||||||
|
|
||||||
def _update_battery_level(self, value):
|
|
||||||
self._battery_level = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_locked(self):
|
def is_locked(self):
|
||||||
"""Return true if device is locked."""
|
"""Return true if device is locked."""
|
||||||
return self._state == STATE_LOCKED
|
value = self.service.value(CharacteristicsTypes.LOCK_MECHANISM_CURRENT_STATE)
|
||||||
|
return CURRENT_STATE_MAP[value] == STATE_LOCKED
|
||||||
|
|
||||||
async def async_lock(self, **kwargs):
|
async def async_lock(self, **kwargs):
|
||||||
"""Lock the device."""
|
"""Lock the device."""
|
||||||
|
@ -84,7 +73,10 @@ class HomeKitLock(HomeKitEntity, LockDevice):
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
"""Return the optional state attributes."""
|
"""Return the optional state attributes."""
|
||||||
if self._battery_level is None:
|
attributes = {}
|
||||||
return None
|
|
||||||
|
|
||||||
return {ATTR_BATTERY_LEVEL: self._battery_level}
|
battery_level = self.service.value(CharacteristicsTypes.BATTERY_LEVEL)
|
||||||
|
if battery_level:
|
||||||
|
attributes[ATTR_BATTERY_LEVEL] = battery_level
|
||||||
|
|
||||||
|
return attributes
|
||||||
|
|
|
@ -130,9 +130,7 @@ class HomeKitTelevision(HomeKitEntity, MediaPlayerDevice):
|
||||||
@property
|
@property
|
||||||
def source(self):
|
def source(self):
|
||||||
"""Name of the current input source."""
|
"""Name of the current input source."""
|
||||||
active_identifier = self.get_hk_char_value(
|
active_identifier = self.service.value(CharacteristicsTypes.ACTIVE_IDENTIFIER)
|
||||||
CharacteristicsTypes.ACTIVE_IDENTIFIER
|
|
||||||
)
|
|
||||||
if not active_identifier:
|
if not active_identifier:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -150,11 +148,11 @@ class HomeKitTelevision(HomeKitEntity, MediaPlayerDevice):
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""State of the tv."""
|
"""State of the tv."""
|
||||||
active = self.get_hk_char_value(CharacteristicsTypes.ACTIVE)
|
active = self.service.value(CharacteristicsTypes.ACTIVE)
|
||||||
if not active:
|
if not active:
|
||||||
return STATE_PROBLEM
|
return STATE_PROBLEM
|
||||||
|
|
||||||
homekit_state = self.get_hk_char_value(CharacteristicsTypes.CURRENT_MEDIA_STATE)
|
homekit_state = self.service.value(CharacteristicsTypes.CURRENT_MEDIA_STATE)
|
||||||
if homekit_state is not None:
|
if homekit_state is not None:
|
||||||
return HK_TO_HA_STATE[homekit_state]
|
return HK_TO_HA_STATE[homekit_state]
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,6 @@ UNIT_LUX = "lux"
|
||||||
class HomeKitHumiditySensor(HomeKitEntity):
|
class HomeKitHumiditySensor(HomeKitEntity):
|
||||||
"""Representation of a Homekit humidity sensor."""
|
"""Representation of a Homekit humidity sensor."""
|
||||||
|
|
||||||
def __init__(self, *args):
|
|
||||||
"""Initialise the entity."""
|
|
||||||
super().__init__(*args)
|
|
||||||
self._state = None
|
|
||||||
|
|
||||||
def get_characteristic_types(self):
|
def get_characteristic_types(self):
|
||||||
"""Define the homekit characteristics the entity is tracking."""
|
"""Define the homekit characteristics the entity is tracking."""
|
||||||
return [CharacteristicsTypes.RELATIVE_HUMIDITY_CURRENT]
|
return [CharacteristicsTypes.RELATIVE_HUMIDITY_CURRENT]
|
||||||
|
@ -54,23 +49,15 @@ class HomeKitHumiditySensor(HomeKitEntity):
|
||||||
"""Return units for the sensor."""
|
"""Return units for the sensor."""
|
||||||
return UNIT_PERCENTAGE
|
return UNIT_PERCENTAGE
|
||||||
|
|
||||||
def _update_relative_humidity_current(self, value):
|
|
||||||
self._state = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the current humidity."""
|
"""Return the current humidity."""
|
||||||
return self._state
|
return self.service.value(CharacteristicsTypes.RELATIVE_HUMIDITY_CURRENT)
|
||||||
|
|
||||||
|
|
||||||
class HomeKitTemperatureSensor(HomeKitEntity):
|
class HomeKitTemperatureSensor(HomeKitEntity):
|
||||||
"""Representation of a Homekit temperature sensor."""
|
"""Representation of a Homekit temperature sensor."""
|
||||||
|
|
||||||
def __init__(self, *args):
|
|
||||||
"""Initialise the entity."""
|
|
||||||
super().__init__(*args)
|
|
||||||
self._state = None
|
|
||||||
|
|
||||||
def get_characteristic_types(self):
|
def get_characteristic_types(self):
|
||||||
"""Define the homekit characteristics the entity is tracking."""
|
"""Define the homekit characteristics the entity is tracking."""
|
||||||
return [CharacteristicsTypes.TEMPERATURE_CURRENT]
|
return [CharacteristicsTypes.TEMPERATURE_CURRENT]
|
||||||
|
@ -95,23 +82,15 @@ class HomeKitTemperatureSensor(HomeKitEntity):
|
||||||
"""Return units for the sensor."""
|
"""Return units for the sensor."""
|
||||||
return TEMP_CELSIUS
|
return TEMP_CELSIUS
|
||||||
|
|
||||||
def _update_temperature_current(self, value):
|
|
||||||
self._state = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the current temperature in Celsius."""
|
"""Return the current temperature in Celsius."""
|
||||||
return self._state
|
return self.service.value(CharacteristicsTypes.TEMPERATURE_CURRENT)
|
||||||
|
|
||||||
|
|
||||||
class HomeKitLightSensor(HomeKitEntity):
|
class HomeKitLightSensor(HomeKitEntity):
|
||||||
"""Representation of a Homekit light level sensor."""
|
"""Representation of a Homekit light level sensor."""
|
||||||
|
|
||||||
def __init__(self, *args):
|
|
||||||
"""Initialise the entity."""
|
|
||||||
super().__init__(*args)
|
|
||||||
self._state = None
|
|
||||||
|
|
||||||
def get_characteristic_types(self):
|
def get_characteristic_types(self):
|
||||||
"""Define the homekit characteristics the entity is tracking."""
|
"""Define the homekit characteristics the entity is tracking."""
|
||||||
return [CharacteristicsTypes.LIGHT_LEVEL_CURRENT]
|
return [CharacteristicsTypes.LIGHT_LEVEL_CURRENT]
|
||||||
|
@ -136,23 +115,15 @@ class HomeKitLightSensor(HomeKitEntity):
|
||||||
"""Return units for the sensor."""
|
"""Return units for the sensor."""
|
||||||
return UNIT_LUX
|
return UNIT_LUX
|
||||||
|
|
||||||
def _update_light_level_current(self, value):
|
|
||||||
self._state = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the current light level in lux."""
|
"""Return the current light level in lux."""
|
||||||
return self._state
|
return self.service.value(CharacteristicsTypes.LIGHT_LEVEL_CURRENT)
|
||||||
|
|
||||||
|
|
||||||
class HomeKitCarbonDioxideSensor(HomeKitEntity):
|
class HomeKitCarbonDioxideSensor(HomeKitEntity):
|
||||||
"""Representation of a Homekit Carbon Dioxide sensor."""
|
"""Representation of a Homekit Carbon Dioxide sensor."""
|
||||||
|
|
||||||
def __init__(self, *args):
|
|
||||||
"""Initialise the entity."""
|
|
||||||
super().__init__(*args)
|
|
||||||
self._state = None
|
|
||||||
|
|
||||||
def get_characteristic_types(self):
|
def get_characteristic_types(self):
|
||||||
"""Define the homekit characteristics the entity is tracking."""
|
"""Define the homekit characteristics the entity is tracking."""
|
||||||
return [CharacteristicsTypes.CARBON_DIOXIDE_LEVEL]
|
return [CharacteristicsTypes.CARBON_DIOXIDE_LEVEL]
|
||||||
|
@ -172,25 +143,15 @@ class HomeKitCarbonDioxideSensor(HomeKitEntity):
|
||||||
"""Return units for the sensor."""
|
"""Return units for the sensor."""
|
||||||
return CONCENTRATION_PARTS_PER_MILLION
|
return CONCENTRATION_PARTS_PER_MILLION
|
||||||
|
|
||||||
def _update_carbon_dioxide_level(self, value):
|
|
||||||
self._state = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the current CO2 level in ppm."""
|
"""Return the current CO2 level in ppm."""
|
||||||
return self._state
|
return self.service.value(CharacteristicsTypes.CARBON_DIOXIDE_LEVEL)
|
||||||
|
|
||||||
|
|
||||||
class HomeKitBatterySensor(HomeKitEntity):
|
class HomeKitBatterySensor(HomeKitEntity):
|
||||||
"""Representation of a Homekit battery sensor."""
|
"""Representation of a Homekit battery sensor."""
|
||||||
|
|
||||||
def __init__(self, *args):
|
|
||||||
"""Initialise the entity."""
|
|
||||||
super().__init__(*args)
|
|
||||||
self._state = None
|
|
||||||
self._low_battery = False
|
|
||||||
self._charging = False
|
|
||||||
|
|
||||||
def get_characteristic_types(self):
|
def get_characteristic_types(self):
|
||||||
"""Define the homekit characteristics the entity is tracking."""
|
"""Define the homekit characteristics the entity is tracking."""
|
||||||
return [
|
return [
|
||||||
|
@ -218,12 +179,12 @@ class HomeKitBatterySensor(HomeKitEntity):
|
||||||
# This is similar to the logic in helpers.icon, but we have delegated the
|
# This is similar to the logic in helpers.icon, but we have delegated the
|
||||||
# decision about what mdi:battery-alert is to the device.
|
# decision about what mdi:battery-alert is to the device.
|
||||||
icon = "mdi:battery"
|
icon = "mdi:battery"
|
||||||
if self._charging and self.state > 10:
|
if self.is_charging and self.state > 10:
|
||||||
percentage = int(round(self.state / 20 - 0.01)) * 20
|
percentage = int(round(self.state / 20 - 0.01)) * 20
|
||||||
icon += f"-charging-{percentage}"
|
icon += f"-charging-{percentage}"
|
||||||
elif self._charging:
|
elif self.is_charging:
|
||||||
icon += "-outline"
|
icon += "-outline"
|
||||||
elif self._low_battery:
|
elif self.is_low_battery:
|
||||||
icon += "-alert"
|
icon += "-alert"
|
||||||
elif self.state < 95:
|
elif self.state < 95:
|
||||||
percentage = max(int(round(self.state / 10 - 0.01)) * 10, 10)
|
percentage = max(int(round(self.state / 10 - 0.01)) * 10, 10)
|
||||||
|
@ -236,22 +197,23 @@ class HomeKitBatterySensor(HomeKitEntity):
|
||||||
"""Return units for the sensor."""
|
"""Return units for the sensor."""
|
||||||
return UNIT_PERCENTAGE
|
return UNIT_PERCENTAGE
|
||||||
|
|
||||||
def _update_battery_level(self, value):
|
@property
|
||||||
self._state = value
|
def is_low_battery(self):
|
||||||
|
"""Return true if battery level is low."""
|
||||||
|
return self.service.value(CharacteristicsTypes.STATUS_LO_BATT) == 1
|
||||||
|
|
||||||
def _update_status_lo_batt(self, value):
|
@property
|
||||||
self._low_battery = value == 1
|
def is_charging(self):
|
||||||
|
"""Return true if currently charing."""
|
||||||
def _update_charging_state(self, value):
|
|
||||||
# 0 = not charging
|
# 0 = not charging
|
||||||
# 1 = charging
|
# 1 = charging
|
||||||
# 2 = not chargeable
|
# 2 = not chargeable
|
||||||
self._charging = value == 1
|
return self.service.value(CharacteristicsTypes.CHARGING_STATE) == 1
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the current battery level percentage."""
|
"""Return the current battery level percentage."""
|
||||||
return self._state
|
return self.service.value(CharacteristicsTypes.BATTERY_LEVEL)
|
||||||
|
|
||||||
|
|
||||||
ENTITY_TYPES = {
|
ENTITY_TYPES = {
|
||||||
|
|
|
@ -32,30 +32,17 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
class HomeKitSwitch(HomeKitEntity, SwitchDevice):
|
class HomeKitSwitch(HomeKitEntity, SwitchDevice):
|
||||||
"""Representation of a Homekit switch."""
|
"""Representation of a Homekit switch."""
|
||||||
|
|
||||||
def __init__(self, *args):
|
|
||||||
"""Initialise the switch."""
|
|
||||||
super().__init__(*args)
|
|
||||||
self._on = None
|
|
||||||
self._outlet_in_use = None
|
|
||||||
|
|
||||||
def get_characteristic_types(self):
|
def get_characteristic_types(self):
|
||||||
"""Define the homekit characteristics the entity cares about."""
|
"""Define the homekit characteristics the entity cares about."""
|
||||||
return [CharacteristicsTypes.ON, CharacteristicsTypes.OUTLET_IN_USE]
|
return [CharacteristicsTypes.ON, CharacteristicsTypes.OUTLET_IN_USE]
|
||||||
|
|
||||||
def _update_on(self, value):
|
|
||||||
self._on = value
|
|
||||||
|
|
||||||
def _update_outlet_in_use(self, value):
|
|
||||||
self._outlet_in_use = value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
"""Return true if device is on."""
|
"""Return true if device is on."""
|
||||||
return self._on
|
return self.service.value(CharacteristicsTypes.ON)
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs):
|
async def async_turn_on(self, **kwargs):
|
||||||
"""Turn the specified switch on."""
|
"""Turn the specified switch on."""
|
||||||
self._on = True
|
|
||||||
characteristics = [{"aid": self._aid, "iid": self._chars["on"], "value": True}]
|
characteristics = [{"aid": self._aid, "iid": self._chars["on"], "value": True}]
|
||||||
await self._accessory.put_characteristics(characteristics)
|
await self._accessory.put_characteristics(characteristics)
|
||||||
|
|
||||||
|
@ -67,5 +54,6 @@ class HomeKitSwitch(HomeKitEntity, SwitchDevice):
|
||||||
@property
|
@property
|
||||||
def device_state_attributes(self):
|
def device_state_attributes(self):
|
||||||
"""Return the optional state attributes."""
|
"""Return the optional state attributes."""
|
||||||
if self._outlet_in_use is not None:
|
outlet_in_use = self.service.value(CharacteristicsTypes.OUTLET_IN_USE)
|
||||||
return {OUTLET_IN_USE: self._outlet_in_use}
|
if outlet_in_use is not None:
|
||||||
|
return {OUTLET_IN_USE: outlet_in_use}
|
||||||
|
|
Loading…
Add table
Reference in a new issue