Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions homeassistant/components/homekit_controller/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
'window-covering': 'cover',
'lock-mechanism': 'lock',
'motion': 'binary_sensor',
'humidity': 'sensor',
'light': 'sensor',
'temperature': 'sensor'
}

HOMEKIT_IGNORE = [
Expand Down
153 changes: 153 additions & 0 deletions homeassistant/components/homekit_controller/sensor.py
Original file line number Diff line number Diff line change
@@ -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
7 changes: 5 additions & 2 deletions tests/components/homekit_controller/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,12 @@ def add_characteristic(self, name):
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.

If capitalize is True, property names will be in upper case.

If suffix is set, entityId will include the suffix
"""
domain = None
for service in services:
Expand Down Expand Up @@ -174,4 +176,5 @@ async def setup_test_component(hass, services, capitalize=False):
fire_service_discovered(hass, SERVICE_HOMEKIT, discovery_info)
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 changes: 79 additions & 0 deletions tests/components/homekit_controller/test_sensor.py
Original file line number Diff line number Diff line change
@@ -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'