async def test_reset_switch(hass, hk_driver, entity_id, attrs, events): """Test if switch accessory is reset correctly.""" domain = split_entity_id(entity_id)[0] hass.states.async_set(entity_id, None, attrs) await hass.async_block_till_done() acc = Switch(hass, hk_driver, 'Switch', entity_id, 2, None) await hass.async_add_job(acc.run) await hass.async_block_till_done() assert acc.activate_only is True assert acc.char_on.value is False call_turn_on = async_mock_service(hass, domain, 'turn_on') call_turn_off = async_mock_service(hass, domain, 'turn_off') await hass.async_add_job(acc.char_on.client_update_value, True) await hass.async_block_till_done() assert acc.char_on.value is True assert call_turn_on assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id assert len(events) == 1 assert events[-1].data[ATTR_VALUE] is None future = dt_util.utcnow() + timedelta(seconds=1) async_fire_time_changed(hass, future) await hass.async_block_till_done() assert acc.char_on.value is False assert len(events) == 1 assert not call_turn_off await hass.async_add_job(acc.char_on.client_update_value, False) await hass.async_block_till_done() assert acc.char_on.value is False assert len(events) == 1
async def test_onoff_fan(hass): """Test OnOff trait support for fan domain.""" assert trait.OnOffTrait.supported(fan.DOMAIN, 0) trt_on = trait.OnOffTrait(hass, State('fan.bla', STATE_ON), BASIC_CONFIG) assert trt_on.sync_attributes() == {} assert trt_on.query_attributes() == { 'on': True } trt_off = trait.OnOffTrait(hass, State('fan.bla', STATE_OFF), BASIC_CONFIG) assert trt_off.query_attributes() == { 'on': False } on_calls = async_mock_service(hass, fan.DOMAIN, SERVICE_TURN_ON) await trt_on.execute( trait.COMMAND_ONOFF, BASIC_DATA, {'on': True}) assert len(on_calls) == 1 assert on_calls[0].data == { ATTR_ENTITY_ID: 'fan.bla', } off_calls = async_mock_service(hass, fan.DOMAIN, SERVICE_TURN_OFF) await trt_on.execute( trait.COMMAND_ONOFF, BASIC_DATA, {'on': False}) assert len(off_calls) == 1 assert off_calls[0].data == { ATTR_ENTITY_ID: 'fan.bla', }
def test_api_turn_off(hass, domain): """Test api turn on process.""" request = get_new_request( 'Alexa.PowerController', 'TurnOff', '{}#test'.format(domain)) # setup test devices hass.states.async_set( '{}.test'.format(domain), 'on', { 'friendly_name': "Test {}".format(domain) }) call_domain = domain if domain == 'group': call_domain = 'homeassistant' if domain == 'cover': call = async_mock_service(hass, call_domain, 'close_cover') else: call = async_mock_service(hass, call_domain, 'turn_off') msg = yield from smart_home.async_handle_message( hass, DEFAULT_CONFIG, request) yield from hass.async_block_till_done() assert 'event' in msg msg = msg['event'] assert len(call) == 1 assert call[0].data['entity_id'] == '{}.test'.format(domain) assert msg['header']['name'] == 'Response'
async def test_onoff_cover(hass): """Test OnOff trait support for cover domain.""" assert trait.OnOffTrait.supported(media_player.DOMAIN, 0) trt_on = trait.OnOffTrait(hass, State('cover.bla', cover.STATE_OPEN)) assert trt_on.sync_attributes() == {} assert trt_on.query_attributes() == { 'on': True } trt_off = trait.OnOffTrait(hass, State('cover.bla', cover.STATE_CLOSED)) assert trt_off.query_attributes() == { 'on': False } on_calls = async_mock_service(hass, cover.DOMAIN, cover.SERVICE_OPEN_COVER) await trt_on.execute(trait.COMMAND_ONOFF, { 'on': True }) assert len(on_calls) == 1 assert on_calls[0].data == { ATTR_ENTITY_ID: 'cover.bla', } off_calls = async_mock_service(hass, cover.DOMAIN, cover.SERVICE_CLOSE_COVER) await trt_on.execute(trait.COMMAND_ONOFF, { 'on': False }) assert len(off_calls) == 1 assert off_calls[0].data == { ATTR_ENTITY_ID: 'cover.bla', }
async def test_onoff_media_player(hass): """Test OnOff trait support for media_player domain.""" assert trait.OnOffTrait.supported(media_player.DOMAIN, 0) trt_on = trait.OnOffTrait(State('media_player.bla', STATE_ON)) assert trt_on.sync_attributes() == {} assert trt_on.query_attributes() == { 'on': True } trt_off = trait.OnOffTrait(State('media_player.bla', STATE_OFF)) assert trt_off.query_attributes() == { 'on': False } on_calls = async_mock_service(hass, media_player.DOMAIN, SERVICE_TURN_ON) await trt_on.execute(hass, trait.COMMAND_ONOFF, { 'on': True }) assert len(on_calls) == 1 assert on_calls[0].data == { ATTR_ENTITY_ID: 'media_player.bla', } off_calls = async_mock_service(hass, media_player.DOMAIN, SERVICE_TURN_OFF) await trt_on.execute(hass, trait.COMMAND_ONOFF, { 'on': False }) assert len(off_calls) == 1 assert off_calls[0].data == { ATTR_ENTITY_ID: 'media_player.bla', }
async def test_garage_door_open_close(hass, hk_driver, cls, events): """Test if accessory and HA are updated accordingly.""" entity_id = 'cover.garage_door' hass.states.async_set(entity_id, None) await hass.async_block_till_done() acc = cls.garage(hass, hk_driver, 'Garage Door', entity_id, 2, None) await hass.async_add_job(acc.run) assert acc.aid == 2 assert acc.category == 4 # GarageDoorOpener assert acc.char_current_state.value == 0 assert acc.char_target_state.value == 0 hass.states.async_set(entity_id, STATE_CLOSED) await hass.async_block_till_done() assert acc.char_current_state.value == 1 assert acc.char_target_state.value == 1 hass.states.async_set(entity_id, STATE_OPEN) await hass.async_block_till_done() assert acc.char_current_state.value == 0 assert acc.char_target_state.value == 0 hass.states.async_set(entity_id, STATE_UNAVAILABLE) await hass.async_block_till_done() assert acc.char_current_state.value == 0 assert acc.char_target_state.value == 0 hass.states.async_set(entity_id, STATE_UNKNOWN) await hass.async_block_till_done() assert acc.char_current_state.value == 0 assert acc.char_target_state.value == 0 # Set from HomeKit call_close_cover = async_mock_service(hass, DOMAIN, 'close_cover') call_open_cover = async_mock_service(hass, DOMAIN, 'open_cover') await hass.async_add_job(acc.char_target_state.client_update_value, 1) await hass.async_block_till_done() assert call_close_cover assert call_close_cover[0].data[ATTR_ENTITY_ID] == entity_id assert acc.char_current_state.value == 2 assert acc.char_target_state.value == 1 assert len(events) == 1 assert events[-1].data[ATTR_VALUE] is None hass.states.async_set(entity_id, STATE_CLOSED) await hass.async_block_till_done() await hass.async_add_job(acc.char_target_state.client_update_value, 0) await hass.async_block_till_done() assert call_open_cover assert call_open_cover[0].data[ATTR_ENTITY_ID] == entity_id assert acc.char_current_state.value == 3 assert acc.char_target_state.value == 0 assert len(events) == 2 assert events[-1].data[ATTR_VALUE] is None
async def test_thermostat_power_state(hass, hk_driver, cls, events): """Test if accessory and HA are updated accordingly.""" entity_id = 'climate.test' # SUPPORT_ON_OFF = True hass.states.async_set(entity_id, STATE_HEAT, {ATTR_SUPPORTED_FEATURES: 4096, ATTR_OPERATION_MODE: STATE_HEAT, ATTR_TEMPERATURE: 23.0, ATTR_CURRENT_TEMPERATURE: 18.0}) await hass.async_block_till_done() acc = cls.thermostat(hass, hk_driver, 'Climate', entity_id, 2, None) await hass.async_add_job(acc.run) await hass.async_block_till_done() assert acc.support_power_state is True assert acc.char_current_heat_cool.value == 1 assert acc.char_target_heat_cool.value == 1 hass.states.async_set(entity_id, STATE_OFF, {ATTR_OPERATION_MODE: STATE_HEAT, ATTR_TEMPERATURE: 23.0, ATTR_CURRENT_TEMPERATURE: 18.0}) await hass.async_block_till_done() assert acc.char_current_heat_cool.value == 0 assert acc.char_target_heat_cool.value == 0 hass.states.async_set(entity_id, STATE_OFF, {ATTR_OPERATION_MODE: STATE_OFF, ATTR_TEMPERATURE: 23.0, ATTR_CURRENT_TEMPERATURE: 18.0}) await hass.async_block_till_done() assert acc.char_current_heat_cool.value == 0 assert acc.char_target_heat_cool.value == 0 # Set from HomeKit call_turn_on = async_mock_service(hass, DOMAIN_CLIMATE, 'turn_on') call_turn_off = async_mock_service(hass, DOMAIN_CLIMATE, 'turn_off') call_set_operation_mode = async_mock_service(hass, DOMAIN_CLIMATE, 'set_operation_mode') await hass.async_add_job(acc.char_target_heat_cool.client_update_value, 1) await hass.async_block_till_done() assert call_turn_on assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id assert call_set_operation_mode assert call_set_operation_mode[0].data[ATTR_ENTITY_ID] == entity_id assert call_set_operation_mode[0].data[ATTR_OPERATION_MODE] == STATE_HEAT assert acc.char_target_heat_cool.value == 1 assert len(events) == 2 assert events[-1].data[ATTR_VALUE] == STATE_HEAT await hass.async_add_job(acc.char_target_heat_cool.client_update_value, 0) await hass.async_block_till_done() assert call_turn_off assert call_turn_off[0].data[ATTR_ENTITY_ID] == entity_id assert acc.char_target_heat_cool.value == 0 assert len(events) == 3 assert events[-1].data[ATTR_VALUE] is None
async def test_lock_unlock(hass, hk_driver, events): """Test if accessory and HA are updated accordingly.""" code = '1234' config = {ATTR_CODE: code} entity_id = 'lock.kitchen_door' hass.states.async_set(entity_id, None) await hass.async_block_till_done() acc = Lock(hass, hk_driver, 'Lock', entity_id, 2, config) await hass.async_add_job(acc.run) assert acc.aid == 2 assert acc.category == 6 # DoorLock assert acc.char_current_state.value == 3 assert acc.char_target_state.value == 1 hass.states.async_set(entity_id, STATE_LOCKED) await hass.async_block_till_done() assert acc.char_current_state.value == 1 assert acc.char_target_state.value == 1 hass.states.async_set(entity_id, STATE_UNLOCKED) await hass.async_block_till_done() assert acc.char_current_state.value == 0 assert acc.char_target_state.value == 0 hass.states.async_set(entity_id, STATE_UNKNOWN) await hass.async_block_till_done() assert acc.char_current_state.value == 3 assert acc.char_target_state.value == 0 hass.states.async_remove(entity_id) await hass.async_block_till_done() assert acc.char_current_state.value == 3 assert acc.char_target_state.value == 0 # Set from HomeKit call_lock = async_mock_service(hass, DOMAIN, 'lock') call_unlock = async_mock_service(hass, DOMAIN, 'unlock') await hass.async_add_job(acc.char_target_state.client_update_value, 1) await hass.async_block_till_done() assert call_lock assert call_lock[0].data[ATTR_ENTITY_ID] == entity_id assert call_lock[0].data[ATTR_CODE] == code assert acc.char_target_state.value == 1 assert len(events) == 1 assert events[-1].data[ATTR_VALUE] is None await hass.async_add_job(acc.char_target_state.client_update_value, 0) await hass.async_block_till_done() assert call_unlock assert call_unlock[0].data[ATTR_ENTITY_ID] == entity_id assert call_unlock[0].data[ATTR_CODE] == code assert acc.char_target_state.value == 0 assert len(events) == 2 assert events[-1].data[ATTR_VALUE] is None
async def test_setup_user_notify_service(hass): """Test allow select notify service during mfa setup.""" notify_calls = async_mock_service( hass, 'notify', 'test1', NOTIFY_SERVICE_SCHEMA) async_mock_service(hass, 'notify', 'test2', NOTIFY_SERVICE_SCHEMA) notify_auth_module = await auth_mfa_module_from_config(hass, { 'type': 'notify', }) services = notify_auth_module.aync_get_available_notify_services() assert services == ['test1', 'test2'] flow = await notify_auth_module.async_setup_flow('test-user') step = await flow.async_step_init() assert step['type'] == data_entry_flow.RESULT_TYPE_FORM assert step['step_id'] == 'init' schema = step['data_schema'] schema({'notify_service': 'test2'}) with patch('pyotp.HOTP.at', return_value=MOCK_CODE): step = await flow.async_step_init({'notify_service': 'test1'}) assert step['type'] == data_entry_flow.RESULT_TYPE_FORM assert step['step_id'] == 'setup' # wait service call finished await hass.async_block_till_done() assert len(notify_calls) == 1 notify_call = notify_calls[0] assert notify_call.domain == 'notify' assert notify_call.service == 'test1' message = notify_call.data['message'] message.hass = hass assert MOCK_CODE in message.async_render() with patch('pyotp.HOTP.at', return_value=MOCK_CODE_2): step = await flow.async_step_setup({'code': 'invalid'}) assert step['type'] == data_entry_flow.RESULT_TYPE_FORM assert step['step_id'] == 'setup' assert step['errors']['base'] == 'invalid_code' # wait service call finished await hass.async_block_till_done() assert len(notify_calls) == 2 notify_call = notify_calls[1] assert notify_call.domain == 'notify' assert notify_call.service == 'test1' message = notify_call.data['message'] message.hass = hass assert MOCK_CODE_2 in message.async_render() with patch('pyotp.HOTP.verify', return_value=True): step = await flow.async_step_setup({'code': MOCK_CODE_2}) assert step['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
async def test_fan_basic(hass, hk_driver, cls, events): """Test fan with char state.""" entity_id = 'fan.demo' hass.states.async_set(entity_id, STATE_ON, {ATTR_SUPPORTED_FEATURES: 0}) await hass.async_block_till_done() acc = cls.fan(hass, hk_driver, 'Fan', entity_id, 2, None) assert acc.aid == 2 assert acc.category == 3 # Fan assert acc.char_active.value == 0 # If there are no speed_list values, then HomeKit speed is unsupported assert acc.char_speed is None await hass.async_add_job(acc.run) await hass.async_block_till_done() assert acc.char_active.value == 1 hass.states.async_set(entity_id, STATE_OFF, {ATTR_SUPPORTED_FEATURES: 0}) await hass.async_block_till_done() assert acc.char_active.value == 0 hass.states.async_set(entity_id, STATE_UNKNOWN) await hass.async_block_till_done() assert acc.char_active.value == 0 hass.states.async_remove(entity_id) await hass.async_block_till_done() assert acc.char_active.value == 0 # Set from HomeKit call_turn_on = async_mock_service(hass, DOMAIN, 'turn_on') call_turn_off = async_mock_service(hass, DOMAIN, 'turn_off') await hass.async_add_job(acc.char_active.client_update_value, 1) await hass.async_block_till_done() assert call_turn_on assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id assert len(events) == 1 assert events[-1].data[ATTR_VALUE] is None hass.states.async_set(entity_id, STATE_ON) await hass.async_block_till_done() await hass.async_add_job(acc.char_active.client_update_value, 0) await hass.async_block_till_done() assert call_turn_off assert call_turn_off[0].data[ATTR_ENTITY_ID] == entity_id assert len(events) == 2 assert events[-1].data[ATTR_VALUE] is None
async def test_setup_user_no_notify_service(hass): """Test setup flow abort if there is no avilable notify service.""" async_mock_service(hass, 'notify', 'test1', NOTIFY_SERVICE_SCHEMA) notify_auth_module = await auth_mfa_module_from_config(hass, { 'type': 'notify', 'exclude': 'test1', }) services = notify_auth_module.aync_get_available_notify_services() assert services == [] flow = await notify_auth_module.async_setup_flow('test-user') step = await flow.async_step_init() assert step['type'] == data_entry_flow.RESULT_TYPE_ABORT assert step['reason'] == 'no_available_service'
async def test_light_brightness(hass, hk_driver, cls, events): """Test light with brightness.""" entity_id = 'light.demo' hass.states.async_set(entity_id, STATE_ON, { ATTR_SUPPORTED_FEATURES: SUPPORT_BRIGHTNESS, ATTR_BRIGHTNESS: 255}) await hass.async_block_till_done() acc = cls.light(hass, hk_driver, 'Light', entity_id, 2, None) assert acc.char_brightness.value == 0 await hass.async_add_job(acc.run) await hass.async_block_till_done() assert acc.char_brightness.value == 100 hass.states.async_set(entity_id, STATE_ON, {ATTR_BRIGHTNESS: 102}) await hass.async_block_till_done() assert acc.char_brightness.value == 40 # Set from HomeKit call_turn_on = async_mock_service(hass, DOMAIN, 'turn_on') call_turn_off = async_mock_service(hass, DOMAIN, 'turn_off') await hass.async_add_job(acc.char_brightness.client_update_value, 20) await hass.async_add_job(acc.char_on.client_update_value, 1) await hass.async_block_till_done() assert call_turn_on[0] assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id assert call_turn_on[0].data[ATTR_BRIGHTNESS_PCT] == 20 assert len(events) == 1 assert events[-1].data[ATTR_VALUE] == 'brightness at 20%' await hass.async_add_job(acc.char_on.client_update_value, 1) await hass.async_add_job(acc.char_brightness.client_update_value, 40) await hass.async_block_till_done() assert call_turn_on[1] assert call_turn_on[1].data[ATTR_ENTITY_ID] == entity_id assert call_turn_on[1].data[ATTR_BRIGHTNESS_PCT] == 40 assert len(events) == 2 assert events[-1].data[ATTR_VALUE] == 'brightness at 40%' await hass.async_add_job(acc.char_on.client_update_value, 1) await hass.async_add_job(acc.char_brightness.client_update_value, 0) await hass.async_block_till_done() assert call_turn_off assert call_turn_off[0].data[ATTR_ENTITY_ID] == entity_id assert len(events) == 3 assert events[-1].data[ATTR_VALUE] is None
async def test_light_basic(hass, hk_driver, cls, events): """Test light with char state.""" entity_id = 'light.demo' hass.states.async_set(entity_id, STATE_ON, {ATTR_SUPPORTED_FEATURES: 0}) await hass.async_block_till_done() acc = cls.light(hass, hk_driver, 'Light', entity_id, 2, None) assert acc.aid == 2 assert acc.category == 5 # Lightbulb assert acc.char_on.value == 0 await hass.async_add_job(acc.run) await hass.async_block_till_done() assert acc.char_on.value == 1 hass.states.async_set(entity_id, STATE_OFF, {ATTR_SUPPORTED_FEATURES: 0}) await hass.async_block_till_done() assert acc.char_on.value == 0 hass.states.async_set(entity_id, STATE_UNKNOWN) await hass.async_block_till_done() assert acc.char_on.value == 0 hass.states.async_remove(entity_id) await hass.async_block_till_done() assert acc.char_on.value == 0 # Set from HomeKit call_turn_on = async_mock_service(hass, DOMAIN, 'turn_on') call_turn_off = async_mock_service(hass, DOMAIN, 'turn_off') await hass.async_add_job(acc.char_on.client_update_value, 1) await hass.async_block_till_done() assert call_turn_on assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id assert len(events) == 1 assert events[-1].data[ATTR_VALUE] is None hass.states.async_set(entity_id, STATE_ON) await hass.async_block_till_done() await hass.async_add_job(acc.char_on.client_update_value, 0) await hass.async_block_till_done() assert call_turn_off assert call_turn_off[0].data[ATTR_ENTITY_ID] == entity_id assert len(events) == 2 assert events[-1].data[ATTR_VALUE] is None
async def test_light_rgb_color(hass, hk_driver, cls): """Test light with rgb_color.""" entity_id = 'light.demo' hass.states.async_set(entity_id, STATE_ON, { ATTR_SUPPORTED_FEATURES: SUPPORT_COLOR, ATTR_HS_COLOR: (260, 90)}) await hass.async_block_till_done() acc = cls.light(hass, hk_driver, 'Light', entity_id, 2, None) assert acc.char_hue.value == 0 assert acc.char_saturation.value == 75 await hass.async_add_job(acc.run) await hass.async_block_till_done() assert acc.char_hue.value == 260 assert acc.char_saturation.value == 90 # Set from HomeKit call_turn_on = async_mock_service(hass, DOMAIN, 'turn_on') await hass.async_add_job(acc.char_hue.client_update_value, 145) await hass.async_add_job(acc.char_saturation.client_update_value, 75) await hass.async_block_till_done() assert call_turn_on assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id assert call_turn_on[0].data[ATTR_HS_COLOR] == (145, 75)
def test_api_set_color_rgb(hass): """Test api set color process.""" request = get_new_request( 'Alexa.ColorController', 'SetColor', 'light#test') # add payload request['directive']['payload']['color'] = { 'hue': '120', 'saturation': '0.612', 'brightness': '0.342', } # setup test devices hass.states.async_set( 'light.test', 'off', { 'friendly_name': "Test light", 'supported_features': 16, }) call_light = async_mock_service(hass, 'light', 'turn_on') msg = yield from smart_home.async_handle_message( hass, DEFAULT_CONFIG, request) yield from hass.async_block_till_done() assert 'event' in msg msg = msg['event'] assert len(call_light) == 1 assert call_light[0].data['entity_id'] == 'light.test' assert call_light[0].data['rgb_color'] == (33, 87, 33) assert msg['header']['name'] == 'Response'
def test_api_decrease_color_temp(hass, result, initial): """Test api decrease color temp process.""" request = get_new_request( 'Alexa.ColorTemperatureController', 'DecreaseColorTemperature', 'light#test') # setup test devices hass.states.async_set( 'light.test', 'off', { 'friendly_name': "Test light", 'color_temp': initial, 'max_mireds': 500, }) call_light = async_mock_service(hass, 'light', 'turn_on') msg = yield from smart_home.async_handle_message( hass, DEFAULT_CONFIG, request) yield from hass.async_block_till_done() assert 'event' in msg msg = msg['event'] assert len(call_light) == 1 assert call_light[0].data['entity_id'] == 'light.test' assert call_light[0].data['color_temp'] == result assert msg['header']['name'] == 'Response'
def test_api_set_color_temperature(hass): """Test api set color temperature process.""" request = get_new_request( 'Alexa.ColorTemperatureController', 'SetColorTemperature', 'light#test') # add payload request['directive']['payload']['colorTemperatureInKelvin'] = '7500' # setup test devices hass.states.async_set( 'light.test', 'off', {'friendly_name': "Test light"}) call_light = async_mock_service(hass, 'light', 'turn_on') msg = yield from smart_home.async_handle_message( hass, DEFAULT_CONFIG, request) yield from hass.async_block_till_done() assert 'event' in msg msg = msg['event'] assert len(call_light) == 1 assert call_light[0].data['entity_id'] == 'light.test' assert call_light[0].data['kelvin'] == 7500 assert msg['header']['name'] == 'Response'
def assert_request_calls_service( namespace, name, endpoint, service, hass, response_type='Response', payload=None): """Assert an API request calls a hass service.""" request = get_new_request(namespace, name, endpoint) if payload: request['directive']['payload'] = payload domain, service_name = service.split('.') call = async_mock_service(hass, domain, service_name) msg = yield from smart_home.async_handle_message( hass, DEFAULT_CONFIG, request) yield from hass.async_block_till_done() assert len(call) == 1 assert 'event' in msg assert call[0].data['entity_id'] == endpoint.replace('#', '.') assert msg['event']['header']['name'] == response_type return call[0], msg
def test_api_adjust_brightness(hass, result, adjust): """Test api adjust brightness process.""" request = get_new_request( 'Alexa.BrightnessController', 'AdjustBrightness', 'light#test') # add payload request['directive']['payload']['brightnessDelta'] = adjust # setup test devices hass.states.async_set( 'light.test', 'off', { 'friendly_name': "Test light", 'brightness': '77' }) call_light = async_mock_service(hass, 'light', 'turn_on') msg = yield from smart_home.async_handle_message( hass, DEFAULT_CONFIG, request) yield from hass.async_block_till_done() assert 'event' in msg msg = msg['event'] assert len(call_light) == 1 assert call_light[0].data['entity_id'] == 'light.test' assert call_light[0].data['brightness_pct'] == result assert msg['header']['name'] == 'Response'
async def test_fan_oscillate(hass, hk_driver, cls): """Test fan with oscillate.""" entity_id = 'fan.demo' hass.states.async_set(entity_id, STATE_ON, { ATTR_SUPPORTED_FEATURES: SUPPORT_OSCILLATE, ATTR_OSCILLATING: False}) await hass.async_block_till_done() acc = cls.fan(hass, hk_driver, 'Fan', entity_id, 2, None) assert acc.char_swing.value == 0 await hass.async_add_job(acc.run) await hass.async_block_till_done() assert acc.char_swing.value == 0 hass.states.async_set(entity_id, STATE_ON, {ATTR_OSCILLATING: True}) await hass.async_block_till_done() assert acc.char_swing.value == 1 # Set from HomeKit call_oscillate = async_mock_service(hass, DOMAIN, 'oscillate') await hass.async_add_job(acc.char_swing.client_update_value, 0) await hass.async_block_till_done() assert call_oscillate[0] assert call_oscillate[0].data[ATTR_ENTITY_ID] == entity_id assert call_oscillate[0].data[ATTR_OSCILLATING] is False await hass.async_add_job(acc.char_swing.client_update_value, 1) await hass.async_block_till_done() assert call_oscillate[1] assert call_oscillate[1].data[ATTR_ENTITY_ID] == entity_id assert call_oscillate[1].data[ATTR_OSCILLATING] is True
async def test_fan_direction(hass, hk_driver, cls): """Test fan with direction.""" entity_id = 'fan.demo' hass.states.async_set(entity_id, STATE_ON, { ATTR_SUPPORTED_FEATURES: SUPPORT_DIRECTION, ATTR_DIRECTION: DIRECTION_FORWARD}) await hass.async_block_till_done() acc = cls.fan(hass, hk_driver, 'Fan', entity_id, 2, None) assert acc.char_direction.value == 0 await hass.async_add_job(acc.run) await hass.async_block_till_done() assert acc.char_direction.value == 0 hass.states.async_set(entity_id, STATE_ON, {ATTR_DIRECTION: DIRECTION_REVERSE}) await hass.async_block_till_done() assert acc.char_direction.value == 1 # Set from HomeKit call_set_direction = async_mock_service(hass, DOMAIN, 'set_direction') await hass.async_add_job(acc.char_direction.client_update_value, 0) await hass.async_block_till_done() assert call_set_direction[0] assert call_set_direction[0].data[ATTR_ENTITY_ID] == entity_id assert call_set_direction[0].data[ATTR_DIRECTION] == DIRECTION_FORWARD await hass.async_add_job(acc.char_direction.client_update_value, 1) await hass.async_block_till_done() assert call_set_direction[1] assert call_set_direction[1].data[ATTR_ENTITY_ID] == entity_id assert call_set_direction[1].data[ATTR_DIRECTION] == DIRECTION_REVERSE
def test_no_initial_value_and_restore_off(hass): """Test initial value off and restored state is turned on.""" calls = async_mock_service(hass, 'test', 'automation') mock_restore_cache(hass, ( State('automation.hello', STATE_OFF), )) res = yield from async_setup_component(hass, automation.DOMAIN, { automation.DOMAIN: { 'alias': 'hello', 'trigger': { 'platform': 'event', 'event_type': 'test_event', }, 'action': { 'service': 'test.automation', 'entity_id': 'hello.world' } } }) assert res assert not automation.is_on(hass, 'automation.hello') hass.bus.async_fire('test_event') yield from hass.async_block_till_done() assert len(calls) == 0
def test_automation_not_trigger_on_bootstrap(hass): """Test if automation is not trigger on bootstrap.""" hass.state = CoreState.not_running calls = async_mock_service(hass, 'test', 'automation') res = yield from async_setup_component(hass, automation.DOMAIN, { automation.DOMAIN: { 'alias': 'hello', 'trigger': { 'platform': 'event', 'event_type': 'test_event', }, 'action': { 'service': 'test.automation', 'entity_id': 'hello.world' } } }) assert res assert not automation.is_on(hass, 'automation.hello') hass.bus.async_fire('test_event') yield from hass.async_block_till_done() assert len(calls) == 0 hass.bus.async_fire(EVENT_HOMEASSISTANT_START) yield from hass.async_block_till_done() assert automation.is_on(hass, 'automation.hello') hass.bus.async_fire('test_event') yield from hass.async_block_till_done() assert len(calls) == 1 assert ['hello.world'] == calls[0].data.get(ATTR_ENTITY_ID)
async def test_brightness_media_player(hass): """Test brightness trait support for media player domain.""" assert trait.BrightnessTrait.supported(media_player.DOMAIN, media_player.SUPPORT_VOLUME_SET) trt = trait.BrightnessTrait(State( 'media_player.bla', media_player.STATE_PLAYING, { media_player.ATTR_MEDIA_VOLUME_LEVEL: .3 })) assert trt.sync_attributes() == {} assert trt.query_attributes() == { 'brightness': 30 } calls = async_mock_service( hass, media_player.DOMAIN, media_player.SERVICE_VOLUME_SET) await trt.execute(hass, trait.COMMAND_BRIGHTNESS_ABSOLUTE, { 'brightness': 60 }) assert len(calls) == 1 assert calls[0].data == { ATTR_ENTITY_ID: 'media_player.bla', media_player.ATTR_MEDIA_VOLUME_LEVEL: .6 }
async def test_service_call_event_contains_original_data(hass): """Test that service call event contains original data.""" events = [] @ha.callback def callback(event): events.append(event) hass.bus.async_listen(EVENT_CALL_SERVICE, callback) calls = async_mock_service(hass, 'test', 'service', vol.Schema({ 'number': vol.Coerce(int) })) context = ha.Context() await hass.services.async_call('test', 'service', { 'number': '23' }, blocking=True, context=context) await hass.async_block_till_done() assert len(events) == 1 assert events[0].data['service_data']['number'] == '23' assert events[0].context is context assert len(calls) == 1 assert calls[0].data['number'] == 23 assert calls[0].context is context
async def test_light_color_temperature(hass, hk_driver, cls): """Test light with color temperature.""" entity_id = 'light.demo' hass.states.async_set(entity_id, STATE_ON, { ATTR_SUPPORTED_FEATURES: SUPPORT_COLOR_TEMP, ATTR_COLOR_TEMP: 190}) await hass.async_block_till_done() acc = cls.light(hass, hk_driver, 'Light', entity_id, 2, None) assert acc.char_color_temperature.value == 153 await hass.async_add_job(acc.run) await hass.async_block_till_done() assert acc.char_color_temperature.value == 190 # Set from HomeKit call_turn_on = async_mock_service(hass, DOMAIN, 'turn_on') await hass.async_add_job( acc.char_color_temperature.client_update_value, 250) await hass.async_block_till_done() assert call_turn_on assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id assert call_turn_on[0].data[ATTR_COLOR_TEMP] == 250
def test_api_adjust_percentage_fan(hass, result, adjust): """Test api adjust percentage for fan process.""" request = get_new_request( 'Alexa.PercentageController', 'AdjustPercentage', 'fan#test_2') # add payload request['directive']['payload']['percentageDelta'] = adjust # setup test devices hass.states.async_set( 'fan.test_2', 'on', { 'friendly_name': "Test fan 2", 'speed': 'high' }) call_fan = async_mock_service(hass, 'fan', 'set_speed') msg = yield from smart_home.async_handle_message( hass, DEFAULT_CONFIG, request) yield from hass.async_block_till_done() assert 'event' in msg msg = msg['event'] assert len(call_fan) == 1 assert call_fan[0].data['entity_id'] == 'fan.test_2' assert call_fan[0].data['speed'] == result assert msg['header']['name'] == 'Response'
async def test_intent_set_color_and_brightness(hass): """Test the set color intent.""" hass.states.async_set('light.hello_2', 'off', { ATTR_SUPPORTED_FEATURES: ( light.SUPPORT_RGB_COLOR | light.SUPPORT_BRIGHTNESS) }) hass.states.async_set('switch.hello', 'off') calls = async_mock_service(hass, light.DOMAIN, light.SERVICE_TURN_ON) hass.helpers.intent.async_register(light.SetIntentHandler()) result = await hass.helpers.intent.async_handle( 'test', light.INTENT_SET, { 'name': { 'value': 'Hello', }, 'color': { 'value': 'blue' }, 'brightness': { 'value': '20' } }) await hass.async_block_till_done() assert result.speech['plain']['speech'] == \ 'Changed hello 2 to the color blue and 20% brightness' assert len(calls) == 1 call = calls[0] assert call.domain == light.DOMAIN assert call.service == SERVICE_TURN_ON assert call.data.get(ATTR_ENTITY_ID) == 'light.hello_2' assert call.data.get(light.ATTR_RGB_COLOR) == (0, 0, 255) assert call.data.get(light.ATTR_BRIGHTNESS_PCT) == 20
def test_api_adjust_percentage_cover(hass, result, adjust): """Test api adjust percentage for cover process.""" request = get_new_request( 'Alexa.PercentageController', 'AdjustPercentage', 'cover#test') # add payload request['directive']['payload']['percentageDelta'] = adjust # setup test devices hass.states.async_set( 'cover.test', 'closed', { 'friendly_name': "Test cover", 'position': 30 }) call_cover = async_mock_service(hass, 'cover', 'set_cover_position') msg = yield from smart_home.async_handle_message( hass, DEFAULT_CONFIG, request) yield from hass.async_block_till_done() assert 'event' in msg msg = msg['event'] assert len(call_cover) == 1 assert call_cover[0].data['entity_id'] == 'cover.test' assert call_cover[0].data['position'] == result assert msg['header']['name'] == 'Response'
async def test_brightness_cover(hass): """Test brightness trait support for cover domain.""" assert trait.BrightnessTrait.supported(cover.DOMAIN, cover.SUPPORT_SET_POSITION) trt = trait.BrightnessTrait(State('cover.bla', cover.STATE_OPEN, { cover.ATTR_CURRENT_POSITION: 75 })) assert trt.sync_attributes() == {} assert trt.query_attributes() == { 'brightness': 75 } calls = async_mock_service( hass, cover.DOMAIN, cover.SERVICE_SET_COVER_POSITION) await trt.execute(hass, trait.COMMAND_BRIGHTNESS_ABSOLUTE, { 'brightness': 50 }) assert len(calls) == 1 assert calls[0].data == { ATTR_ENTITY_ID: 'cover.bla', cover.ATTR_POSITION: 50 }
async def test_methods(hass): """Test if methods call the services as expected.""" # Test is_on hass.states.async_set("light.test", STATE_ON) assert light.is_on(hass, "light.test") hass.states.async_set("light.test", STATE_OFF) assert not light.is_on(hass, "light.test") # Test turn_on turn_on_calls = async_mock_service(hass, light.DOMAIN, SERVICE_TURN_ON) await hass.services.async_call( light.DOMAIN, SERVICE_TURN_ON, { ATTR_ENTITY_ID: "entity_id_val", light.ATTR_TRANSITION: "transition_val", light.ATTR_BRIGHTNESS: "brightness_val", light.ATTR_RGB_COLOR: "rgb_color_val", light.ATTR_XY_COLOR: "xy_color_val", light.ATTR_PROFILE: "profile_val", light.ATTR_COLOR_NAME: "color_name_val", light.ATTR_WHITE_VALUE: "white_val", }, blocking=True, ) assert len(turn_on_calls) == 1 call = turn_on_calls[-1] assert call.domain == light.DOMAIN assert call.service == SERVICE_TURN_ON assert call.data.get(ATTR_ENTITY_ID) == "entity_id_val" assert call.data.get(light.ATTR_TRANSITION) == "transition_val" assert call.data.get(light.ATTR_BRIGHTNESS) == "brightness_val" assert call.data.get(light.ATTR_RGB_COLOR) == "rgb_color_val" assert call.data.get(light.ATTR_XY_COLOR) == "xy_color_val" assert call.data.get(light.ATTR_PROFILE) == "profile_val" assert call.data.get(light.ATTR_COLOR_NAME) == "color_name_val" assert call.data.get(light.ATTR_WHITE_VALUE) == "white_val" # Test turn_off turn_off_calls = async_mock_service(hass, light.DOMAIN, SERVICE_TURN_OFF) await hass.services.async_call( light.DOMAIN, SERVICE_TURN_OFF, { ATTR_ENTITY_ID: "entity_id_val", light.ATTR_TRANSITION: "transition_val", }, blocking=True, ) assert len(turn_off_calls) == 1 call = turn_off_calls[-1] assert call.domain == light.DOMAIN assert call.service == SERVICE_TURN_OFF assert call.data[ATTR_ENTITY_ID] == "entity_id_val" assert call.data[light.ATTR_TRANSITION] == "transition_val" # Test toggle toggle_calls = async_mock_service(hass, light.DOMAIN, SERVICE_TOGGLE) await hass.services.async_call( light.DOMAIN, SERVICE_TOGGLE, { ATTR_ENTITY_ID: "entity_id_val", light.ATTR_TRANSITION: "transition_val" }, blocking=True, ) assert len(toggle_calls) == 1 call = toggle_calls[-1] assert call.domain == light.DOMAIN assert call.service == SERVICE_TOGGLE assert call.data[ATTR_ENTITY_ID] == "entity_id_val" assert call.data[light.ATTR_TRANSITION] == "transition_val"
async def test_filter_color_modes(hass, caplog, color_mode): """Test filtering of parameters according to color mode.""" hass.states.async_set("light.entity", "off", {}) all_colors = { **VALID_WHITE_VALUE, **VALID_COLOR_NAME, **VALID_COLOR_TEMP, **VALID_HS_COLOR, **VALID_KELVIN, **VALID_RGB_COLOR, **VALID_RGBW_COLOR, **VALID_RGBWW_COLOR, **VALID_XY_COLOR, **VALID_BRIGHTNESS, } turn_on_calls = async_mock_service(hass, "light", "turn_on") await hass.helpers.state.async_reproduce_state([ State("light.entity", "on", { **all_colors, "color_mode": color_mode }) ]) expected_map = { light.COLOR_MODE_COLOR_TEMP: { **VALID_BRIGHTNESS, **VALID_COLOR_TEMP }, light.COLOR_MODE_BRIGHTNESS: VALID_BRIGHTNESS, light.COLOR_MODE_HS: { **VALID_BRIGHTNESS, **VALID_HS_COLOR }, light.COLOR_MODE_ONOFF: { **VALID_BRIGHTNESS }, light.COLOR_MODE_RGB: { **VALID_BRIGHTNESS, **VALID_RGB_COLOR }, light.COLOR_MODE_RGBW: { **VALID_BRIGHTNESS, **VALID_RGBW_COLOR }, light.COLOR_MODE_RGBWW: { **VALID_BRIGHTNESS, **VALID_RGBWW_COLOR }, light.COLOR_MODE_UNKNOWN: { **VALID_BRIGHTNESS, **VALID_HS_COLOR, **VALID_WHITE_VALUE, }, light.COLOR_MODE_WHITE: { **VALID_BRIGHTNESS, light.ATTR_WHITE: VALID_BRIGHTNESS[light.ATTR_BRIGHTNESS], }, light.COLOR_MODE_XY: { **VALID_BRIGHTNESS, **VALID_XY_COLOR }, } expected = expected_map[color_mode] assert len(turn_on_calls) == 1 assert turn_on_calls[0].domain == "light" assert dict(turn_on_calls[0].data) == { "entity_id": "light.entity", **expected } # This should do nothing, the light is already in the desired state hass.states.async_set("light.entity", "on", { "color_mode": color_mode, **expected }) await hass.helpers.state.async_reproduce_state( [State("light.entity", "on", { **expected, "color_mode": color_mode })]) assert len(turn_on_calls) == 1
async def test_reproducing_states(hass, caplog): """Test reproducing Light states.""" hass.states.async_set("light.entity_off", "off", {}) hass.states.async_set("light.entity_bright", "on", VALID_BRIGHTNESS) hass.states.async_set("light.entity_white", "on", VALID_WHITE_VALUE) hass.states.async_set("light.entity_flash", "on", VALID_FLASH) hass.states.async_set("light.entity_effect", "on", VALID_EFFECT) hass.states.async_set("light.entity_trans", "on", VALID_TRANSITION) hass.states.async_set("light.entity_name", "on", VALID_COLOR_NAME) hass.states.async_set("light.entity_temp", "on", VALID_COLOR_TEMP) hass.states.async_set("light.entity_hs", "on", VALID_HS_COLOR) hass.states.async_set("light.entity_kelvin", "on", VALID_KELVIN) hass.states.async_set("light.entity_profile", "on", VALID_PROFILE) hass.states.async_set("light.entity_rgb", "on", VALID_RGB_COLOR) hass.states.async_set("light.entity_xy", "on", VALID_XY_COLOR) turn_on_calls = async_mock_service(hass, "light", "turn_on") turn_off_calls = async_mock_service(hass, "light", "turn_off") # These calls should do nothing as entities already in desired state await async_reproduce_state( hass, [ State("light.entity_off", "off"), State("light.entity_bright", "on", VALID_BRIGHTNESS), State("light.entity_white", "on", VALID_WHITE_VALUE), State("light.entity_flash", "on", VALID_FLASH), State("light.entity_effect", "on", VALID_EFFECT), State("light.entity_trans", "on", VALID_TRANSITION), State("light.entity_name", "on", VALID_COLOR_NAME), State("light.entity_temp", "on", VALID_COLOR_TEMP), State("light.entity_hs", "on", VALID_HS_COLOR), State("light.entity_kelvin", "on", VALID_KELVIN), State("light.entity_profile", "on", VALID_PROFILE), State("light.entity_rgb", "on", VALID_RGB_COLOR), State("light.entity_xy", "on", VALID_XY_COLOR), ], ) assert len(turn_on_calls) == 0 assert len(turn_off_calls) == 0 # Test invalid state is handled await async_reproduce_state(hass, [State("light.entity_off", "not_supported")]) assert "not_supported" in caplog.text assert len(turn_on_calls) == 0 assert len(turn_off_calls) == 0 # Make sure correct services are called await async_reproduce_state( hass, [ State("light.entity_xy", "off"), State("light.entity_off", "on", VALID_BRIGHTNESS), State("light.entity_bright", "on", VALID_WHITE_VALUE), State("light.entity_white", "on", VALID_FLASH), State("light.entity_flash", "on", VALID_EFFECT), State("light.entity_effect", "on", VALID_TRANSITION), State("light.entity_trans", "on", VALID_COLOR_NAME), State("light.entity_name", "on", VALID_COLOR_TEMP), State("light.entity_temp", "on", VALID_HS_COLOR), State("light.entity_hs", "on", VALID_KELVIN), State("light.entity_kelvin", "on", VALID_PROFILE), State("light.entity_profile", "on", VALID_RGB_COLOR), State("light.entity_rgb", "on", VALID_XY_COLOR), ], ) assert len(turn_on_calls) == 12 expected_calls = [] expected_off = dict(VALID_BRIGHTNESS) expected_off["entity_id"] = "light.entity_off" expected_calls.append(expected_off) expected_bright = dict(VALID_WHITE_VALUE) expected_bright["entity_id"] = "light.entity_bright" expected_calls.append(expected_bright) expected_white = dict(VALID_FLASH) expected_white["entity_id"] = "light.entity_white" expected_calls.append(expected_white) expected_flash = dict(VALID_EFFECT) expected_flash["entity_id"] = "light.entity_flash" expected_calls.append(expected_flash) expected_effect = dict(VALID_TRANSITION) expected_effect["entity_id"] = "light.entity_effect" expected_calls.append(expected_effect) expected_trans = dict(VALID_COLOR_NAME) expected_trans["entity_id"] = "light.entity_trans" expected_calls.append(expected_trans) expected_name = dict(VALID_COLOR_TEMP) expected_name["entity_id"] = "light.entity_name" expected_calls.append(expected_name) expected_temp = dict(VALID_HS_COLOR) expected_temp["entity_id"] = "light.entity_temp" expected_calls.append(expected_temp) expected_hs = dict(VALID_KELVIN) expected_hs["entity_id"] = "light.entity_hs" expected_calls.append(expected_hs) expected_kelvin = dict(VALID_PROFILE) expected_kelvin["entity_id"] = "light.entity_kelvin" expected_calls.append(expected_kelvin) expected_profile = dict(VALID_RGB_COLOR) expected_profile["entity_id"] = "light.entity_profile" expected_calls.append(expected_profile) expected_rgb = dict(VALID_XY_COLOR) expected_rgb["entity_id"] = "light.entity_rgb" expected_calls.append(expected_rgb) for call in turn_on_calls: assert call.domain == "light" found = False for expected in expected_calls: if call.data["entity_id"] == expected["entity_id"]: # We found the matching entry assert call.data == expected found = True break # No entry found assert found assert len(turn_off_calls) == 1 assert turn_off_calls[0].domain == "light" assert turn_off_calls[0].data == {"entity_id": "light.entity_xy"}
def calls(hass): """Track calls to a mock serivce.""" return async_mock_service(hass, "zha", "warning_device_warn")
def calls(hass): """Track calls to a mock serivce.""" return async_mock_service(hass, 'test', 'automation')
async def test_set_auto_off_service( hass: HomeAssistantType, mock_bridge: Generator[None, Any, None], mock_api: Generator[None, Any, None], hass_owner_user: "******", hass_read_only_user: "******", ) -> None: """Test the set_auto_off service.""" assert await async_setup_component(hass, DOMAIN, MANDATORY_CONFIGURATION) await hass.async_block_till_done() assert hass.services.has_service(DOMAIN, SERVICE_SET_AUTO_OFF_NAME) await hass.services.async_call( DOMAIN, SERVICE_SET_AUTO_OFF_NAME, { CONF_ENTITY_ID: SWITCH_ENTITY_ID, CONF_AUTO_OFF: DUMMY_AUTO_OFF_SET }, blocking=True, context=Context(user_id=hass_owner_user.id), ) with raises(Unauthorized) as unauthorized_read_only_exc: await hass.services.async_call( DOMAIN, SERVICE_SET_AUTO_OFF_NAME, { CONF_ENTITY_ID: SWITCH_ENTITY_ID, CONF_AUTO_OFF: DUMMY_AUTO_OFF_SET }, blocking=True, context=Context(user_id=hass_read_only_user.id), ) assert unauthorized_read_only_exc.type is Unauthorized with raises(Unauthorized) as unauthorized_wrong_entity_exc: await hass.services.async_call( DOMAIN, SERVICE_SET_AUTO_OFF_NAME, { CONF_ENTITY_ID: "light.not_related_entity", CONF_AUTO_OFF: DUMMY_AUTO_OFF_SET, }, blocking=True, context=Context(user_id=hass_owner_user.id), ) assert unauthorized_wrong_entity_exc.type is Unauthorized with raises(UnknownUser) as unknown_user_exc: await hass.services.async_call( DOMAIN, SERVICE_SET_AUTO_OFF_NAME, { CONF_ENTITY_ID: SWITCH_ENTITY_ID, CONF_AUTO_OFF: DUMMY_AUTO_OFF_SET }, blocking=True, context=Context(user_id="not_real_user"), ) assert unknown_user_exc.type is UnknownUser service_calls = async_mock_service(hass, DOMAIN, SERVICE_SET_AUTO_OFF_NAME, SERVICE_SET_AUTO_OFF_SCHEMA) await hass.services.async_call( DOMAIN, SERVICE_SET_AUTO_OFF_NAME, { CONF_ENTITY_ID: SWITCH_ENTITY_ID, CONF_AUTO_OFF: DUMMY_AUTO_OFF_SET }, ) await hass.async_block_till_done() assert len(service_calls) == 1 assert str( service_calls[0].data[CONF_AUTO_OFF]) == DUMMY_AUTO_OFF_SET.lstrip("0")
async def test_action(opp): """Test for actions.""" opp.states.async_set( "humidifier.entity", STATE_ON, {const.ATTR_AVAILABLE_MODES: [const.MODE_HOME, const.MODE_AWAY]}, ) assert await async_setup_component( opp, automation.DOMAIN, { automation.DOMAIN: [ { "trigger": { "platform": "event", "event_type": "test_event_turn_off", }, "action": { "domain": DOMAIN, "device_id": "abcdefgh", "entity_id": "humidifier.entity", "type": "turn_off", }, }, { "trigger": { "platform": "event", "event_type": "test_event_turn_on", }, "action": { "domain": DOMAIN, "device_id": "abcdefgh", "entity_id": "humidifier.entity", "type": "turn_on", }, }, { "trigger": { "platform": "event", "event_type": "test_event_toggle" }, "action": { "domain": DOMAIN, "device_id": "abcdefgh", "entity_id": "humidifier.entity", "type": "toggle", }, }, { "trigger": { "platform": "event", "event_type": "test_event_set_humidity", }, "action": { "domain": DOMAIN, "device_id": "abcdefgh", "entity_id": "humidifier.entity", "type": "set_humidity", "humidity": 35, }, }, { "trigger": { "platform": "event", "event_type": "test_event_set_mode", }, "action": { "domain": DOMAIN, "device_id": "abcdefgh", "entity_id": "humidifier.entity", "type": "set_mode", "mode": const.MODE_AWAY, }, }, ] }, ) set_humidity_calls = async_mock_service(opp, "humidifier", "set_humidity") set_mode_calls = async_mock_service(opp, "humidifier", "set_mode") turn_on_calls = async_mock_service(opp, "humidifier", "turn_on") turn_off_calls = async_mock_service(opp, "humidifier", "turn_off") toggle_calls = async_mock_service(opp, "humidifier", "toggle") assert len(set_humidity_calls) == 0 assert len(set_mode_calls) == 0 assert len(turn_on_calls) == 0 assert len(turn_off_calls) == 0 assert len(toggle_calls) == 0 opp.bus.async_fire("test_event_set_humidity") await opp.async_block_till_done() assert len(set_humidity_calls) == 1 assert len(set_mode_calls) == 0 assert len(turn_on_calls) == 0 assert len(turn_off_calls) == 0 assert len(toggle_calls) == 0 opp.bus.async_fire("test_event_set_mode") await opp.async_block_till_done() assert len(set_humidity_calls) == 1 assert len(set_mode_calls) == 1 assert len(turn_on_calls) == 0 assert len(turn_off_calls) == 0 assert len(toggle_calls) == 0 opp.bus.async_fire("test_event_turn_off") await opp.async_block_till_done() assert len(set_humidity_calls) == 1 assert len(set_mode_calls) == 1 assert len(turn_on_calls) == 0 assert len(turn_off_calls) == 1 assert len(toggle_calls) == 0 opp.bus.async_fire("test_event_turn_on") await opp.async_block_till_done() assert len(set_humidity_calls) == 1 assert len(set_mode_calls) == 1 assert len(turn_on_calls) == 1 assert len(turn_off_calls) == 1 assert len(toggle_calls) == 0 opp.bus.async_fire("test_event_toggle") await opp.async_block_till_done() assert len(set_humidity_calls) == 1 assert len(set_mode_calls) == 1 assert len(turn_on_calls) == 1 assert len(turn_off_calls) == 1 assert len(toggle_calls) == 1
async def test_reproducing_states(hass, caplog): """Test reproducing Water heater states.""" hass.states.async_set("water_heater.entity_off", STATE_OFF, {}) hass.states.async_set("water_heater.entity_on", STATE_ON, {ATTR_TEMPERATURE: 45}) hass.states.async_set("water_heater.entity_away", STATE_ON, {ATTR_AWAY_MODE: True}) hass.states.async_set("water_heater.entity_gas", STATE_GAS, {}) hass.states.async_set( "water_heater.entity_all", STATE_ECO, { ATTR_AWAY_MODE: True, ATTR_TEMPERATURE: 45 }, ) turn_on_calls = async_mock_service(hass, "water_heater", SERVICE_TURN_ON) turn_off_calls = async_mock_service(hass, "water_heater", SERVICE_TURN_OFF) set_op_calls = async_mock_service(hass, "water_heater", SERVICE_SET_OPERATION_MODE) set_temp_calls = async_mock_service(hass, "water_heater", SERVICE_SET_TEMPERATURE) set_away_calls = async_mock_service(hass, "water_heater", SERVICE_SET_AWAY_MODE) # These calls should do nothing as entities already in desired state await hass.helpers.state.async_reproduce_state( [ State("water_heater.entity_off", STATE_OFF), State("water_heater.entity_on", STATE_ON, {ATTR_TEMPERATURE: 45}), State("water_heater.entity_away", STATE_ON, {ATTR_AWAY_MODE: True}), State("water_heater.entity_gas", STATE_GAS, {}), State( "water_heater.entity_all", STATE_ECO, { ATTR_AWAY_MODE: True, ATTR_TEMPERATURE: 45 }, ), ], blocking=True, ) assert len(turn_on_calls) == 0 assert len(turn_off_calls) == 0 assert len(set_op_calls) == 0 assert len(set_temp_calls) == 0 assert len(set_away_calls) == 0 # Test invalid state is handled await hass.helpers.state.async_reproduce_state( [State("water_heater.entity_off", "not_supported")], blocking=True) assert "not_supported" in caplog.text assert len(turn_on_calls) == 0 assert len(turn_off_calls) == 0 assert len(set_op_calls) == 0 assert len(set_temp_calls) == 0 assert len(set_away_calls) == 0 # Make sure correct services are called await hass.helpers.state.async_reproduce_state( [ State("water_heater.entity_on", STATE_OFF), State("water_heater.entity_off", STATE_ON, {ATTR_TEMPERATURE: 45}), State("water_heater.entity_all", STATE_ECO, {ATTR_AWAY_MODE: False}), State("water_heater.entity_away", STATE_GAS, {}), State( "water_heater.entity_gas", STATE_ECO, { ATTR_AWAY_MODE: True, ATTR_TEMPERATURE: 45 }, ), # Should not raise State("water_heater.non_existing", "on"), ], blocking=True, ) assert len(turn_on_calls) == 1 assert turn_on_calls[0].domain == "water_heater" assert turn_on_calls[0].data == {"entity_id": "water_heater.entity_off"} assert len(turn_off_calls) == 1 assert turn_off_calls[0].domain == "water_heater" assert turn_off_calls[0].data == {"entity_id": "water_heater.entity_on"} VALID_OP_CALLS = [ { "entity_id": "water_heater.entity_away", ATTR_OPERATION_MODE: STATE_GAS }, { "entity_id": "water_heater.entity_gas", ATTR_OPERATION_MODE: STATE_ECO }, ] assert len(set_op_calls) == 2 for call in set_op_calls: assert call.domain == "water_heater" assert call.data in VALID_OP_CALLS VALID_OP_CALLS.remove(call.data) VALID_TEMP_CALLS = [ { "entity_id": "water_heater.entity_off", ATTR_TEMPERATURE: 45 }, { "entity_id": "water_heater.entity_gas", ATTR_TEMPERATURE: 45 }, ] assert len(set_temp_calls) == 2 for call in set_temp_calls: assert call.domain == "water_heater" assert call.data in VALID_TEMP_CALLS VALID_TEMP_CALLS.remove(call.data) VALID_AWAY_CALLS = [ { "entity_id": "water_heater.entity_all", ATTR_AWAY_MODE: False }, { "entity_id": "water_heater.entity_gas", ATTR_AWAY_MODE: True }, ] assert len(set_away_calls) == 2 for call in set_away_calls: assert call.domain == "water_heater" assert call.data in VALID_AWAY_CALLS VALID_AWAY_CALLS.remove(call.data)
async def test_fan_speed(opp, hk_driver, events): """Test fan with speed.""" entity_id = "fan.demo" opp.states.async_set( entity_id, STATE_ON, { ATTR_SUPPORTED_FEATURES: SUPPORT_SET_SPEED, ATTR_PERCENTAGE: 0, ATTR_PERCENTAGE_STEP: 25, }, ) await opp.async_block_till_done() acc = Fan(opp, hk_driver, "Fan", entity_id, 1, None) hk_driver.add_accessory(acc) # Initial value can be anything but 0. If it is 0, it might cause HomeKit to set the # speed to 100 when turning on a fan on a freshly booted up server. assert acc.char_speed.value != 0 assert acc.char_speed.properties[PROP_MIN_STEP] == 25 await acc.run() await opp.async_block_till_done() opp.states.async_set(entity_id, STATE_ON, {ATTR_PERCENTAGE: 100}) await opp.async_block_till_done() assert acc.char_speed.value == 100 # Set from HomeKit call_set_percentage = async_mock_service(opp, DOMAIN, "set_percentage") char_speed_iid = acc.char_speed.to_HAP()[HAP_REPR_IID] char_active_iid = acc.char_active.to_HAP()[HAP_REPR_IID] hk_driver.set_characteristics( { HAP_REPR_CHARS: [ { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_speed_iid, HAP_REPR_VALUE: 42, }, ] }, "mock_addr", ) await opp.async_add_executor_job(acc.char_speed.client_update_value, 42) await opp.async_block_till_done() assert acc.char_speed.value == 42 assert acc.char_active.value == 1 assert call_set_percentage[0] assert call_set_percentage[0].data[ATTR_ENTITY_ID] == entity_id assert call_set_percentage[0].data[ATTR_PERCENTAGE] == 42 assert len(events) == 1 assert events[-1].data[ATTR_VALUE] == 42 # Verify speed is preserved from off to on opp.states.async_set(entity_id, STATE_OFF, {ATTR_PERCENTAGE: 42}) await opp.async_block_till_done() assert acc.char_speed.value == 42 assert acc.char_active.value == 0 hk_driver.set_characteristics( { HAP_REPR_CHARS: [ { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_active_iid, HAP_REPR_VALUE: 1, }, ] }, "mock_addr", ) await opp.async_block_till_done() assert acc.char_speed.value == 42 assert acc.char_active.value == 1
async def test_motion_light(hass): """Test motion light blueprint.""" hass.states.async_set("binary_sensor.kitchen", "off") with patch_blueprint( "motion_light.yaml", BUILTIN_BLUEPRINT_FOLDER / "motion_light.yaml", ): assert await async_setup_component( hass, "automation", { "automation": { "use_blueprint": { "path": "motion_light.yaml", "input": { "light_target": { "entity_id": "light.kitchen" }, "motion_entity": "binary_sensor.kitchen", }, } } }, ) turn_on_calls = async_mock_service(hass, "light", "turn_on") turn_off_calls = async_mock_service(hass, "light", "turn_off") # Turn on motion hass.states.async_set("binary_sensor.kitchen", "on") # Can't block till done because delay is active # So wait 5 event loop iterations to process script for _ in range(5): await asyncio.sleep(0) assert len(turn_on_calls) == 1 # Test light doesn't turn off if motion stays async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=200)) for _ in range(5): await asyncio.sleep(0) assert len(turn_off_calls) == 0 # Test light turns off off 120s after last motion hass.states.async_set("binary_sensor.kitchen", "off") for _ in range(5): await asyncio.sleep(0) async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=120)) await hass.async_block_till_done() assert len(turn_off_calls) == 1 # Test restarting the script hass.states.async_set("binary_sensor.kitchen", "on") for _ in range(5): await asyncio.sleep(0) assert len(turn_on_calls) == 2 assert len(turn_off_calls) == 1 hass.states.async_set("binary_sensor.kitchen", "off") for _ in range(5): await asyncio.sleep(0) hass.states.async_set("binary_sensor.kitchen", "on") for _ in range(15): await asyncio.sleep(0) assert len(turn_on_calls) == 3 assert len(turn_off_calls) == 1 # Verify trigger works await hass.services.async_call( "automation", "trigger", {"entity_id": "automation.automation_0"}, ) for _ in range(25): await asyncio.sleep(0) assert len(turn_on_calls) == 4
async def test_fan_direction(opp, hk_driver, events): """Test fan with direction.""" entity_id = "fan.demo" opp.states.async_set( entity_id, STATE_ON, {ATTR_SUPPORTED_FEATURES: SUPPORT_DIRECTION, ATTR_DIRECTION: DIRECTION_FORWARD}, ) await opp.async_block_till_done() acc = Fan(opp, hk_driver, "Fan", entity_id, 1, None) hk_driver.add_accessory(acc) assert acc.char_direction.value == 0 await acc.run() await opp.async_block_till_done() assert acc.char_direction.value == 0 opp.states.async_set(entity_id, STATE_ON, {ATTR_DIRECTION: DIRECTION_REVERSE}) await opp.async_block_till_done() assert acc.char_direction.value == 1 # Set from HomeKit call_set_direction = async_mock_service(opp, DOMAIN, "set_direction") char_direction_iid = acc.char_direction.to_HAP()[HAP_REPR_IID] hk_driver.set_characteristics( { HAP_REPR_CHARS: [ { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_direction_iid, HAP_REPR_VALUE: 0, }, ] }, "mock_addr", ) await opp.async_block_till_done() assert call_set_direction[0] assert call_set_direction[0].data[ATTR_ENTITY_ID] == entity_id assert call_set_direction[0].data[ATTR_DIRECTION] == DIRECTION_FORWARD assert len(events) == 1 assert events[-1].data[ATTR_VALUE] == DIRECTION_FORWARD hk_driver.set_characteristics( { HAP_REPR_CHARS: [ { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_direction_iid, HAP_REPR_VALUE: 1, }, ] }, "mock_addr", ) await opp.async_add_executor_job(acc.char_direction.client_update_value, 1) await opp.async_block_till_done() assert call_set_direction[1] assert call_set_direction[1].data[ATTR_ENTITY_ID] == entity_id assert call_set_direction[1].data[ATTR_DIRECTION] == DIRECTION_REVERSE assert len(events) == 2 assert events[-1].data[ATTR_VALUE] == DIRECTION_REVERSE
def calls(hass): """Track calls to a mock service.""" return async_mock_service(hass, "test", "automation")
async def test_overrides(hass, config_children_and_attr): """Test overrides.""" config = copy(config_children_and_attr) excmd = {"service": "test.override", "data": {}} config["name"] = "overridden" config["commands"] = { "turn_on": excmd, "turn_off": excmd, "volume_up": excmd, "volume_down": excmd, "volume_mute": excmd, "volume_set": excmd, "select_sound_mode": excmd, "select_source": excmd, "repeat_set": excmd, "shuffle_set": excmd, "media_play": excmd, "media_play_pause": excmd, "media_pause": excmd, "media_stop": excmd, "media_next_track": excmd, "media_previous_track": excmd, "clear_playlist": excmd, "play_media": excmd, "toggle": excmd, } await async_setup_component(hass, "media_player", {"media_player": config}) await hass.async_block_till_done() service = async_mock_service(hass, "test", "override") await hass.services.async_call( "media_player", "turn_on", service_data={"entity_id": "media_player.overridden"}, blocking=True, ) assert len(service) == 1 await hass.services.async_call( "media_player", "turn_off", service_data={"entity_id": "media_player.overridden"}, blocking=True, ) assert len(service) == 2 await hass.services.async_call( "media_player", "volume_up", service_data={"entity_id": "media_player.overridden"}, blocking=True, ) assert len(service) == 3 await hass.services.async_call( "media_player", "volume_down", service_data={"entity_id": "media_player.overridden"}, blocking=True, ) assert len(service) == 4 await hass.services.async_call( "media_player", "volume_mute", service_data={ "entity_id": "media_player.overridden", "is_volume_muted": True, }, blocking=True, ) assert len(service) == 5 await hass.services.async_call( "media_player", "volume_set", service_data={ "entity_id": "media_player.overridden", "volume_level": 1 }, blocking=True, ) assert len(service) == 6 await hass.services.async_call( "media_player", "select_sound_mode", service_data={ "entity_id": "media_player.overridden", "sound_mode": "music", }, blocking=True, ) assert len(service) == 7 await hass.services.async_call( "media_player", "select_source", service_data={ "entity_id": "media_player.overridden", "source": "video1" }, blocking=True, ) assert len(service) == 8 await hass.services.async_call( "media_player", "repeat_set", service_data={ "entity_id": "media_player.overridden", "repeat": "all" }, blocking=True, ) assert len(service) == 9 await hass.services.async_call( "media_player", "shuffle_set", service_data={ "entity_id": "media_player.overridden", "shuffle": True }, blocking=True, ) assert len(service) == 10 await hass.services.async_call( "media_player", "media_play", service_data={"entity_id": "media_player.overridden"}, blocking=True, ) assert len(service) == 11 await hass.services.async_call( "media_player", "media_pause", service_data={"entity_id": "media_player.overridden"}, blocking=True, ) assert len(service) == 12 await hass.services.async_call( "media_player", "media_stop", service_data={"entity_id": "media_player.overridden"}, blocking=True, ) assert len(service) == 13 await hass.services.async_call( "media_player", "media_next_track", service_data={"entity_id": "media_player.overridden"}, blocking=True, ) assert len(service) == 14 await hass.services.async_call( "media_player", "media_previous_track", service_data={"entity_id": "media_player.overridden"}, blocking=True, ) assert len(service) == 15 await hass.services.async_call( "media_player", "clear_playlist", service_data={"entity_id": "media_player.overridden"}, blocking=True, ) assert len(service) == 16 await hass.services.async_call( "media_player", "media_play_pause", service_data={"entity_id": "media_player.overridden"}, blocking=True, ) assert len(service) == 17 await hass.services.async_call( "media_player", "play_media", service_data={ "entity_id": "media_player.overridden", "media_content_id": 1, "media_content_type": "channel", }, blocking=True, ) assert len(service) == 18 await hass.services.async_call( "media_player", "toggle", service_data={"entity_id": "media_player.overridden"}, blocking=True, ) assert len(service) == 19
async def test_hygrostat_power_state(hass, hk_driver, events): """Test if accessory and HA are updated accordingly.""" entity_id = "humidifier.test" hass.states.async_set( entity_id, STATE_ON, {ATTR_HUMIDITY: 43}, ) await hass.async_block_till_done() acc = HumidifierDehumidifier( hass, hk_driver, "HumidifierDehumidifier", entity_id, 1, None ) hk_driver.add_accessory(acc) await acc.run() await hass.async_block_till_done() assert acc.char_current_humidifier_dehumidifier.value == 2 assert acc.char_target_humidifier_dehumidifier.value == 1 assert acc.char_active.value == 1 hass.states.async_set( entity_id, STATE_OFF, {ATTR_HUMIDITY: 43}, ) await hass.async_block_till_done() assert acc.char_current_humidifier_dehumidifier.value == 0 assert acc.char_target_humidifier_dehumidifier.value == 1 assert acc.char_active.value == 0 # Set from HomeKit call_turn_on = async_mock_service(hass, DOMAIN, SERVICE_TURN_ON) char_active_iid = acc.char_active.to_HAP()[HAP_REPR_IID] hk_driver.set_characteristics( { HAP_REPR_CHARS: [ { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_active_iid, HAP_REPR_VALUE: 1, }, ] }, "mock_addr", ) await hass.async_block_till_done() assert len(call_turn_on) == 1 assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id assert acc.char_active.value == 1 assert len(events) == 1 assert events[-1].data[ATTR_VALUE] == "Active to 1" call_turn_off = async_mock_service(hass, DOMAIN, SERVICE_TURN_OFF) hk_driver.set_characteristics( { HAP_REPR_CHARS: [ { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_active_iid, HAP_REPR_VALUE: 0, }, ] }, "mock_addr", ) await hass.async_block_till_done() assert len(call_turn_off) == 1 assert call_turn_off[0].data[ATTR_ENTITY_ID] == entity_id assert acc.char_active.value == 0 assert len(events) == 2 assert events[-1].data[ATTR_VALUE] == "Active to 0"
def __init__(self, hass, name): """Initialize the media player.""" self.hass = hass self._name = name self.entity_id = media_player.ENTITY_ID_FORMAT.format(name) self._state = STATE_OFF self._volume_level = 0 self._is_volume_muted = False self._media_title = None self._supported_features = 0 self._source = None self._tracks = 12 self._media_image_url = None self._shuffle = False self._sound_mode = None self.service_calls = { "turn_on": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_TURN_ON), "turn_off": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_TURN_OFF), "mute_volume": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_VOLUME_MUTE), "set_volume_level": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_VOLUME_SET), "media_play": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_MEDIA_PLAY), "media_pause": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_MEDIA_PAUSE), "media_stop": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_MEDIA_STOP), "media_previous_track": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_MEDIA_PREVIOUS_TRACK), "media_next_track": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_MEDIA_NEXT_TRACK), "media_seek": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_MEDIA_SEEK), "play_media": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_PLAY_MEDIA), "volume_up": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_VOLUME_UP), "volume_down": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_VOLUME_DOWN), "media_play_pause": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_MEDIA_PLAY_PAUSE), "select_sound_mode": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_SELECT_SOUND_MODE), "select_source": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_SELECT_SOURCE), "toggle": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_TOGGLE), "clear_playlist": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_CLEAR_PLAYLIST), "repeat_set": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_REPEAT_SET), "shuffle_set": async_mock_service(hass, media_player.DOMAIN, media_player.SERVICE_SHUFFLE_SET), }
async def test_humidifier(hass, hk_driver, events): """Test if humidifier accessory and HA are updated accordingly.""" entity_id = "humidifier.test" hass.states.async_set(entity_id, STATE_OFF) await hass.async_block_till_done() acc = HumidifierDehumidifier( hass, hk_driver, "HumidifierDehumidifier", entity_id, 1, None ) hk_driver.add_accessory(acc) await acc.run() await hass.async_block_till_done() assert acc.aid == 1 assert acc.category == CATEGORY_HUMIDIFIER assert acc.char_current_humidifier_dehumidifier.value == 0 assert acc.char_target_humidifier_dehumidifier.value == 1 assert acc.char_current_humidity.value == 0 assert acc.char_target_humidity.value == 45.0 assert acc.char_active.value == 0 assert acc.char_target_humidity.properties[PROP_MAX_VALUE] == DEFAULT_MAX_HUMIDITY assert acc.char_target_humidity.properties[PROP_MIN_VALUE] == DEFAULT_MIN_HUMIDITY assert acc.char_target_humidity.properties[PROP_MIN_STEP] == 1.0 assert acc.char_target_humidifier_dehumidifier.properties[PROP_VALID_VALUES] == { "Humidifier": 1 } hass.states.async_set( entity_id, STATE_ON, {ATTR_HUMIDITY: 47}, ) await hass.async_block_till_done() assert acc.char_target_humidity.value == 47.0 assert acc.char_current_humidifier_dehumidifier.value == 2 assert acc.char_target_humidifier_dehumidifier.value == 1 assert acc.char_active.value == 1 hass.states.async_set( entity_id, STATE_OFF, {ATTR_HUMIDITY: 42, ATTR_DEVICE_CLASS: DEVICE_CLASS_HUMIDIFIER}, ) await hass.async_block_till_done() assert acc.char_target_humidity.value == 42.0 assert acc.char_current_humidifier_dehumidifier.value == 0 assert acc.char_target_humidifier_dehumidifier.value == 1 assert acc.char_active.value == 0 # Set from HomeKit call_set_humidity = async_mock_service(hass, DOMAIN, SERVICE_SET_HUMIDITY) char_target_humidity_iid = acc.char_target_humidity.to_HAP()[HAP_REPR_IID] hk_driver.set_characteristics( { HAP_REPR_CHARS: [ { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_target_humidity_iid, HAP_REPR_VALUE: 39.0, }, ] }, "mock_addr", ) await hass.async_block_till_done() assert len(call_set_humidity) == 1 assert call_set_humidity[0].data[ATTR_ENTITY_ID] == entity_id assert call_set_humidity[0].data[ATTR_HUMIDITY] == 39.0 assert acc.char_target_humidity.value == 39.0 assert len(events) == 1 assert events[-1].data[ATTR_VALUE] == "RelativeHumidityHumidifierThreshold to 39.0%"
async def test_script_variables(hass, caplog): """Test defining scripts.""" assert await async_setup_component( hass, "script", { "script": { "script1": { "variables": { "test_var": "from_config", "templated_config_var": "{{ var_from_service | default('config-default') }}", }, "sequence": [ { "service": "test.script", "data": { "value": "{{ test_var }}", "templated_config_var": "{{ templated_config_var }}", }, }, ], }, "script2": { "variables": { "test_var": "from_config", }, "sequence": [ { "service": "test.script", "data": { "value": "{{ test_var }}", }, }, ], }, "script3": { "variables": { "test_var": "{{ break + 1 }}", }, "sequence": [ { "service": "test.script", "data": { "value": "{{ test_var }}", }, }, ], }, } }, ) mock_calls = async_mock_service(hass, "test", "script") await hass.services.async_call( "script", "script1", {"var_from_service": "hello"}, blocking=True ) assert len(mock_calls) == 1 assert mock_calls[0].data["value"] == "from_config" assert mock_calls[0].data["templated_config_var"] == "hello" await hass.services.async_call( "script", "script1", {"test_var": "from_service"}, blocking=True ) assert len(mock_calls) == 2 assert mock_calls[1].data["value"] == "from_service" assert mock_calls[1].data["templated_config_var"] == "config-default" # Call script with vars but no templates in it await hass.services.async_call( "script", "script2", {"test_var": "from_service"}, blocking=True ) assert len(mock_calls) == 3 assert mock_calls[2].data["value"] == "from_service" assert "Error rendering variables" not in caplog.text with pytest.raises(template.TemplateError): await hass.services.async_call("script", "script3", blocking=True) assert "Error rendering variables" in caplog.text assert len(mock_calls) == 3 await hass.services.async_call("script", "script3", {"break": 0}, blocking=True) assert len(mock_calls) == 4 assert mock_calls[3].data["value"] == 1
async def test_temperature_setting_climate_range(hass): """Test TemperatureSetting trait support for climate domain - range.""" assert not trait.TemperatureSettingTrait.supported(climate.DOMAIN, 0) assert trait.TemperatureSettingTrait.supported( climate.DOMAIN, climate.SUPPORT_OPERATION_MODE) hass.config.units.temperature_unit = TEMP_FAHRENHEIT trt = trait.TemperatureSettingTrait(hass, State( 'climate.bla', climate.STATE_AUTO, { climate.ATTR_CURRENT_TEMPERATURE: 70, climate.ATTR_CURRENT_HUMIDITY: 25, climate.ATTR_OPERATION_MODE: climate.STATE_AUTO, climate.ATTR_OPERATION_LIST: [ climate.STATE_OFF, climate.STATE_COOL, climate.STATE_HEAT, climate.STATE_AUTO, ], climate.ATTR_TARGET_TEMP_HIGH: 75, climate.ATTR_TARGET_TEMP_LOW: 65, climate.ATTR_MIN_TEMP: 50, climate.ATTR_MAX_TEMP: 80 })) assert trt.sync_attributes() == { 'availableThermostatModes': 'off,cool,heat,heatcool', 'thermostatTemperatureUnit': 'F', } assert trt.query_attributes() == { 'thermostatMode': 'heatcool', 'thermostatTemperatureAmbient': 21.1, 'thermostatHumidityAmbient': 25, 'thermostatTemperatureSetpointLow': 18.3, 'thermostatTemperatureSetpointHigh': 23.9, } assert trt.can_execute(trait.COMMAND_THERMOSTAT_TEMPERATURE_SETPOINT, {}) assert trt.can_execute(trait.COMMAND_THERMOSTAT_TEMPERATURE_SET_RANGE, {}) assert trt.can_execute(trait.COMMAND_THERMOSTAT_SET_MODE, {}) calls = async_mock_service( hass, climate.DOMAIN, climate.SERVICE_SET_TEMPERATURE) await trt.execute(trait.COMMAND_THERMOSTAT_TEMPERATURE_SET_RANGE, { 'thermostatTemperatureSetpointHigh': 25, 'thermostatTemperatureSetpointLow': 20, }) assert len(calls) == 1 assert calls[0].data == { ATTR_ENTITY_ID: 'climate.bla', climate.ATTR_TARGET_TEMP_HIGH: 77, climate.ATTR_TARGET_TEMP_LOW: 68, } calls = async_mock_service( hass, climate.DOMAIN, climate.SERVICE_SET_OPERATION_MODE) await trt.execute(trait.COMMAND_THERMOSTAT_SET_MODE, { 'thermostatMode': 'heatcool', }) assert len(calls) == 1 assert calls[0].data == { ATTR_ENTITY_ID: 'climate.bla', climate.ATTR_OPERATION_MODE: climate.STATE_AUTO, } with pytest.raises(helpers.SmartHomeError) as err: await trt.execute(trait.COMMAND_THERMOSTAT_TEMPERATURE_SETPOINT, { 'thermostatTemperatureSetpoint': -100, }) assert err.value.code == const.ERR_VALUE_OUT_OF_RANGE hass.config.units.temperature_unit = TEMP_CELSIUS
async def test_reproducing_states(hass, caplog): """Test reproducing Input datetime states.""" hass.states.async_set( "input_datetime.entity_datetime", "2010-10-10 01:20:00", { "has_date": True, "has_time": True }, ) hass.states.async_set("input_datetime.entity_time", "01:20:00", { "has_date": False, "has_time": True }) hass.states.async_set( "input_datetime.entity_date", "2010-10-10", { "has_date": True, "has_time": False }, ) datetime_calls = async_mock_service(hass, "input_datetime", "set_datetime") # These calls should do nothing as entities already in desired state await hass.helpers.state.async_reproduce_state([ State("input_datetime.entity_datetime", "2010-10-10 01:20:00"), State("input_datetime.entity_time", "01:20:00"), State("input_datetime.entity_date", "2010-10-10"), ], ) assert len(datetime_calls) == 0 # Test invalid state is handled await hass.helpers.state.async_reproduce_state([ State("input_datetime.entity_datetime", "not_supported"), State("input_datetime.entity_datetime", "not-valid-date"), State("input_datetime.entity_datetime", "not:valid:time"), State("input_datetime.entity_datetime", "1234-56-78 90:12:34"), ], ) assert "not_supported" in caplog.text assert "not-valid-date" in caplog.text assert "not:valid:time" in caplog.text assert "1234-56-78 90:12:34" in caplog.text assert len(datetime_calls) == 0 # Make sure correct services are called await hass.helpers.state.async_reproduce_state( [ State("input_datetime.entity_datetime", "2011-10-10 02:20:00"), State("input_datetime.entity_time", "02:20:00"), State("input_datetime.entity_date", "2011-10-10"), # Should not raise State("input_datetime.non_existing", "2010-10-10 01:20:00"), ], ) valid_calls = [ { "entity_id": "input_datetime.entity_datetime", "datetime": "2011-10-10 02:20:00", }, { "entity_id": "input_datetime.entity_time", "time": "02:20:00" }, { "entity_id": "input_datetime.entity_date", "date": "2011-10-10" }, ] assert len(datetime_calls) == 3 for call in datetime_calls: assert call.domain == "input_datetime" assert call.data in valid_calls valid_calls.remove(call.data)
async def test_valve_set_state(hass, hk_driver, events): """Test if Valve accessory and HA are updated accordingly.""" entity_id = "switch.valve_test" hass.states.async_set(entity_id, None) await hass.async_block_till_done() acc = Valve(hass, hk_driver, "Valve", entity_id, 2, {CONF_TYPE: TYPE_FAUCET}) await acc.run() await hass.async_block_till_done() assert acc.category == 29 # Faucet assert acc.char_valve_type.value == 3 # Water faucet acc = Valve(hass, hk_driver, "Valve", entity_id, 2, {CONF_TYPE: TYPE_SHOWER}) await acc.run() await hass.async_block_till_done() assert acc.category == 30 # Shower assert acc.char_valve_type.value == 2 # Shower head acc = Valve(hass, hk_driver, "Valve", entity_id, 2, {CONF_TYPE: TYPE_SPRINKLER}) await acc.run() await hass.async_block_till_done() assert acc.category == 28 # Sprinkler assert acc.char_valve_type.value == 1 # Irrigation acc = Valve(hass, hk_driver, "Valve", entity_id, 2, {CONF_TYPE: TYPE_VALVE}) await acc.run() await hass.async_block_till_done() assert acc.aid == 2 assert acc.category == 29 # Faucet assert acc.char_active.value == 0 assert acc.char_in_use.value == 0 assert acc.char_valve_type.value == 0 # Generic Valve hass.states.async_set(entity_id, STATE_ON) await hass.async_block_till_done() assert acc.char_active.value == 1 assert acc.char_in_use.value == 1 hass.states.async_set(entity_id, STATE_OFF) await hass.async_block_till_done() assert acc.char_active.value == 0 assert acc.char_in_use.value == 0 # Set from HomeKit call_turn_on = async_mock_service(hass, "switch", "turn_on") call_turn_off = async_mock_service(hass, "switch", "turn_off") await hass.async_add_executor_job(acc.char_active.client_update_value, 1) await hass.async_block_till_done() assert acc.char_in_use.value == 1 assert call_turn_on assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id assert len(events) == 1 assert events[-1].data[ATTR_VALUE] is None await hass.async_add_executor_job(acc.char_active.client_update_value, 0) await hass.async_block_till_done() assert acc.char_in_use.value == 0 assert call_turn_off assert call_turn_off[0].data[ATTR_ENTITY_ID] == entity_id assert len(events) == 2 assert events[-1].data[ATTR_VALUE] is None
async def test_garage_door_open_close(hass, hk_driver, events): """Test if accessory and HA are updated accordingly.""" entity_id = "cover.garage_door" hass.states.async_set(entity_id, None) await hass.async_block_till_done() acc = GarageDoorOpener(hass, hk_driver, "Garage Door", entity_id, 2, None) await acc.run() await hass.async_block_till_done() assert acc.aid == 2 assert acc.category == 4 # GarageDoorOpener assert acc.char_current_state.value == HK_DOOR_OPEN assert acc.char_target_state.value == HK_DOOR_OPEN hass.states.async_set(entity_id, STATE_CLOSED, {ATTR_OBSTRUCTION_DETECTED: False}) await hass.async_block_till_done() assert acc.char_current_state.value == HK_DOOR_CLOSED assert acc.char_target_state.value == HK_DOOR_CLOSED assert acc.char_obstruction_detected.value is False hass.states.async_set(entity_id, STATE_OPEN, {ATTR_OBSTRUCTION_DETECTED: True}) await hass.async_block_till_done() assert acc.char_current_state.value == HK_DOOR_OPEN assert acc.char_target_state.value == HK_DOOR_OPEN assert acc.char_obstruction_detected.value is True hass.states.async_set(entity_id, STATE_UNAVAILABLE, {ATTR_OBSTRUCTION_DETECTED: False}) await hass.async_block_till_done() assert acc.char_current_state.value == HK_DOOR_OPEN assert acc.char_target_state.value == HK_DOOR_OPEN assert acc.char_obstruction_detected.value is False hass.states.async_set(entity_id, STATE_UNKNOWN) await hass.async_block_till_done() assert acc.char_current_state.value == HK_DOOR_OPEN assert acc.char_target_state.value == HK_DOOR_OPEN # Set from HomeKit call_close_cover = async_mock_service(hass, DOMAIN, "close_cover") call_open_cover = async_mock_service(hass, DOMAIN, "open_cover") acc.char_target_state.client_update_value(1) await hass.async_block_till_done() assert call_close_cover assert call_close_cover[0].data[ATTR_ENTITY_ID] == entity_id assert acc.char_current_state.value == HK_DOOR_CLOSING assert acc.char_target_state.value == HK_DOOR_CLOSED assert len(events) == 1 assert events[-1].data[ATTR_VALUE] is None hass.states.async_set(entity_id, STATE_CLOSED) await hass.async_block_till_done() acc.char_target_state.client_update_value(1) await hass.async_block_till_done() assert acc.char_current_state.value == HK_DOOR_CLOSED assert acc.char_target_state.value == HK_DOOR_CLOSED assert len(events) == 2 assert events[-1].data[ATTR_VALUE] is None acc.char_target_state.client_update_value(0) await hass.async_block_till_done() assert call_open_cover assert call_open_cover[0].data[ATTR_ENTITY_ID] == entity_id assert acc.char_current_state.value == HK_DOOR_OPENING assert acc.char_target_state.value == HK_DOOR_OPEN assert len(events) == 3 assert events[-1].data[ATTR_VALUE] is None hass.states.async_set(entity_id, STATE_OPEN) await hass.async_block_till_done() acc.char_target_state.client_update_value(0) await hass.async_block_till_done() assert acc.char_current_state.value == HK_DOOR_OPEN assert acc.char_target_state.value == HK_DOOR_OPEN assert len(events) == 4 assert events[-1].data[ATTR_VALUE] is None
async def test_reproducing_states(hass, caplog): """Test reproducing Fan states.""" hass.states.async_set("fan.entity_off", "off", {}) hass.states.async_set("fan.entity_on", "on", {}) hass.states.async_set("fan.entity_speed", "on", {"percentage": 100}) hass.states.async_set("fan.entity_oscillating", "on", {"oscillating": True}) hass.states.async_set("fan.entity_direction", "on", {"direction": "forward"}) turn_on_calls = async_mock_service(hass, "fan", "turn_on") turn_off_calls = async_mock_service(hass, "fan", "turn_off") set_direction_calls = async_mock_service(hass, "fan", "set_direction") oscillate_calls = async_mock_service(hass, "fan", "oscillate") set_percentage_calls = async_mock_service(hass, "fan", "set_percentage") # These calls should do nothing as entities already in desired state await async_reproduce_state( hass, [ State("fan.entity_off", "off"), State("fan.entity_on", "on"), State("fan.entity_speed", "on", {"percentage": 100}), State("fan.entity_oscillating", "on", {"oscillating": True}), State("fan.entity_direction", "on", {"direction": "forward"}), ], ) assert len(turn_on_calls) == 0 assert len(turn_off_calls) == 0 assert len(set_direction_calls) == 0 assert len(oscillate_calls) == 0 # Test invalid state is handled await async_reproduce_state(hass, [State("fan.entity_off", "not_supported")]) assert "not_supported" in caplog.text assert len(turn_on_calls) == 0 assert len(turn_off_calls) == 0 assert len(set_direction_calls) == 0 assert len(oscillate_calls) == 0 assert len(set_percentage_calls) == 0 # Make sure correct services are called await async_reproduce_state( hass, [ State("fan.entity_on", "off"), State("fan.entity_off", "on"), State("fan.entity_speed", "on", {"percentage": 25}), State("fan.entity_oscillating", "on", {"oscillating": False}), State("fan.entity_direction", "on", {"direction": "reverse"}), # Should not raise State("fan.non_existing", "on"), ], ) assert len(turn_on_calls) == 1 assert turn_on_calls[0].domain == "fan" assert turn_on_calls[0].data == {"entity_id": "fan.entity_off"} assert len(set_direction_calls) == 1 assert set_direction_calls[0].domain == "fan" assert set_direction_calls[0].data == { "entity_id": "fan.entity_direction", "direction": "reverse", } assert len(oscillate_calls) == 1 assert oscillate_calls[0].domain == "fan" assert oscillate_calls[0].data == { "entity_id": "fan.entity_oscillating", "oscillating": False, } assert len(set_percentage_calls) == 1 assert set_percentage_calls[0].domain == "fan" assert set_percentage_calls[0].data == { "entity_id": "fan.entity_speed", "percentage": 25, } assert len(turn_off_calls) == 1 assert turn_off_calls[0].domain == "fan" assert turn_off_calls[0].data == {"entity_id": "fan.entity_on"}
async def test_windowcovering_cover_set_tilt(hass, hk_driver, events): """Test if accessory and HA update slat tilt accordingly.""" entity_id = "cover.window" hass.states.async_set(entity_id, STATE_UNKNOWN, {ATTR_SUPPORTED_FEATURES: SUPPORT_SET_TILT_POSITION}) await hass.async_block_till_done() acc = WindowCovering(hass, hk_driver, "Cover", entity_id, 2, None) await acc.run() await hass.async_block_till_done() assert acc.aid == 2 assert acc.category == 14 # CATEGORY_WINDOW_COVERING assert acc.char_current_tilt.value == 0 assert acc.char_target_tilt.value == 0 hass.states.async_set(entity_id, STATE_UNKNOWN, {ATTR_CURRENT_TILT_POSITION: None}) await hass.async_block_till_done() assert acc.char_current_tilt.value == 0 assert acc.char_target_tilt.value == 0 hass.states.async_set(entity_id, STATE_UNKNOWN, {ATTR_CURRENT_TILT_POSITION: 100}) await hass.async_block_till_done() assert acc.char_current_tilt.value == 90 assert acc.char_target_tilt.value == 90 hass.states.async_set(entity_id, STATE_UNKNOWN, {ATTR_CURRENT_TILT_POSITION: 50}) await hass.async_block_till_done() assert acc.char_current_tilt.value == 0 assert acc.char_target_tilt.value == 0 hass.states.async_set(entity_id, STATE_UNKNOWN, {ATTR_CURRENT_TILT_POSITION: 0}) await hass.async_block_till_done() assert acc.char_current_tilt.value == -90 assert acc.char_target_tilt.value == -90 # set from HomeKit call_set_tilt_position = async_mock_service( hass, DOMAIN, SERVICE_SET_COVER_TILT_POSITION) # HomeKit sets tilts between -90 and 90 (degrees), whereas # Homeassistant expects a % between 0 and 100. Keep that in mind # when comparing acc.char_target_tilt.client_update_value(90) await hass.async_block_till_done() assert call_set_tilt_position[0] assert call_set_tilt_position[0].data[ATTR_ENTITY_ID] == entity_id assert call_set_tilt_position[0].data[ATTR_TILT_POSITION] == 100 assert acc.char_current_tilt.value == -90 assert acc.char_target_tilt.value == 90 assert len(events) == 1 assert events[-1].data[ATTR_VALUE] == 100 acc.char_target_tilt.client_update_value(45) await hass.async_block_till_done() assert call_set_tilt_position[1] assert call_set_tilt_position[1].data[ATTR_ENTITY_ID] == entity_id assert call_set_tilt_position[1].data[ATTR_TILT_POSITION] == 75 assert acc.char_current_tilt.value == -90 assert acc.char_target_tilt.value == 45 assert len(events) == 2 assert events[-1].data[ATTR_VALUE] == 75
async def test_windowcovering_open_close(hass, hk_driver, events): """Test if accessory and HA are updated accordingly.""" entity_id = "cover.window" hass.states.async_set(entity_id, STATE_UNKNOWN, {ATTR_SUPPORTED_FEATURES: 0}) acc = WindowCoveringBasic(hass, hk_driver, "Cover", entity_id, 2, None) await acc.run() await hass.async_block_till_done() assert acc.aid == 2 assert acc.category == 14 # WindowCovering assert acc.char_current_position.value == 0 assert acc.char_target_position.value == 0 assert acc.char_position_state.value == 2 hass.states.async_set(entity_id, STATE_UNKNOWN) await hass.async_block_till_done() assert acc.char_current_position.value == 0 assert acc.char_target_position.value == 0 assert acc.char_position_state.value == 2 hass.states.async_set(entity_id, STATE_OPENING) await hass.async_block_till_done() assert acc.char_current_position.value == 0 assert acc.char_target_position.value == 0 assert acc.char_position_state.value == 1 hass.states.async_set(entity_id, STATE_OPEN) await hass.async_block_till_done() assert acc.char_current_position.value == 100 assert acc.char_target_position.value == 100 assert acc.char_position_state.value == 2 hass.states.async_set(entity_id, STATE_CLOSING) await hass.async_block_till_done() assert acc.char_current_position.value == 100 assert acc.char_target_position.value == 100 assert acc.char_position_state.value == 0 hass.states.async_set(entity_id, STATE_CLOSED) await hass.async_block_till_done() assert acc.char_current_position.value == 0 assert acc.char_target_position.value == 0 assert acc.char_position_state.value == 2 # Set from HomeKit call_close_cover = async_mock_service(hass, DOMAIN, "close_cover") call_open_cover = async_mock_service(hass, DOMAIN, "open_cover") acc.char_target_position.client_update_value(25) await hass.async_block_till_done() assert call_close_cover assert call_close_cover[0].data[ATTR_ENTITY_ID] == entity_id assert acc.char_current_position.value == 0 assert acc.char_target_position.value == 0 assert acc.char_position_state.value == 2 assert len(events) == 1 assert events[-1].data[ATTR_VALUE] is None acc.char_target_position.client_update_value(90) await hass.async_block_till_done() assert call_open_cover[0] assert call_open_cover[0].data[ATTR_ENTITY_ID] == entity_id assert acc.char_current_position.value == 100 assert acc.char_target_position.value == 100 assert acc.char_position_state.value == 2 assert len(events) == 2 assert events[-1].data[ATTR_VALUE] is None acc.char_target_position.client_update_value(55) await hass.async_block_till_done() assert call_open_cover[1] assert call_open_cover[1].data[ATTR_ENTITY_ID] == entity_id assert acc.char_current_position.value == 100 assert acc.char_target_position.value == 100 assert acc.char_position_state.value == 2 assert len(events) == 3 assert events[-1].data[ATTR_VALUE] is None
async def test_light_set_brightness_and_color_temp(hass, hk_driver, cls, events): """Test light with all chars in one go.""" entity_id = "light.demo" hass.states.async_set( entity_id, STATE_ON, { ATTR_SUPPORTED_FEATURES: SUPPORT_BRIGHTNESS | SUPPORT_COLOR_TEMP, ATTR_BRIGHTNESS: 255, }, ) await hass.async_block_till_done() acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None) hk_driver.add_accessory(acc) # Initial value can be anything but 0. If it is 0, it might cause HomeKit to set the # brightness to 100 when turning on a light on a freshly booted up server. assert acc.char_brightness.value != 0 char_on_iid = acc.char_on.to_HAP()[HAP_REPR_IID] char_brightness_iid = acc.char_brightness.to_HAP()[HAP_REPR_IID] char_color_temperature_iid = acc.char_color_temperature.to_HAP( )[HAP_REPR_IID] await acc.run_handler() await hass.async_block_till_done() assert acc.char_brightness.value == 100 hass.states.async_set(entity_id, STATE_ON, {ATTR_BRIGHTNESS: 102}) await hass.async_block_till_done() assert acc.char_brightness.value == 40 hass.states.async_set(entity_id, STATE_ON, {ATTR_COLOR_TEMP: (224.14)}) await hass.async_block_till_done() assert acc.char_color_temperature.value == 224 # Set from HomeKit call_turn_on = async_mock_service(hass, DOMAIN, "turn_on") hk_driver.set_characteristics( { HAP_REPR_CHARS: [ { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1 }, { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_brightness_iid, HAP_REPR_VALUE: 20, }, { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_color_temperature_iid, HAP_REPR_VALUE: 250, }, ] }, "mock_addr", ) await hass.async_block_till_done() assert call_turn_on[0] assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id assert call_turn_on[0].data[ATTR_BRIGHTNESS_PCT] == 20 assert call_turn_on[0].data[ATTR_COLOR_TEMP] == 250 assert len(events) == 1 assert ( events[-1].data[ATTR_VALUE] == f"Set state to 1, brightness at 20{PERCENTAGE}, color temperature at 250" )
async def test_windowcovering_set_cover_position(hass, hk_driver, events): """Test if accessory and HA are updated accordingly.""" entity_id = "cover.window" hass.states.async_set(entity_id, STATE_UNKNOWN, {ATTR_SUPPORTED_FEATURES: SUPPORT_SET_POSITION}) await hass.async_block_till_done() acc = WindowCovering(hass, hk_driver, "Cover", entity_id, 2, None) await acc.run() await hass.async_block_till_done() assert acc.aid == 2 assert acc.category == 14 # WindowCovering assert acc.char_current_position.value == 0 assert acc.char_target_position.value == 0 hass.states.async_set( entity_id, STATE_UNKNOWN, { ATTR_SUPPORTED_FEATURES: SUPPORT_SET_POSITION, ATTR_CURRENT_POSITION: None }, ) await hass.async_block_till_done() assert acc.char_current_position.value == 0 assert acc.char_target_position.value == 0 assert acc.char_position_state.value == 2 hass.states.async_set( entity_id, STATE_OPENING, { ATTR_SUPPORTED_FEATURES: SUPPORT_SET_POSITION, ATTR_CURRENT_POSITION: 60 }, ) await hass.async_block_till_done() assert acc.char_current_position.value == 60 assert acc.char_target_position.value == 0 assert acc.char_position_state.value == 1 hass.states.async_set( entity_id, STATE_OPENING, { ATTR_SUPPORTED_FEATURES: SUPPORT_SET_POSITION, ATTR_CURRENT_POSITION: 70.0 }, ) await hass.async_block_till_done() assert acc.char_current_position.value == 70 assert acc.char_target_position.value == 0 assert acc.char_position_state.value == 1 hass.states.async_set( entity_id, STATE_CLOSING, { ATTR_SUPPORTED_FEATURES: SUPPORT_SET_POSITION, ATTR_CURRENT_POSITION: 50 }, ) await hass.async_block_till_done() assert acc.char_current_position.value == 50 assert acc.char_target_position.value == 0 assert acc.char_position_state.value == 0 hass.states.async_set( entity_id, STATE_OPEN, { ATTR_SUPPORTED_FEATURES: SUPPORT_SET_POSITION, ATTR_CURRENT_POSITION: 50 }, ) await hass.async_block_till_done() assert acc.char_current_position.value == 50 assert acc.char_target_position.value == 50 assert acc.char_position_state.value == 2 # Set from HomeKit call_set_cover_position = async_mock_service(hass, DOMAIN, "set_cover_position") acc.char_target_position.client_update_value(25) await hass.async_block_till_done() assert call_set_cover_position[0] assert call_set_cover_position[0].data[ATTR_ENTITY_ID] == entity_id assert call_set_cover_position[0].data[ATTR_POSITION] == 25 assert acc.char_current_position.value == 50 assert acc.char_target_position.value == 25 assert len(events) == 1 assert events[-1].data[ATTR_VALUE] == 25 acc.char_target_position.client_update_value(75) await hass.async_block_till_done() assert call_set_cover_position[1] assert call_set_cover_position[1].data[ATTR_ENTITY_ID] == entity_id assert call_set_cover_position[1].data[ATTR_POSITION] == 75 assert acc.char_current_position.value == 50 assert acc.char_target_position.value == 75 assert len(events) == 2 assert events[-1].data[ATTR_VALUE] == 75
async def test_light_basic(hass, hk_driver, cls, events): """Test light with char state.""" entity_id = "light.demo" hass.states.async_set(entity_id, STATE_ON, {ATTR_SUPPORTED_FEATURES: 0}) await hass.async_block_till_done() acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None) hk_driver.add_accessory(acc) assert acc.aid == 1 assert acc.category == 5 # Lightbulb assert acc.char_on.value await acc.run_handler() await hass.async_block_till_done() assert acc.char_on.value == 1 hass.states.async_set(entity_id, STATE_OFF, {ATTR_SUPPORTED_FEATURES: 0}) await hass.async_block_till_done() assert acc.char_on.value == 0 hass.states.async_set(entity_id, STATE_UNKNOWN) await hass.async_block_till_done() assert acc.char_on.value == 0 hass.states.async_remove(entity_id) await hass.async_block_till_done() assert acc.char_on.value == 0 # Set from HomeKit call_turn_on = async_mock_service(hass, DOMAIN, "turn_on") call_turn_off = async_mock_service(hass, DOMAIN, "turn_off") char_on_iid = acc.char_on.to_HAP()[HAP_REPR_IID] hk_driver.set_characteristics( { HAP_REPR_CHARS: [{ HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1 }] }, "mock_addr", ) await hass.async_add_executor_job(acc.char_on.client_update_value, 1) await hass.async_block_till_done() assert call_turn_on assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id assert len(events) == 1 assert events[-1].data[ATTR_VALUE] == "Set state to 1" hass.states.async_set(entity_id, STATE_ON) await hass.async_block_till_done() hk_driver.set_characteristics( { HAP_REPR_CHARS: [{ HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 0 }] }, "mock_addr", ) await hass.async_block_till_done() assert call_turn_off assert call_turn_off[0].data[ATTR_ENTITY_ID] == entity_id assert len(events) == 2 assert events[-1].data[ATTR_VALUE] == "Set state to 0"
async def test_light_brightness(hass, hk_driver, cls, events): """Test light with brightness.""" entity_id = "light.demo" hass.states.async_set( entity_id, STATE_ON, { ATTR_SUPPORTED_FEATURES: SUPPORT_BRIGHTNESS, ATTR_BRIGHTNESS: 255 }, ) await hass.async_block_till_done() acc = cls.light(hass, hk_driver, "Light", entity_id, 1, None) hk_driver.add_accessory(acc) # Initial value can be anything but 0. If it is 0, it might cause HomeKit to set the # brightness to 100 when turning on a light on a freshly booted up server. assert acc.char_brightness.value != 0 char_on_iid = acc.char_on.to_HAP()[HAP_REPR_IID] char_brightness_iid = acc.char_brightness.to_HAP()[HAP_REPR_IID] await acc.run_handler() await hass.async_block_till_done() assert acc.char_brightness.value == 100 hass.states.async_set(entity_id, STATE_ON, {ATTR_BRIGHTNESS: 102}) await hass.async_block_till_done() assert acc.char_brightness.value == 40 # Set from HomeKit call_turn_on = async_mock_service(hass, DOMAIN, "turn_on") call_turn_off = async_mock_service(hass, DOMAIN, "turn_off") hk_driver.set_characteristics( { HAP_REPR_CHARS: [ { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1 }, { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_brightness_iid, HAP_REPR_VALUE: 20, }, ] }, "mock_addr", ) await hass.async_block_till_done() assert call_turn_on[0] assert call_turn_on[0].data[ATTR_ENTITY_ID] == entity_id assert call_turn_on[0].data[ATTR_BRIGHTNESS_PCT] == 20 assert len(events) == 1 assert (events[-1].data[ATTR_VALUE] == f"Set state to 1, brightness at 20{PERCENTAGE}") hk_driver.set_characteristics( { HAP_REPR_CHARS: [ { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1 }, { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_brightness_iid, HAP_REPR_VALUE: 40, }, ] }, "mock_addr", ) await hass.async_block_till_done() assert call_turn_on[1] assert call_turn_on[1].data[ATTR_ENTITY_ID] == entity_id assert call_turn_on[1].data[ATTR_BRIGHTNESS_PCT] == 40 assert len(events) == 2 assert (events[-1].data[ATTR_VALUE] == f"Set state to 1, brightness at 40{PERCENTAGE}") hk_driver.set_characteristics( { HAP_REPR_CHARS: [ { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_on_iid, HAP_REPR_VALUE: 1 }, { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_brightness_iid, HAP_REPR_VALUE: 0, }, ] }, "mock_addr", ) await hass.async_block_till_done() assert call_turn_off assert call_turn_off[0].data[ATTR_ENTITY_ID] == entity_id assert len(events) == 3 assert events[-1].data[ ATTR_VALUE] == f"Set state to 0, brightness at 0{PERCENTAGE}" # 0 is a special case for homekit, see "Handle Brightness" # in update_state hass.states.async_set(entity_id, STATE_ON, {ATTR_BRIGHTNESS: 0}) await hass.async_block_till_done() assert acc.char_brightness.value == 1 hass.states.async_set(entity_id, STATE_ON, {ATTR_BRIGHTNESS: 255}) await hass.async_block_till_done() assert acc.char_brightness.value == 100 hass.states.async_set(entity_id, STATE_ON, {ATTR_BRIGHTNESS: 0}) await hass.async_block_till_done() assert acc.char_brightness.value == 1 # Ensure floats are handled hass.states.async_set(entity_id, STATE_ON, {ATTR_BRIGHTNESS: 55.66}) await hass.async_block_till_done() assert acc.char_brightness.value == 22 hass.states.async_set(entity_id, STATE_ON, {ATTR_BRIGHTNESS: 108.4}) await hass.async_block_till_done() assert acc.char_brightness.value == 43 hass.states.async_set(entity_id, STATE_ON, {ATTR_BRIGHTNESS: 0.0}) await hass.async_block_till_done() assert acc.char_brightness.value == 1
async def test_fan_oscillate(opp, hk_driver, events): """Test fan with oscillate.""" entity_id = "fan.demo" opp.states.async_set( entity_id, STATE_ON, {ATTR_SUPPORTED_FEATURES: SUPPORT_OSCILLATE, ATTR_OSCILLATING: False}, ) await opp.async_block_till_done() acc = Fan(opp, hk_driver, "Fan", entity_id, 1, None) hk_driver.add_accessory(acc) assert acc.char_swing.value == 0 await acc.run() await opp.async_block_till_done() assert acc.char_swing.value == 0 opp.states.async_set(entity_id, STATE_ON, {ATTR_OSCILLATING: True}) await opp.async_block_till_done() assert acc.char_swing.value == 1 # Set from HomeKit call_oscillate = async_mock_service(opp, DOMAIN, "oscillate") char_swing_iid = acc.char_swing.to_HAP()[HAP_REPR_IID] hk_driver.set_characteristics( { HAP_REPR_CHARS: [ { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_swing_iid, HAP_REPR_VALUE: 0, }, ] }, "mock_addr", ) await opp.async_add_executor_job(acc.char_swing.client_update_value, 0) await opp.async_block_till_done() assert call_oscillate[0] assert call_oscillate[0].data[ATTR_ENTITY_ID] == entity_id assert call_oscillate[0].data[ATTR_OSCILLATING] is False assert len(events) == 1 assert events[-1].data[ATTR_VALUE] is False hk_driver.set_characteristics( { HAP_REPR_CHARS: [ { HAP_REPR_AID: acc.aid, HAP_REPR_IID: char_swing_iid, HAP_REPR_VALUE: 1, }, ] }, "mock_addr", ) await opp.async_add_executor_job(acc.char_swing.client_update_value, 1) await opp.async_block_till_done() assert call_oscillate[1] assert call_oscillate[1].data[ATTR_ENTITY_ID] == entity_id assert call_oscillate[1].data[ATTR_OSCILLATING] is True assert len(events) == 2 assert events[-1].data[ATTR_VALUE] is True
async def test_action(hass, calls): """Test for turn_on and turn_off actions.""" platform = getattr(hass.components, f"test.{DOMAIN}") platform.init() assert await async_setup_component(hass, DOMAIN, {DOMAIN: { CONF_PLATFORM: "test" }}) await hass.async_block_till_done() ent1 = platform.ENTITIES[0] assert await async_setup_component( hass, automation.DOMAIN, { automation.DOMAIN: [ { "trigger": { "platform": "event", "event_type": "test_off" }, "action": { "domain": DOMAIN, "device_id": "", "entity_id": ent1.entity_id, "type": "turn_off", }, }, { "trigger": { "platform": "event", "event_type": "test_on" }, "action": { "domain": DOMAIN, "device_id": "", "entity_id": ent1.entity_id, "type": "turn_on", }, }, { "trigger": { "platform": "event", "event_type": "test_toggle" }, "action": { "domain": DOMAIN, "device_id": "", "entity_id": ent1.entity_id, "type": "toggle", }, }, { "trigger": { "platform": "event", "event_type": "test_flash_short" }, "action": { "domain": DOMAIN, "device_id": "", "entity_id": ent1.entity_id, "type": "flash", }, }, { "trigger": { "platform": "event", "event_type": "test_flash_long" }, "action": { "domain": DOMAIN, "device_id": "", "entity_id": ent1.entity_id, "type": "flash", "flash": "long", }, }, { "trigger": { "platform": "event", "event_type": "test_brightness_increase", }, "action": { "domain": DOMAIN, "device_id": "", "entity_id": ent1.entity_id, "type": "brightness_increase", }, }, { "trigger": { "platform": "event", "event_type": "test_brightness_decrease", }, "action": { "domain": DOMAIN, "device_id": "", "entity_id": ent1.entity_id, "type": "brightness_decrease", }, }, { "trigger": { "platform": "event", "event_type": "test_brightness" }, "action": { "domain": DOMAIN, "device_id": "", "entity_id": ent1.entity_id, "type": "turn_on", "brightness_pct": 75, }, }, ] }, ) await hass.async_block_till_done() assert hass.states.get(ent1.entity_id).state == STATE_ON assert len(calls) == 0 hass.bus.async_fire("test_off") await hass.async_block_till_done() assert hass.states.get(ent1.entity_id).state == STATE_OFF hass.bus.async_fire("test_off") await hass.async_block_till_done() assert hass.states.get(ent1.entity_id).state == STATE_OFF hass.bus.async_fire("test_on") await hass.async_block_till_done() assert hass.states.get(ent1.entity_id).state == STATE_ON hass.bus.async_fire("test_on") await hass.async_block_till_done() assert hass.states.get(ent1.entity_id).state == STATE_ON hass.bus.async_fire("test_toggle") await hass.async_block_till_done() assert hass.states.get(ent1.entity_id).state == STATE_OFF hass.bus.async_fire("test_toggle") await hass.async_block_till_done() assert hass.states.get(ent1.entity_id).state == STATE_ON hass.bus.async_fire("test_toggle") await hass.async_block_till_done() assert hass.states.get(ent1.entity_id).state == STATE_OFF hass.bus.async_fire("test_flash_short") await hass.async_block_till_done() assert hass.states.get(ent1.entity_id).state == STATE_ON hass.bus.async_fire("test_toggle") await hass.async_block_till_done() assert hass.states.get(ent1.entity_id).state == STATE_OFF hass.bus.async_fire("test_flash_long") await hass.async_block_till_done() assert hass.states.get(ent1.entity_id).state == STATE_ON turn_on_calls = async_mock_service(hass, DOMAIN, "turn_on") hass.bus.async_fire("test_brightness_increase") await hass.async_block_till_done() assert len(turn_on_calls) == 1 assert turn_on_calls[0].data["entity_id"] == ent1.entity_id assert turn_on_calls[0].data["brightness_step_pct"] == 10 hass.bus.async_fire("test_brightness_decrease") await hass.async_block_till_done() assert len(turn_on_calls) == 2 assert turn_on_calls[1].data["entity_id"] == ent1.entity_id assert turn_on_calls[1].data["brightness_step_pct"] == -10 hass.bus.async_fire("test_brightness") await hass.async_block_till_done() assert len(turn_on_calls) == 3 assert turn_on_calls[2].data["entity_id"] == ent1.entity_id assert turn_on_calls[2].data["brightness_pct"] == 75 hass.bus.async_fire("test_on") await hass.async_block_till_done() assert len(turn_on_calls) == 4 assert turn_on_calls[3].data["entity_id"] == ent1.entity_id assert "brightness_pct" not in turn_on_calls[3].data hass.bus.async_fire("test_flash_short") await hass.async_block_till_done() assert len(turn_on_calls) == 5 assert turn_on_calls[4].data["entity_id"] == ent1.entity_id assert turn_on_calls[4].data["flash"] == FLASH_SHORT hass.bus.async_fire("test_flash_long") await hass.async_block_till_done() assert len(turn_on_calls) == 6 assert turn_on_calls[5].data["entity_id"] == ent1.entity_id assert turn_on_calls[5].data["flash"] == FLASH_LONG