"""Test HomeKit util module.""" import pytest import voluptuous as vol from homeassistant.components.homekit.const import ( CONF_FEATURE, CONF_FEATURE_LIST, FEATURE_ON_OFF, FEATURE_PLAY_PAUSE, HOMEKIT_NOTIFY_ID, TYPE_FAUCET, TYPE_OUTLET, TYPE_SHOWER, TYPE_SPRINKLER, TYPE_SWITCH, TYPE_VALVE) from homeassistant.components.homekit.util import ( HomeKitSpeedMapping, SpeedRange, convert_to_float, density_to_air_quality, dismiss_setup_message, show_setup_message, temperature_to_homekit, temperature_to_states, validate_entity_config as vec, validate_media_player_features) from homeassistant.components.persistent_notification import ( ATTR_MESSAGE, ATTR_NOTIFICATION_ID, DOMAIN) from homeassistant.const import ( ATTR_CODE, ATTR_SUPPORTED_FEATURES, CONF_NAME, CONF_TYPE, STATE_UNKNOWN, TEMP_CELSIUS, TEMP_FAHRENHEIT) from homeassistant.core import State from tests.common import async_mock_service def test_validate_entity_config(): """Test validate entities.""" configs = [None, [], 'string', 12345, {'invalid_entity_id': {}}, {'demo.test': 1}, {'demo.test': 'test'}, {'demo.test': [1, 2]}, {'demo.test': None}, {'demo.test': {CONF_NAME: None}}, {'media_player.test': {CONF_FEATURE_LIST: [ {CONF_FEATURE: 'invalid_feature'}]}}, {'media_player.test': {CONF_FEATURE_LIST: [ {CONF_FEATURE: FEATURE_ON_OFF}, {CONF_FEATURE: FEATURE_ON_OFF}]}}, {'switch.test': {CONF_TYPE: 'invalid_type'}}] for conf in configs: with pytest.raises(vol.Invalid): vec(conf) assert vec({}) == {} assert vec({'demo.test': {CONF_NAME: 'Name'}}) == \ {'demo.test': {CONF_NAME: 'Name'}} assert vec({'alarm_control_panel.demo': {}}) == \ {'alarm_control_panel.demo': {ATTR_CODE: None}} assert vec({'alarm_control_panel.demo': {ATTR_CODE: '1234'}}) == \ {'alarm_control_panel.demo': {ATTR_CODE: '1234'}} assert vec({'lock.demo': {}}) == {'lock.demo': {ATTR_CODE: None}} assert vec({'lock.demo': {ATTR_CODE: '1234'}}) == \ {'lock.demo': {ATTR_CODE: '1234'}} assert vec({'media_player.demo': {}}) == \ {'media_player.demo': {CONF_FEATURE_LIST: {}}} config = {CONF_FEATURE_LIST: [{CONF_FEATURE: FEATURE_ON_OFF}, {CONF_FEATURE: FEATURE_PLAY_PAUSE}]} assert vec({'media_player.demo': config}) == \ {'media_player.demo': {CONF_FEATURE_LIST: {FEATURE_ON_OFF: {}, FEATURE_PLAY_PAUSE: {}}}} assert vec({'switch.demo': {CONF_TYPE: TYPE_FAUCET}}) == \ {'switch.demo': {CONF_TYPE: TYPE_FAUCET}} assert vec({'switch.demo': {CONF_TYPE: TYPE_OUTLET}}) == \ {'switch.demo': {CONF_TYPE: TYPE_OUTLET}} assert vec({'switch.demo': {CONF_TYPE: TYPE_SHOWER}}) == \ {'switch.demo': {CONF_TYPE: TYPE_SHOWER}} assert vec({'switch.demo': {CONF_TYPE: TYPE_SPRINKLER}}) == \ {'switch.demo': {CONF_TYPE: TYPE_SPRINKLER}} assert vec({'switch.demo': {CONF_TYPE: TYPE_SWITCH}}) == \ {'switch.demo': {CONF_TYPE: TYPE_SWITCH}} assert vec({'switch.demo': {CONF_TYPE: TYPE_VALVE}}) == \ {'switch.demo': {CONF_TYPE: TYPE_VALVE}} def test_validate_media_player_features(): """Test validate modes for media players.""" config = {} attrs = {ATTR_SUPPORTED_FEATURES: 20873} entity_state = State('media_player.demo', 'on', attrs) assert validate_media_player_features(entity_state, config) is True config = {FEATURE_ON_OFF: None} assert validate_media_player_features(entity_state, config) is True entity_state = State('media_player.demo', 'on') assert validate_media_player_features(entity_state, config) is False 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.5 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.5 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 async def test_show_setup_msg(hass): """Test show setup message as persistence notification.""" pincode = b'123-45-678' call_create_notification = async_mock_service(hass, DOMAIN, 'create') await hass.async_add_job(show_setup_message, hass, pincode) await hass.async_block_till_done() assert call_create_notification assert call_create_notification[0].data[ATTR_NOTIFICATION_ID] == \ HOMEKIT_NOTIFY_ID assert pincode.decode() in call_create_notification[0].data[ATTR_MESSAGE] async def test_dismiss_setup_msg(hass): """Test dismiss setup message.""" call_dismiss_notification = async_mock_service(hass, DOMAIN, 'dismiss') await hass.async_add_job(dismiss_setup_message, hass) await hass.async_block_till_done() assert call_dismiss_notification assert call_dismiss_notification[0].data[ATTR_NOTIFICATION_ID] == \ HOMEKIT_NOTIFY_ID def test_homekit_speed_mapping(): """Test if the SpeedRanges from a speed_list are as expected.""" # A standard 2-speed fan speed_mapping = HomeKitSpeedMapping(['off', 'low', 'high']) assert speed_mapping.speed_ranges == { 'off': SpeedRange(0, 0), 'low': SpeedRange(100 / 3, 50), 'high': SpeedRange(200 / 3, 100), } # A standard 3-speed fan speed_mapping = HomeKitSpeedMapping(['off', 'low', 'medium', 'high']) assert speed_mapping.speed_ranges == { 'off': SpeedRange(0, 0), 'low': SpeedRange(100 / 4, 100 / 3), 'medium': SpeedRange(200 / 4, 200 / 3), 'high': SpeedRange(300 / 4, 100), } # a Dyson-like fan with 10 speeds speed_mapping = HomeKitSpeedMapping([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) assert speed_mapping.speed_ranges == { 0: SpeedRange(0, 0), 1: SpeedRange(10, 100 / 9), 2: SpeedRange(20, 200 / 9), 3: SpeedRange(30, 300 / 9), 4: SpeedRange(40, 400 / 9), 5: SpeedRange(50, 500 / 9), 6: SpeedRange(60, 600 / 9), 7: SpeedRange(70, 700 / 9), 8: SpeedRange(80, 800 / 9), 9: SpeedRange(90, 100), } def test_speed_to_homekit(): """Test speed conversion from HA to Homekit.""" speed_mapping = HomeKitSpeedMapping(['off', 'low', 'high']) assert speed_mapping.speed_to_homekit('off') == 0 assert speed_mapping.speed_to_homekit('low') == 50 assert speed_mapping.speed_to_homekit('high') == 100 def test_speed_to_states(): """Test speed conversion from Homekit to HA.""" speed_mapping = HomeKitSpeedMapping(['off', 'low', 'high']) assert speed_mapping.speed_to_states(0) == 'off' assert speed_mapping.speed_to_states(33) == 'off' assert speed_mapping.speed_to_states(34) == 'low' assert speed_mapping.speed_to_states(50) == 'low' assert speed_mapping.speed_to_states(66) == 'low' assert speed_mapping.speed_to_states(67) == 'high' assert speed_mapping.speed_to_states(100) == 'high'