mirror of
https://github.com/home-assistant/core.git
synced 2025-07-25 22:27:07 +00:00
Add support for homekit controller sensors (#21535)
Adds support for homekit devices with temperature, humidity, and light level characteristics (such as the iHome iSS50)
This commit is contained in:
parent
82bdd9568d
commit
84b84559a4
@ -25,6 +25,9 @@ HOMEKIT_ACCESSORY_DISPATCH = {
|
|||||||
'window-covering': 'cover',
|
'window-covering': 'cover',
|
||||||
'lock-mechanism': 'lock',
|
'lock-mechanism': 'lock',
|
||||||
'motion': 'binary_sensor',
|
'motion': 'binary_sensor',
|
||||||
|
'humidity': 'sensor',
|
||||||
|
'light': 'sensor',
|
||||||
|
'temperature': 'sensor'
|
||||||
}
|
}
|
||||||
|
|
||||||
HOMEKIT_IGNORE = [
|
HOMEKIT_IGNORE = [
|
||||||
|
153
homeassistant/components/homekit_controller/sensor.py
Normal file
153
homeassistant/components/homekit_controller/sensor.py
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
"""Support for Homekit sensors."""
|
||||||
|
from homeassistant.components.homekit_controller import (
|
||||||
|
KNOWN_ACCESSORIES, HomeKitEntity)
|
||||||
|
from homeassistant.const import TEMP_CELSIUS
|
||||||
|
|
||||||
|
DEPENDENCIES = ['homekit_controller']
|
||||||
|
|
||||||
|
HUMIDITY_ICON = 'mdi-water-percent'
|
||||||
|
TEMP_C_ICON = "mdi-temperature-celsius"
|
||||||
|
BRIGHTNESS_ICON = "mdi-brightness-6"
|
||||||
|
|
||||||
|
UNIT_PERCENT = "%"
|
||||||
|
UNIT_LUX = "lux"
|
||||||
|
|
||||||
|
|
||||||
|
def setup_platform(hass, config, add_entities, discovery_info=None):
|
||||||
|
"""Set up Homekit sensor support."""
|
||||||
|
if discovery_info is not None:
|
||||||
|
accessory = hass.data[KNOWN_ACCESSORIES][discovery_info['serial']]
|
||||||
|
devtype = discovery_info['device-type']
|
||||||
|
|
||||||
|
if devtype == 'humidity':
|
||||||
|
add_entities(
|
||||||
|
[HomeKitHumiditySensor(accessory, discovery_info)], True)
|
||||||
|
elif devtype == 'temperature':
|
||||||
|
add_entities(
|
||||||
|
[HomeKitTemperatureSensor(accessory, discovery_info)], True)
|
||||||
|
elif devtype == 'light':
|
||||||
|
add_entities(
|
||||||
|
[HomeKitLightSensor(accessory, discovery_info)], True)
|
||||||
|
|
||||||
|
|
||||||
|
class HomeKitHumiditySensor(HomeKitEntity):
|
||||||
|
"""Representation of a Homekit humidity sensor."""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""Initialise the entity."""
|
||||||
|
super().__init__(*args)
|
||||||
|
self._state = None
|
||||||
|
|
||||||
|
def get_characteristic_types(self):
|
||||||
|
"""Define the homekit characteristics the entity is tracking."""
|
||||||
|
# pylint: disable=import-error
|
||||||
|
from homekit.model.characteristics import CharacteristicsTypes
|
||||||
|
|
||||||
|
return [
|
||||||
|
CharacteristicsTypes.RELATIVE_HUMIDITY_CURRENT
|
||||||
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name of the device."""
|
||||||
|
return "{} {}".format(super().name, "Humidity")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def icon(self):
|
||||||
|
"""Return the sensor icon."""
|
||||||
|
return HUMIDITY_ICON
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unit_of_measurement(self):
|
||||||
|
"""Return units for the sensor."""
|
||||||
|
return UNIT_PERCENT
|
||||||
|
|
||||||
|
def _update_relative_humidity_current(self, value):
|
||||||
|
self._state = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
"""Return the current humidity."""
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
|
||||||
|
class HomeKitTemperatureSensor(HomeKitEntity):
|
||||||
|
"""Representation of a Homekit temperature sensor."""
|
||||||
|
|
||||||
|
def __init__(self, *args):
|
||||||
|
"""Initialise the entity."""
|
||||||
|
super().__init__(*args)
|
||||||
|
self._state = None
|
||||||
|
|
||||||
|
def get_characteristic_types(self):
|
||||||
|
"""Define the homekit characteristics the entity is tracking."""
|
||||||
|
# pylint: disable=import-error
|
||||||
|
from homekit.model.characteristics import CharacteristicsTypes
|
||||||
|
|
||||||
|
return [
|
||||||
|
CharacteristicsTypes.TEMPERATURE_CURRENT
|
||||||
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name of the device."""
|
||||||
|
return "{} {}".format(super().name, "Temperature")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def icon(self):
|
||||||
|
"""Return the sensor icon."""
|
||||||
|
return TEMP_C_ICON
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unit_of_measurement(self):
|
||||||
|
"""Return units for the sensor."""
|
||||||
|
return TEMP_CELSIUS
|
||||||
|
|
||||||
|
def _update_temperature_current(self, value):
|
||||||
|
self._state = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
"""Return the current temperature in Celsius."""
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
|
||||||
|
class HomeKitLightSensor(HomeKitEntity):
|
||||||
|
"""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):
|
||||||
|
"""Define the homekit characteristics the entity is tracking."""
|
||||||
|
# pylint: disable=import-error
|
||||||
|
from homekit.model.characteristics import CharacteristicsTypes
|
||||||
|
|
||||||
|
return [
|
||||||
|
CharacteristicsTypes.LIGHT_LEVEL_CURRENT
|
||||||
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
"""Return the name of the device."""
|
||||||
|
return "{} {}".format(super().name, "Light Level")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def icon(self):
|
||||||
|
"""Return the sensor icon."""
|
||||||
|
return BRIGHTNESS_ICON
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unit_of_measurement(self):
|
||||||
|
"""Return units for the sensor."""
|
||||||
|
return UNIT_LUX
|
||||||
|
|
||||||
|
def _update_light_level_current(self, value):
|
||||||
|
self._state = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
"""Return the current light level in lux."""
|
||||||
|
return self._state
|
@ -134,10 +134,12 @@ class FakeService(AbstractService):
|
|||||||
return char
|
return char
|
||||||
|
|
||||||
|
|
||||||
async def setup_test_component(hass, services, capitalize=False):
|
async def setup_test_component(hass, services, capitalize=False, suffix=None):
|
||||||
"""Load a fake homekit accessory based on a homekit accessory model.
|
"""Load a fake homekit accessory based on a homekit accessory model.
|
||||||
|
|
||||||
If capitalize is True, property names will be in upper case.
|
If capitalize is True, property names will be in upper case.
|
||||||
|
|
||||||
|
If suffix is set, entityId will include the suffix
|
||||||
"""
|
"""
|
||||||
domain = None
|
domain = None
|
||||||
for service in services:
|
for service in services:
|
||||||
@ -174,4 +176,5 @@ async def setup_test_component(hass, services, capitalize=False):
|
|||||||
fire_service_discovered(hass, SERVICE_HOMEKIT, discovery_info)
|
fire_service_discovered(hass, SERVICE_HOMEKIT, discovery_info)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
return Helper(hass, '.'.join((domain, 'testdevice')), pairing, accessory)
|
entity = 'testdevice' if suffix is None else 'testdevice_{}'.format(suffix)
|
||||||
|
return Helper(hass, '.'.join((domain, entity)), pairing, accessory)
|
||||||
|
79
tests/components/homekit_controller/test_sensor.py
Normal file
79
tests/components/homekit_controller/test_sensor.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
"""Basic checks for HomeKit sensor."""
|
||||||
|
from tests.components.homekit_controller.common import (
|
||||||
|
FakeService, setup_test_component)
|
||||||
|
|
||||||
|
TEMPERATURE = ('temperature', 'temperature.current')
|
||||||
|
HUMIDITY = ('humidity', 'relative-humidity.current')
|
||||||
|
LIGHT_LEVEL = ('light', 'light-level.current')
|
||||||
|
|
||||||
|
|
||||||
|
def create_temperature_sensor_service():
|
||||||
|
"""Define temperature characteristics."""
|
||||||
|
service = FakeService('public.hap.service.sensor.temperature')
|
||||||
|
|
||||||
|
cur_state = service.add_characteristic('temperature.current')
|
||||||
|
cur_state.value = 0
|
||||||
|
|
||||||
|
return service
|
||||||
|
|
||||||
|
|
||||||
|
def create_humidity_sensor_service():
|
||||||
|
"""Define humidity characteristics."""
|
||||||
|
service = FakeService('public.hap.service.sensor.humidity')
|
||||||
|
|
||||||
|
cur_state = service.add_characteristic('relative-humidity.current')
|
||||||
|
cur_state.value = 0
|
||||||
|
|
||||||
|
return service
|
||||||
|
|
||||||
|
|
||||||
|
def create_light_level_sensor_service():
|
||||||
|
"""Define light level characteristics."""
|
||||||
|
service = FakeService('public.hap.service.sensor.light')
|
||||||
|
|
||||||
|
cur_state = service.add_characteristic('light-level.current')
|
||||||
|
cur_state.value = 0
|
||||||
|
|
||||||
|
return service
|
||||||
|
|
||||||
|
|
||||||
|
async def test_temperature_sensor_read_state(hass, utcnow):
|
||||||
|
"""Test reading the state of a HomeKit temperature sensor accessory."""
|
||||||
|
sensor = create_temperature_sensor_service()
|
||||||
|
helper = await setup_test_component(hass, [sensor], suffix="temperature")
|
||||||
|
|
||||||
|
helper.characteristics[TEMPERATURE].value = 10
|
||||||
|
state = await helper.poll_and_get_state()
|
||||||
|
assert state.state == '10'
|
||||||
|
|
||||||
|
helper.characteristics[TEMPERATURE].value = 20
|
||||||
|
state = await helper.poll_and_get_state()
|
||||||
|
assert state.state == '20'
|
||||||
|
|
||||||
|
|
||||||
|
async def test_humidity_sensor_read_state(hass, utcnow):
|
||||||
|
"""Test reading the state of a HomeKit humidity sensor accessory."""
|
||||||
|
sensor = create_humidity_sensor_service()
|
||||||
|
helper = await setup_test_component(hass, [sensor], suffix="humidity")
|
||||||
|
|
||||||
|
helper.characteristics[HUMIDITY].value = 10
|
||||||
|
state = await helper.poll_and_get_state()
|
||||||
|
assert state.state == '10'
|
||||||
|
|
||||||
|
helper.characteristics[HUMIDITY].value = 20
|
||||||
|
state = await helper.poll_and_get_state()
|
||||||
|
assert state.state == '20'
|
||||||
|
|
||||||
|
|
||||||
|
async def test_light_level_sensor_read_state(hass, utcnow):
|
||||||
|
"""Test reading the state of a HomeKit temperature sensor accessory."""
|
||||||
|
sensor = create_light_level_sensor_service()
|
||||||
|
helper = await setup_test_component(hass, [sensor], suffix="light_level")
|
||||||
|
|
||||||
|
helper.characteristics[LIGHT_LEVEL].value = 10
|
||||||
|
state = await helper.poll_and_get_state()
|
||||||
|
assert state.state == '10'
|
||||||
|
|
||||||
|
helper.characteristics[LIGHT_LEVEL].value = 20
|
||||||
|
state = await helper.poll_and_get_state()
|
||||||
|
assert state.state == '20'
|
Loading…
x
Reference in New Issue
Block a user