Support CO2/PM2.5/Light sensors in HomeKit (#13804)
* Support co2/light/air sensor in HomeKit * Add tests * Added tests * changed device_class lux to lightpull/13836/head
parent
f47572d3c0
commit
c863b9614c
|
@ -11,7 +11,7 @@ import voluptuous as vol
|
|||
from homeassistant.components.cover import SUPPORT_SET_POSITION
|
||||
from homeassistant.const import (
|
||||
ATTR_SUPPORTED_FEATURES, ATTR_UNIT_OF_MEASUREMENT,
|
||||
CONF_PORT, TEMP_CELSIUS, TEMP_FAHRENHEIT,
|
||||
ATTR_DEVICE_CLASS, CONF_PORT, TEMP_CELSIUS, TEMP_FAHRENHEIT,
|
||||
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP)
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entityfilter import FILTER_SCHEMA
|
||||
|
@ -19,7 +19,9 @@ from homeassistant.util import get_local_ip
|
|||
from homeassistant.util.decorator import Registry
|
||||
from .const import (
|
||||
DOMAIN, HOMEKIT_FILE, CONF_AUTO_START, CONF_ENTITY_CONFIG, CONF_FILTER,
|
||||
DEFAULT_PORT, DEFAULT_AUTO_START, SERVICE_HOMEKIT_START)
|
||||
DEFAULT_PORT, DEFAULT_AUTO_START, SERVICE_HOMEKIT_START,
|
||||
DEVICE_CLASS_CO2, DEVICE_CLASS_LIGHT, DEVICE_CLASS_HUMIDITY,
|
||||
DEVICE_CLASS_PM25, DEVICE_CLASS_TEMPERATURE)
|
||||
from .util import (
|
||||
validate_entity_config, show_setup_message)
|
||||
|
||||
|
@ -103,10 +105,22 @@ def get_accessory(hass, state, aid, config):
|
|||
|
||||
elif state.domain == 'sensor':
|
||||
unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
|
||||
if unit == TEMP_CELSIUS or unit == TEMP_FAHRENHEIT:
|
||||
device_class = state.attributes.get(ATTR_DEVICE_CLASS)
|
||||
|
||||
if device_class == DEVICE_CLASS_TEMPERATURE or unit == TEMP_CELSIUS \
|
||||
or unit == TEMP_FAHRENHEIT:
|
||||
a_type = 'TemperatureSensor'
|
||||
elif unit == '%':
|
||||
elif device_class == DEVICE_CLASS_HUMIDITY or unit == '%':
|
||||
a_type = 'HumiditySensor'
|
||||
elif device_class == DEVICE_CLASS_PM25 \
|
||||
or DEVICE_CLASS_PM25 in state.entity_id:
|
||||
a_type = 'AirQualitySensor'
|
||||
elif device_class == DEVICE_CLASS_CO2 \
|
||||
or DEVICE_CLASS_CO2 in state.entity_id:
|
||||
a_type = 'CarbonDioxideSensor'
|
||||
elif device_class == DEVICE_CLASS_LIGHT or unit == 'lm' or \
|
||||
unit == 'lux':
|
||||
a_type = 'LightSensor'
|
||||
|
||||
elif state.domain == 'switch' or state.domain == 'remote' \
|
||||
or state.domain == 'input_boolean' or state.domain == 'script':
|
||||
|
|
|
@ -34,13 +34,13 @@ CATEGORY_WINDOW_COVERING = 'WINDOW_COVERING'
|
|||
|
||||
# #### Services ####
|
||||
SERV_ACCESSORY_INFO = 'AccessoryInformation'
|
||||
SERV_AIR_QUALITY_SENSOR = 'AirQualitySensor'
|
||||
SERV_CARBON_DIOXIDE_SENSOR = 'CarbonDioxideSensor'
|
||||
SERV_CARBON_MONOXIDE_SENSOR = 'CarbonMonoxideSensor'
|
||||
SERV_CONTACT_SENSOR = 'ContactSensor'
|
||||
SERV_HUMIDITY_SENSOR = 'HumiditySensor'
|
||||
# CurrentRelativeHumidity | StatusActive, StatusFault, StatusTampered,
|
||||
# StatusLowBattery, Name
|
||||
SERV_HUMIDITY_SENSOR = 'HumiditySensor' # CurrentRelativeHumidity
|
||||
SERV_LEAK_SENSOR = 'LeakSensor'
|
||||
SERV_LIGHT_SENSOR = 'LightSensor'
|
||||
SERV_LIGHTBULB = 'Lightbulb' # On | Brightness, Hue, Saturation, Name
|
||||
SERV_LOCK = 'LockMechanism'
|
||||
SERV_MOTION_SENSOR = 'MotionSensor'
|
||||
|
@ -50,17 +50,21 @@ SERV_SMOKE_SENSOR = 'SmokeSensor'
|
|||
SERV_SWITCH = 'Switch'
|
||||
SERV_TEMPERATURE_SENSOR = 'TemperatureSensor'
|
||||
SERV_THERMOSTAT = 'Thermostat'
|
||||
SERV_WINDOW_COVERING = 'WindowCovering'
|
||||
# CurrentPosition, TargetPosition, PositionState
|
||||
SERV_WINDOW_COVERING = 'WindowCovering' # CurrentPosition, TargetPosition
|
||||
|
||||
|
||||
# #### Characteristics ####
|
||||
CHAR_AIR_PARTICULATE_DENSITY = 'AirParticulateDensity'
|
||||
CHAR_AIR_QUALITY = 'AirQuality'
|
||||
CHAR_BRIGHTNESS = 'Brightness' # Int | [0, 100]
|
||||
CHAR_CARBON_DIOXIDE_DETECTED = 'CarbonDioxideDetected'
|
||||
CHAR_CARBON_DIOXIDE_LEVEL = 'CarbonDioxideLevel'
|
||||
CHAR_CARBON_DIOXIDE_PEAK_LEVEL = 'CarbonDioxidePeakLevel'
|
||||
CHAR_CARBON_MONOXIDE_DETECTED = 'CarbonMonoxideDetected'
|
||||
CHAR_COLOR_TEMPERATURE = 'ColorTemperature'
|
||||
CHAR_CONTACT_SENSOR_STATE = 'ContactSensorState'
|
||||
CHAR_COOLING_THRESHOLD_TEMPERATURE = 'CoolingThresholdTemperature'
|
||||
CHAR_CURRENT_AMBIENT_LIGHT_LEVEL = 'CurrentAmbientLightLevel'
|
||||
CHAR_CURRENT_HEATING_COOLING = 'CurrentHeatingCoolingState'
|
||||
CHAR_CURRENT_POSITION = 'CurrentPosition' # Int | [0, 100]
|
||||
CHAR_CURRENT_HUMIDITY = 'CurrentRelativeHumidity' # percent
|
||||
|
@ -93,8 +97,12 @@ PROP_CELSIUS = {'minValue': -273, 'maxValue': 999}
|
|||
# #### Device Class ####
|
||||
DEVICE_CLASS_CO2 = 'co2'
|
||||
DEVICE_CLASS_GAS = 'gas'
|
||||
DEVICE_CLASS_HUMIDITY = 'humidity'
|
||||
DEVICE_CLASS_LIGHT = 'light'
|
||||
DEVICE_CLASS_MOISTURE = 'moisture'
|
||||
DEVICE_CLASS_MOTION = 'motion'
|
||||
DEVICE_CLASS_OCCUPANCY = 'occupancy'
|
||||
DEVICE_CLASS_OPENING = 'opening'
|
||||
DEVICE_CLASS_PM25 = 'pm25'
|
||||
DEVICE_CLASS_SMOKE = 'smoke'
|
||||
DEVICE_CLASS_TEMPERATURE = 'temperature'
|
||||
|
|
|
@ -10,6 +10,9 @@ from .accessories import HomeAccessory, add_preload_service, setup_char
|
|||
from .const import (
|
||||
CATEGORY_SENSOR, SERV_HUMIDITY_SENSOR, SERV_TEMPERATURE_SENSOR,
|
||||
CHAR_CURRENT_HUMIDITY, CHAR_CURRENT_TEMPERATURE, PROP_CELSIUS,
|
||||
SERV_AIR_QUALITY_SENSOR, CHAR_AIR_QUALITY, CHAR_AIR_PARTICULATE_DENSITY,
|
||||
CHAR_CARBON_DIOXIDE_LEVEL, CHAR_CARBON_DIOXIDE_PEAK_LEVEL,
|
||||
SERV_LIGHT_SENSOR, CHAR_CURRENT_AMBIENT_LIGHT_LEVEL,
|
||||
DEVICE_CLASS_CO2, SERV_CARBON_DIOXIDE_SENSOR, CHAR_CARBON_DIOXIDE_DETECTED,
|
||||
DEVICE_CLASS_GAS, SERV_CARBON_MONOXIDE_SENSOR,
|
||||
CHAR_CARBON_MONOXIDE_DETECTED,
|
||||
|
@ -18,7 +21,8 @@ from .const import (
|
|||
DEVICE_CLASS_OCCUPANCY, SERV_OCCUPANCY_SENSOR, CHAR_OCCUPANCY_DETECTED,
|
||||
DEVICE_CLASS_OPENING, SERV_CONTACT_SENSOR, CHAR_CONTACT_SENSOR_STATE,
|
||||
DEVICE_CLASS_SMOKE, SERV_SMOKE_SENSOR, CHAR_SMOKE_DETECTED)
|
||||
from .util import convert_to_float, temperature_to_homekit
|
||||
from .util import (
|
||||
convert_to_float, temperature_to_homekit, density_to_air_quality)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -81,6 +85,78 @@ class HumiditySensor(HomeAccessory):
|
|||
self.entity_id, humidity)
|
||||
|
||||
|
||||
@TYPES.register('AirQualitySensor')
|
||||
class AirQualitySensor(HomeAccessory):
|
||||
"""Generate a AirQualitySensor accessory as air quality sensor."""
|
||||
|
||||
def __init__(self, *args, config):
|
||||
"""Initialize a AirQualitySensor accessory object."""
|
||||
super().__init__(*args, category=CATEGORY_SENSOR)
|
||||
|
||||
serv_air_quality = add_preload_service(self, SERV_AIR_QUALITY_SENSOR,
|
||||
[CHAR_AIR_PARTICULATE_DENSITY])
|
||||
self.char_quality = setup_char(
|
||||
CHAR_AIR_QUALITY, serv_air_quality, value=0)
|
||||
self.char_density = setup_char(
|
||||
CHAR_AIR_PARTICULATE_DENSITY, serv_air_quality, value=0)
|
||||
|
||||
def update_state(self, new_state):
|
||||
"""Update accessory after state change."""
|
||||
density = convert_to_float(new_state.state)
|
||||
if density is not None:
|
||||
self.char_density.set_value(density)
|
||||
self.char_quality.set_value(density_to_air_quality(density))
|
||||
_LOGGER.debug('%s: Set to %d', self.entity_id, density)
|
||||
|
||||
|
||||
@TYPES.register('CarbonDioxideSensor')
|
||||
class CarbonDioxideSensor(HomeAccessory):
|
||||
"""Generate a CarbonDioxideSensor accessory as CO2 sensor."""
|
||||
|
||||
def __init__(self, *args, config):
|
||||
"""Initialize a CarbonDioxideSensor accessory object."""
|
||||
super().__init__(*args, category=CATEGORY_SENSOR)
|
||||
|
||||
serv_co2 = add_preload_service(self, SERV_CARBON_DIOXIDE_SENSOR, [
|
||||
CHAR_CARBON_DIOXIDE_LEVEL, CHAR_CARBON_DIOXIDE_PEAK_LEVEL])
|
||||
self.char_co2 = setup_char(
|
||||
CHAR_CARBON_DIOXIDE_LEVEL, serv_co2, value=0)
|
||||
self.char_peak = setup_char(
|
||||
CHAR_CARBON_DIOXIDE_PEAK_LEVEL, serv_co2, value=0)
|
||||
self.char_detected = setup_char(
|
||||
CHAR_CARBON_DIOXIDE_DETECTED, serv_co2, value=0)
|
||||
|
||||
def update_state(self, new_state):
|
||||
"""Update accessory after state change."""
|
||||
co2 = convert_to_float(new_state.state)
|
||||
if co2 is not None:
|
||||
self.char_co2.set_value(co2)
|
||||
if co2 > self.char_peak.value:
|
||||
self.char_peak.set_value(co2)
|
||||
self.char_detected.set_value(co2 > 1000)
|
||||
_LOGGER.debug('%s: Set to %d', self.entity_id, co2)
|
||||
|
||||
|
||||
@TYPES.register('LightSensor')
|
||||
class LightSensor(HomeAccessory):
|
||||
"""Generate a LightSensor accessory as light sensor."""
|
||||
|
||||
def __init__(self, *args, config):
|
||||
"""Initialize a LightSensor accessory object."""
|
||||
super().__init__(*args, category=CATEGORY_SENSOR)
|
||||
|
||||
serv_light = add_preload_service(self, SERV_LIGHT_SENSOR)
|
||||
self.char_light = setup_char(
|
||||
CHAR_CURRENT_AMBIENT_LIGHT_LEVEL, serv_light, value=0)
|
||||
|
||||
def update_state(self, new_state):
|
||||
"""Update accessory after state change."""
|
||||
luminance = convert_to_float(new_state.state)
|
||||
if luminance is not None:
|
||||
self.char_light.set_value(luminance)
|
||||
_LOGGER.debug('%s: Set to %d', self.entity_id, luminance)
|
||||
|
||||
|
||||
@TYPES.register('BinarySensor')
|
||||
class BinarySensor(HomeAccessory):
|
||||
"""Generate a BinarySensor accessory as binary sensor."""
|
||||
|
|
|
@ -64,3 +64,16 @@ def temperature_to_homekit(temperature, unit):
|
|||
def temperature_to_states(temperature, unit):
|
||||
"""Convert temperature back from Celsius to Home Assistant unit."""
|
||||
return round(temp_util.convert(temperature, TEMP_CELSIUS, unit), 1)
|
||||
|
||||
|
||||
def density_to_air_quality(density):
|
||||
"""Map PM2.5 density to HomeKit AirQuality level."""
|
||||
if density <= 35:
|
||||
return 1
|
||||
elif density <= 75:
|
||||
return 2
|
||||
elif density <= 115:
|
||||
return 3
|
||||
elif density <= 150:
|
||||
return 4
|
||||
return 5
|
||||
|
|
|
@ -41,6 +41,13 @@ class TestGetAccessories(unittest.TestCase):
|
|||
"""Test if mock type was called."""
|
||||
self.assertTrue(self.mock_type.called)
|
||||
|
||||
def test_sensor_temperature(self):
|
||||
"""Test temperature sensor with device class temperature."""
|
||||
with patch.dict(TYPES, {'TemperatureSensor': self.mock_type}):
|
||||
state = State('sensor.temperature', '23',
|
||||
{ATTR_DEVICE_CLASS: 'temperature'})
|
||||
get_accessory(None, state, 2, {})
|
||||
|
||||
def test_sensor_temperature_celsius(self):
|
||||
"""Test temperature sensor with Celsius as unit."""
|
||||
with patch.dict(TYPES, {'TemperatureSensor': self.mock_type}):
|
||||
|
@ -56,12 +63,66 @@ class TestGetAccessories(unittest.TestCase):
|
|||
get_accessory(None, state, 2, {})
|
||||
|
||||
def test_sensor_humidity(self):
|
||||
"""Test humidity sensor with device class humidity."""
|
||||
with patch.dict(TYPES, {'HumiditySensor': self.mock_type}):
|
||||
state = State('sensor.humidity', '20',
|
||||
{ATTR_DEVICE_CLASS: 'humidity'})
|
||||
get_accessory(None, state, 2, {})
|
||||
|
||||
def test_sensor_humidity_unit(self):
|
||||
"""Test humidity sensor with % as unit."""
|
||||
with patch.dict(TYPES, {'HumiditySensor': self.mock_type}):
|
||||
state = State('sensor.humidity', '20',
|
||||
{ATTR_UNIT_OF_MEASUREMENT: '%'})
|
||||
get_accessory(None, state, 2, {})
|
||||
|
||||
def test_air_quality_sensor(self):
|
||||
"""Test air quality sensor with pm25 class."""
|
||||
with patch.dict(TYPES, {'AirQualitySensor': self.mock_type}):
|
||||
state = State('sensor.air_quality', '40',
|
||||
{ATTR_DEVICE_CLASS: 'pm25'})
|
||||
get_accessory(None, state, 2, {})
|
||||
|
||||
def test_air_quality_sensor_entity_id(self):
|
||||
"""Test air quality sensor with entity_id contains pm25."""
|
||||
with patch.dict(TYPES, {'AirQualitySensor': self.mock_type}):
|
||||
state = State('sensor.air_quality_pm25', '40', {})
|
||||
get_accessory(None, state, 2, {})
|
||||
|
||||
def test_co2_sensor(self):
|
||||
"""Test co2 sensor with device class co2."""
|
||||
with patch.dict(TYPES, {'CarbonDioxideSensor': self.mock_type}):
|
||||
state = State('sensor.airmeter', '500',
|
||||
{ATTR_DEVICE_CLASS: 'co2'})
|
||||
get_accessory(None, state, 2, {})
|
||||
|
||||
def test_co2_sensor_entity_id(self):
|
||||
"""Test co2 sensor with entity_id contains co2."""
|
||||
with patch.dict(TYPES, {'CarbonDioxideSensor': self.mock_type}):
|
||||
state = State('sensor.airmeter_co2', '500', {})
|
||||
get_accessory(None, state, 2, {})
|
||||
|
||||
def test_light_sensor(self):
|
||||
"""Test light sensor with device class lux."""
|
||||
with patch.dict(TYPES, {'LightSensor': self.mock_type}):
|
||||
state = State('sensor.light', '900',
|
||||
{ATTR_DEVICE_CLASS: 'light'})
|
||||
get_accessory(None, state, 2, {})
|
||||
|
||||
def test_light_sensor_unit_lm(self):
|
||||
"""Test light sensor with lm as unit."""
|
||||
with patch.dict(TYPES, {'LightSensor': self.mock_type}):
|
||||
state = State('sensor.light', '900',
|
||||
{ATTR_UNIT_OF_MEASUREMENT: 'lm'})
|
||||
get_accessory(None, state, 2, {})
|
||||
|
||||
def test_light_sensor_unit_lux(self):
|
||||
"""Test light sensor with lux as unit."""
|
||||
with patch.dict(TYPES, {'LightSensor': self.mock_type}):
|
||||
state = State('sensor.light', '900',
|
||||
{ATTR_UNIT_OF_MEASUREMENT: 'lux'})
|
||||
get_accessory(None, state, 2, {})
|
||||
|
||||
def test_binary_sensor(self):
|
||||
"""Test binary sensor with opening class."""
|
||||
with patch.dict(TYPES, {'BinarySensor': self.mock_type}):
|
||||
|
|
|
@ -3,7 +3,8 @@ import unittest
|
|||
|
||||
from homeassistant.components.homekit.const import PROP_CELSIUS
|
||||
from homeassistant.components.homekit.type_sensors import (
|
||||
TemperatureSensor, HumiditySensor, BinarySensor, BINARY_SENSOR_SERVICE_MAP)
|
||||
TemperatureSensor, HumiditySensor, AirQualitySensor, CarbonDioxideSensor,
|
||||
LightSensor, BinarySensor, BINARY_SENSOR_SERVICE_MAP)
|
||||
from homeassistant.const import (
|
||||
ATTR_UNIT_OF_MEASUREMENT, ATTR_DEVICE_CLASS, STATE_UNKNOWN, STATE_ON,
|
||||
STATE_OFF, STATE_HOME, STATE_NOT_HOME, TEMP_CELSIUS, TEMP_FAHRENHEIT)
|
||||
|
@ -40,6 +41,7 @@ class TestHomekitSensors(unittest.TestCase):
|
|||
self.hass.states.set(entity_id, STATE_UNKNOWN,
|
||||
{ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS})
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(acc.char_temp.value, 0.0)
|
||||
|
||||
self.hass.states.set(entity_id, '20',
|
||||
{ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS})
|
||||
|
@ -63,14 +65,95 @@ class TestHomekitSensors(unittest.TestCase):
|
|||
|
||||
self.assertEqual(acc.char_humidity.value, 0)
|
||||
|
||||
self.hass.states.set(entity_id, STATE_UNKNOWN,
|
||||
{ATTR_UNIT_OF_MEASUREMENT: "%"})
|
||||
self.hass.states.set(entity_id, STATE_UNKNOWN)
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(acc.char_humidity.value, 0)
|
||||
|
||||
self.hass.states.set(entity_id, '20', {ATTR_UNIT_OF_MEASUREMENT: "%"})
|
||||
self.hass.states.set(entity_id, '20')
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(acc.char_humidity.value, 20)
|
||||
|
||||
def test_air_quality(self):
|
||||
"""Test if accessory is updated after state change."""
|
||||
entity_id = 'sensor.air_quality'
|
||||
|
||||
acc = AirQualitySensor(self.hass, 'Air Quality', entity_id,
|
||||
2, config=None)
|
||||
acc.run()
|
||||
|
||||
self.assertEqual(acc.aid, 2)
|
||||
self.assertEqual(acc.category, 10) # Sensor
|
||||
|
||||
self.assertEqual(acc.char_density.value, 0)
|
||||
self.assertEqual(acc.char_quality.value, 0)
|
||||
|
||||
self.hass.states.set(entity_id, STATE_UNKNOWN)
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(acc.char_density.value, 0)
|
||||
self.assertEqual(acc.char_quality.value, 0)
|
||||
|
||||
self.hass.states.set(entity_id, '34')
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(acc.char_density.value, 34)
|
||||
self.assertEqual(acc.char_quality.value, 1)
|
||||
|
||||
self.hass.states.set(entity_id, '200')
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(acc.char_density.value, 200)
|
||||
self.assertEqual(acc.char_quality.value, 5)
|
||||
|
||||
def test_co2(self):
|
||||
"""Test if accessory is updated after state change."""
|
||||
entity_id = 'sensor.co2'
|
||||
|
||||
acc = CarbonDioxideSensor(self.hass, 'CO2', entity_id, 2, config=None)
|
||||
acc.run()
|
||||
|
||||
self.assertEqual(acc.aid, 2)
|
||||
self.assertEqual(acc.category, 10) # Sensor
|
||||
|
||||
self.assertEqual(acc.char_co2.value, 0)
|
||||
self.assertEqual(acc.char_peak.value, 0)
|
||||
self.assertEqual(acc.char_detected.value, 0)
|
||||
|
||||
self.hass.states.set(entity_id, STATE_UNKNOWN)
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(acc.char_co2.value, 0)
|
||||
self.assertEqual(acc.char_peak.value, 0)
|
||||
self.assertEqual(acc.char_detected.value, 0)
|
||||
|
||||
self.hass.states.set(entity_id, '1100')
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(acc.char_co2.value, 1100)
|
||||
self.assertEqual(acc.char_peak.value, 1100)
|
||||
self.assertEqual(acc.char_detected.value, 1)
|
||||
|
||||
self.hass.states.set(entity_id, '800')
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(acc.char_co2.value, 800)
|
||||
self.assertEqual(acc.char_peak.value, 1100)
|
||||
self.assertEqual(acc.char_detected.value, 0)
|
||||
|
||||
def test_light(self):
|
||||
"""Test if accessory is updated after state change."""
|
||||
entity_id = 'sensor.light'
|
||||
|
||||
acc = LightSensor(self.hass, 'Light', entity_id, 2, config=None)
|
||||
acc.run()
|
||||
|
||||
self.assertEqual(acc.aid, 2)
|
||||
self.assertEqual(acc.category, 10) # Sensor
|
||||
|
||||
self.assertEqual(acc.char_light.value, 0.0001)
|
||||
|
||||
self.hass.states.set(entity_id, STATE_UNKNOWN)
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(acc.char_light.value, 0.0001)
|
||||
|
||||
self.hass.states.set(entity_id, '300')
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(acc.char_light.value, 300)
|
||||
|
||||
def test_binary(self):
|
||||
"""Test if accessory is updated after state change."""
|
||||
entity_id = 'binary_sensor.opening'
|
||||
|
|
|
@ -2,13 +2,15 @@
|
|||
import unittest
|
||||
|
||||
import voluptuous as vol
|
||||
import pytest
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.components.homekit.accessories import HomeBridge
|
||||
from homeassistant.components.homekit.const import HOMEKIT_NOTIFY_ID
|
||||
from homeassistant.components.homekit.util import (
|
||||
show_setup_message, dismiss_setup_message, convert_to_float,
|
||||
temperature_to_homekit, temperature_to_states, ATTR_CODE)
|
||||
temperature_to_homekit, temperature_to_states, ATTR_CODE,
|
||||
density_to_air_quality)
|
||||
from homeassistant.components.homekit.util import validate_entity_config \
|
||||
as vec
|
||||
from homeassistant.components.persistent_notification import (
|
||||
|
@ -20,6 +22,52 @@ from homeassistant.const import (
|
|||
from tests.common import get_test_home_assistant
|
||||
|
||||
|
||||
def test_validate_entity_config():
|
||||
"""Test validate entities."""
|
||||
configs = [{'invalid_entity_id': {}}, {'demo.test': 1},
|
||||
{'demo.test': 'test'}, {'demo.test': [1, 2]},
|
||||
{'demo.test': None}]
|
||||
|
||||
for conf in configs:
|
||||
with pytest.raises(vol.Invalid):
|
||||
vec(conf)
|
||||
|
||||
assert vec({}) == {}
|
||||
assert vec({'alarm_control_panel.demo': {ATTR_CODE: '1234'}}) == \
|
||||
{'alarm_control_panel.demo': {ATTR_CODE: '1234'}}
|
||||
|
||||
|
||||
def test_convert_to_float():
|
||||
"""Test convert_to_float method."""
|
||||
assert convert_to_float(12) == 12
|
||||
assert convert_to_float(12.4) == 12.4
|
||||
assert convert_to_float(STATE_UNKNOWN) is None
|
||||
assert convert_to_float(None) is None
|
||||
|
||||
|
||||
def test_temperature_to_homekit():
|
||||
"""Test temperature conversion from HA to HomeKit."""
|
||||
assert temperature_to_homekit(20.46, TEMP_CELSIUS) == 20.5
|
||||
assert temperature_to_homekit(92.1, TEMP_FAHRENHEIT) == 33.4
|
||||
|
||||
|
||||
def test_temperature_to_states():
|
||||
"""Test temperature conversion from HomeKit to HA."""
|
||||
assert temperature_to_states(20, TEMP_CELSIUS) == 20.0
|
||||
assert temperature_to_states(20.2, TEMP_FAHRENHEIT) == 68.4
|
||||
|
||||
|
||||
def test_density_to_air_quality():
|
||||
"""Test map PM2.5 density to HomeKit AirQuality level."""
|
||||
assert density_to_air_quality(0) == 1
|
||||
assert density_to_air_quality(35) == 1
|
||||
assert density_to_air_quality(35.1) == 2
|
||||
assert density_to_air_quality(75) == 2
|
||||
assert density_to_air_quality(115) == 3
|
||||
assert density_to_air_quality(150) == 4
|
||||
assert density_to_air_quality(300) == 5
|
||||
|
||||
|
||||
class TestUtil(unittest.TestCase):
|
||||
"""Test all HomeKit util methods."""
|
||||
|
||||
|
@ -39,21 +87,6 @@ class TestUtil(unittest.TestCase):
|
|||
"""Stop down everything that was started."""
|
||||
self.hass.stop()
|
||||
|
||||
def test_validate_entity_config(self):
|
||||
"""Test validate entities."""
|
||||
configs = [{'invalid_entity_id': {}}, {'demo.test': 1},
|
||||
{'demo.test': 'test'}, {'demo.test': [1, 2]},
|
||||
{'demo.test': None}]
|
||||
|
||||
for conf in configs:
|
||||
with self.assertRaises(vol.Invalid):
|
||||
vec(conf)
|
||||
|
||||
self.assertEqual(vec({}), {})
|
||||
self.assertEqual(
|
||||
vec({'alarm_control_panel.demo': {ATTR_CODE: '1234'}}),
|
||||
{'alarm_control_panel.demo': {ATTR_CODE: '1234'}})
|
||||
|
||||
def test_show_setup_msg(self):
|
||||
"""Test show setup message as persistence notification."""
|
||||
bridge = HomeBridge(self.hass)
|
||||
|
@ -83,20 +116,3 @@ class TestUtil(unittest.TestCase):
|
|||
self.assertEqual(
|
||||
data[ATTR_SERVICE_DATA].get(ATTR_NOTIFICATION_ID, None),
|
||||
HOMEKIT_NOTIFY_ID)
|
||||
|
||||
def test_convert_to_float(self):
|
||||
"""Test convert_to_float method."""
|
||||
self.assertEqual(convert_to_float(12), 12)
|
||||
self.assertEqual(convert_to_float(12.4), 12.4)
|
||||
self.assertIsNone(convert_to_float(STATE_UNKNOWN))
|
||||
self.assertIsNone(convert_to_float(None))
|
||||
|
||||
def test_temperature_to_homekit(self):
|
||||
"""Test temperature conversion from HA to HomeKit."""
|
||||
self.assertEqual(temperature_to_homekit(20.46, TEMP_CELSIUS), 20.5)
|
||||
self.assertEqual(temperature_to_homekit(92.1, TEMP_FAHRENHEIT), 33.4)
|
||||
|
||||
def test_temperature_to_states(self):
|
||||
"""Test temperature conversion from HomeKit to HA."""
|
||||
self.assertEqual(temperature_to_states(20, TEMP_CELSIUS), 20.0)
|
||||
self.assertEqual(temperature_to_states(20.2, TEMP_FAHRENHEIT), 68.4)
|
||||
|
|
Loading…
Reference in New Issue