async def test_if_fires_on_entity_change_with_for_attribute_change(hass,
                                                                   calls):
    """Test for firing on entity change with for and attribute change."""
    assert await async_setup_component(hass, automation.DOMAIN, {
        automation.DOMAIN: {
            'trigger': {
                'platform': 'numeric_state',
                'entity_id': 'test.entity',
                'above': 8,
                'below': 12,
                'for': {
                    'seconds': 5
                },
            },
            'action': {
                'service': 'test.automation'
            }
        }
    })

    utcnow = dt_util.utcnow()
    with patch('homeassistant.core.dt_util.utcnow') as mock_utcnow:
        mock_utcnow.return_value = utcnow
        hass.states.async_set('test.entity', 9)
        await hass.async_block_till_done()
        mock_utcnow.return_value += timedelta(seconds=4)
        async_fire_time_changed(hass, mock_utcnow.return_value)
        hass.states.async_set('test.entity', 9,
                              attributes={"mock_attr": "attr_change"})
        await hass.async_block_till_done()
        assert 0 == len(calls)
        mock_utcnow.return_value += timedelta(seconds=4)
        async_fire_time_changed(hass, mock_utcnow.return_value)
        await hass.async_block_till_done()
        assert 1 == len(calls)
async def test_trigger_with_specific_trigger_time(hass):
    """Test disarm after trigger."""
    assert await async_setup_component(
        hass, alarm_control_panel.DOMAIN,
        {'alarm_control_panel': {
            'platform': 'manual',
            'name': 'test',
            'disarmed': {
                'trigger_time': 5
            },
            'pending_time': 0,
            'disarm_after_trigger': True
        }})

    entity_id = 'alarm_control_panel.test'

    assert STATE_ALARM_DISARMED == \
        hass.states.get(entity_id).state

    common.async_alarm_trigger(hass, entity_id=entity_id)
    await hass.async_block_till_done()

    assert STATE_ALARM_TRIGGERED == \
        hass.states.get(entity_id).state

    future = dt_util.utcnow() + timedelta(seconds=5)
    with patch(('homeassistant.components.manual.alarm_control_panel.'
                'dt_util.utcnow'), return_value=future):
        async_fire_time_changed(hass, future)
        await hass.async_block_till_done()

    assert STATE_ALARM_DISARMED == \
        hass.states.get(entity_id).state
async def test_arm_home_with_pending(hass):
    """Test arm home method."""
    assert await async_setup_component(
        hass, alarm_control_panel.DOMAIN,
        {'alarm_control_panel': {
            'platform': 'manual',
            'name': 'test',
            'code': CODE,
            'pending_time': 1,
            'disarm_after_trigger': False
        }})

    entity_id = 'alarm_control_panel.test'

    assert STATE_ALARM_DISARMED == \
        hass.states.get(entity_id).state

    common.async_alarm_arm_home(hass, CODE, entity_id)
    await hass.async_block_till_done()

    assert STATE_ALARM_PENDING == \
        hass.states.get(entity_id).state

    state = hass.states.get(entity_id)
    assert state.attributes['post_pending_state'] == STATE_ALARM_ARMED_HOME

    future = dt_util.utcnow() + timedelta(seconds=1)
    with patch(('homeassistant.components.manual.alarm_control_panel.'
                'dt_util.utcnow'), return_value=future):
        async_fire_time_changed(hass, future)
        await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state.state == STATE_ALARM_ARMED_HOME
Beispiel #4
0
async def test_if_not_fires_on_entity_change_with_for(hass, calls):
    """Test for not firing on entity change with for."""
    assert await async_setup_component(hass, automation.DOMAIN, {
        automation.DOMAIN: {
            'trigger': {
                'platform': 'state',
                'entity_id': 'test.entity',
                'to': 'world',
                'for': {
                    'seconds': 5
                },
            },
            'action': {
                'service': 'test.automation'
            }
        }
    })

    hass.states.async_set('test.entity', 'world')
    await hass.async_block_till_done()
    hass.states.async_set('test.entity', 'not_world')
    await hass.async_block_till_done()
    async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10))
    await hass.async_block_till_done()
    assert 0 == len(calls)
Beispiel #5
0
async def test_if_fires_on_entity_change_with_for_multiple_force_update(hass,
                                                                        calls):
    """Test for firing on entity change with for and force update."""
    assert await async_setup_component(hass, automation.DOMAIN, {
        automation.DOMAIN: {
            'trigger': {
                'platform': 'state',
                'entity_id': 'test.force_entity',
                'to': 'world',
                'for': {
                    'seconds': 5
                },
            },
            'action': {
                'service': 'test.automation'
            }
        }
    })

    utcnow = dt_util.utcnow()
    with patch('homeassistant.core.dt_util.utcnow') as mock_utcnow:
        mock_utcnow.return_value = utcnow
        hass.states.async_set('test.force_entity', 'world', None, True)
        await hass.async_block_till_done()
        for _ in range(0, 4):
            mock_utcnow.return_value += timedelta(seconds=1)
            async_fire_time_changed(hass, mock_utcnow.return_value)
            hass.states.async_set('test.force_entity', 'world', None, True)
            await hass.async_block_till_done()
        assert 0 == len(calls)
        mock_utcnow.return_value += timedelta(seconds=4)
        async_fire_time_changed(hass, mock_utcnow.return_value)
        await hass.async_block_till_done()
        assert 1 == len(calls)
async def test_trigger_no_pending(hass):
    """Test triggering when no pending submitted method."""
    assert await async_setup_component(
        hass, alarm_control_panel.DOMAIN,
        {'alarm_control_panel': {
            'platform': 'manual',
            'name': 'test',
            'trigger_time': 1,
            'disarm_after_trigger': False
        }})

    entity_id = 'alarm_control_panel.test'

    assert STATE_ALARM_DISARMED == \
        hass.states.get(entity_id).state

    common.async_alarm_trigger(hass, entity_id=entity_id)
    await hass.async_block_till_done()

    assert STATE_ALARM_PENDING == \
        hass.states.get(entity_id).state

    future = dt_util.utcnow() + timedelta(seconds=60)
    with patch(('homeassistant.components.manual.alarm_control_panel.'
                'dt_util.utcnow'), return_value=future):
        async_fire_time_changed(hass, future)
        await hass.async_block_till_done()

    assert STATE_ALARM_TRIGGERED == \
        hass.states.get(entity_id).state
async def test_armed_night_with_specific_pending(hass):
    """Test arm home method."""
    assert await async_setup_component(
        hass, alarm_control_panel.DOMAIN,
        {'alarm_control_panel': {
            'platform': 'manual',
            'name': 'test',
            'pending_time': 10,
            'armed_night': {
                'pending_time': 2
            }
        }})

    entity_id = 'alarm_control_panel.test'

    common.async_alarm_arm_night(hass)
    await hass.async_block_till_done()

    assert STATE_ALARM_PENDING == \
        hass.states.get(entity_id).state

    future = dt_util.utcnow() + timedelta(seconds=2)
    with patch(('homeassistant.components.manual.alarm_control_panel.'
                'dt_util.utcnow'), return_value=future):
        async_fire_time_changed(hass, future)
        await hass.async_block_till_done()

    assert STATE_ALARM_ARMED_NIGHT == \
        hass.states.get(entity_id).state
async def test_if_fires_when_hour_matches(hass, calls):
    """Test for firing if hour is matching."""
    assert await async_setup_component(hass, automation.DOMAIN, {
        automation.DOMAIN: {
            'trigger': {
                'platform': 'time_pattern',
                'hours': 0,
                'minutes': '*',
                'seconds': '*',
            },
            'action': {
                'service': 'test.automation'
            }
        }
    })

    async_fire_time_changed(hass, dt_util.utcnow().replace(hour=0))
    await hass.async_block_till_done()
    assert 1 == len(calls)

    await common.async_turn_off(hass)
    await hass.async_block_till_done()

    async_fire_time_changed(hass, dt_util.utcnow().replace(hour=0))
    await hass.async_block_till_done()
    assert 1 == len(calls)
Beispiel #9
0
async def test_stop_covers(hass, setup_comp):
    """Test stop cover function."""
    await hass.services.async_call(
        DOMAIN, SERVICE_OPEN_COVER,
        {ATTR_ENTITY_ID: COVER_GROUP}, blocking=True)
    future = dt_util.utcnow() + timedelta(seconds=1)
    async_fire_time_changed(hass, future)
    await hass.async_block_till_done()

    await hass.services.async_call(
        DOMAIN, SERVICE_STOP_COVER,
        {ATTR_ENTITY_ID: COVER_GROUP}, blocking=True)
    future = dt_util.utcnow() + timedelta(seconds=1)
    async_fire_time_changed(hass, future)
    await hass.async_block_till_done()

    state = hass.states.get(COVER_GROUP)
    assert state.state == STATE_OPEN
    assert state.attributes.get(ATTR_CURRENT_POSITION) == 100

    assert hass.states.get(DEMO_COVER).state == STATE_OPEN
    assert hass.states.get(DEMO_COVER_POS) \
        .attributes.get(ATTR_CURRENT_POSITION) == 20
    assert hass.states.get(DEMO_COVER_TILT) \
        .attributes.get(ATTR_CURRENT_POSITION) == 80
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
Beispiel #11
0
async def test_update_stale(hass):
    """Test stalled update."""
    scanner = get_component(hass, 'device_tracker.test').SCANNER
    scanner.reset()
    scanner.come_home('DEV1')

    register_time = datetime(2015, 9, 15, 23, tzinfo=dt_util.UTC)
    scan_time = datetime(2015, 9, 15, 23, 1, tzinfo=dt_util.UTC)

    with patch('homeassistant.components.device_tracker.dt_util.utcnow',
               return_value=register_time):
        with assert_setup_component(1, device_tracker.DOMAIN):
            assert await async_setup_component(hass, device_tracker.DOMAIN, {
                device_tracker.DOMAIN: {
                    CONF_PLATFORM: 'test',
                    device_tracker.CONF_CONSIDER_HOME: 59,
                }})
            await hass.async_block_till_done()

    assert STATE_HOME == \
        hass.states.get('device_tracker.dev1').state

    scanner.leave_home('DEV1')

    with patch('homeassistant.components.device_tracker.dt_util.utcnow',
               return_value=scan_time):
        async_fire_time_changed(hass, scan_time)
        await hass.async_block_till_done()

    assert STATE_NOT_HOME == \
        hass.states.get('device_tracker.dev1').state
Beispiel #12
0
async def test_sunset_trigger_with_offset(hass, calls):
    """Test the sunset trigger with offset."""
    now = datetime(2015, 9, 15, 23, tzinfo=dt_util.UTC)
    trigger_time = datetime(2015, 9, 16, 2, 30, tzinfo=dt_util.UTC)

    with patch('homeassistant.util.dt.utcnow',
               return_value=now):
        await async_setup_component(hass, automation.DOMAIN, {
            automation.DOMAIN: {
                'trigger': {
                    'platform': 'sun',
                    'event': SUN_EVENT_SUNSET,
                    'offset': '0:30:00'
                },
                'action': {
                    'service': 'test.automation',
                    'data_template': {
                        'some':
                        '{{ trigger.%s }}' % '}} - {{ trigger.'.join((
                            'platform', 'event', 'offset'))
                    },
                }
            }
        })

    async_fire_time_changed(hass, trigger_time)
    await hass.async_block_till_done()
    assert 1 == len(calls)
    assert 'sun - sunset - 0:30:00' == calls[0].data['some']
Beispiel #13
0
async def test_sunset_trigger(hass, calls):
    """Test the sunset trigger."""
    now = datetime(2015, 9, 15, 23, tzinfo=dt_util.UTC)
    trigger_time = datetime(2015, 9, 16, 2, tzinfo=dt_util.UTC)

    with patch('homeassistant.util.dt.utcnow',
               return_value=now):
        await async_setup_component(hass, automation.DOMAIN, {
            automation.DOMAIN: {
                'trigger': {
                    'platform': 'sun',
                    'event': SUN_EVENT_SUNSET,
                },
                'action': {
                    'service': 'test.automation',
                }
            }
        })

    await common.async_turn_off(hass)
    await hass.async_block_till_done()

    async_fire_time_changed(hass, trigger_time)
    await hass.async_block_till_done()
    assert 0 == len(calls)

    with patch('homeassistant.util.dt.utcnow',
               return_value=now):
        await common.async_turn_on(hass)
        await hass.async_block_till_done()

    async_fire_time_changed(hass, trigger_time)
    await hass.async_block_till_done()
    assert 1 == len(calls)
async def test_saving_and_loading(hass):
    """Test that we're saving and loading correctly."""
    loader.set_component(
        hass, 'test',
        MockModule('test', async_setup_entry=lambda *args: mock_coro(True)))

    class TestFlow(config_entries.ConfigFlow):
        VERSION = 5
        CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL

        @asyncio.coroutine
        def async_step_user(self, user_input=None):
            return self.async_create_entry(
                title='Test Title',
                data={
                    'token': 'abcd'
                }
            )

    with patch.dict(config_entries.HANDLERS, {'test': TestFlow}):
        await hass.config_entries.flow.async_init(
            'test', context={'source': config_entries.SOURCE_USER})

    class Test2Flow(config_entries.ConfigFlow):
        VERSION = 3
        CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_PUSH

        @asyncio.coroutine
        def async_step_user(self, user_input=None):
            return self.async_create_entry(
                title='Test 2 Title',
                data={
                    'username': '******'
                }
            )

    with patch('homeassistant.config_entries.HANDLERS.get',
               return_value=Test2Flow):
        await hass.config_entries.flow.async_init(
            'test', context={'source': config_entries.SOURCE_USER})

    # To trigger the call_later
    async_fire_time_changed(hass, dt.utcnow() + timedelta(seconds=1))
    # To execute the save
    await hass.async_block_till_done()

    # Now load written data in new config manager
    manager = config_entries.ConfigEntries(hass, {})
    await manager.async_initialize()

    # Ensure same order
    for orig, loaded in zip(hass.config_entries.async_entries(),
                            manager.async_entries()):
        assert orig.version == loaded.version
        assert orig.domain == loaded.domain
        assert orig.title == loaded.title
        assert orig.data == loaded.data
        assert orig.source == loaded.source
        assert orig.connection_class == loaded.connection_class
def test_template_delay_off(hass):
    """Test binary sensor template delay off."""
    config = {
        'binary_sensor': {
            'platform': 'template',
            'sensors': {
                'test': {
                    'friendly_name': 'virtual thingy',
                    'value_template':
                        "{{ states.sensor.test_state.state == 'on' }}",
                    'device_class': 'motion',
                    'delay_off': 5
                },
            },
        },
    }
    hass.states.async_set('sensor.test_state', 'on')
    yield from setup.async_setup_component(hass, 'binary_sensor', config)
    yield from hass.async_start()

    hass.states.async_set('sensor.test_state', 'off')
    yield from hass.async_block_till_done()

    state = hass.states.get('binary_sensor.test')
    assert state.state == 'on'

    future = dt_util.utcnow() + timedelta(seconds=5)
    async_fire_time_changed(hass, future)
    yield from hass.async_block_till_done()

    state = hass.states.get('binary_sensor.test')
    assert state.state == 'off'

    # check with time changes
    hass.states.async_set('sensor.test_state', 'on')
    yield from hass.async_block_till_done()

    state = hass.states.get('binary_sensor.test')
    assert state.state == 'on'

    hass.states.async_set('sensor.test_state', 'off')
    yield from hass.async_block_till_done()

    state = hass.states.get('binary_sensor.test')
    assert state.state == 'on'

    hass.states.async_set('sensor.test_state', 'on')
    yield from hass.async_block_till_done()

    state = hass.states.get('binary_sensor.test')
    assert state.state == 'on'

    future = dt_util.utcnow() + timedelta(seconds=5)
    async_fire_time_changed(hass, future)
    yield from hass.async_block_till_done()

    state = hass.states.get('binary_sensor.test')
    assert state.state == 'on'
Beispiel #16
0
    async def poll_and_get_state(self):
        """Trigger a time based poll and return the current entity state."""
        next_update = dt_util.utcnow() + timedelta(seconds=60)
        async_fire_time_changed(self.hass, next_update)
        await self.hass.async_block_till_done()

        state = self.hass.states.get(self.entity_id)
        assert state is not None
        return state
async def test_trigger_with_pending_and_specific_delay(hass):
    """Test trigger method and switch from pending to triggered."""
    assert await async_setup_component(
        hass, alarm_control_panel.DOMAIN,
        {'alarm_control_panel': {
            'platform': 'manual',
            'name': 'test',
            'code': CODE,
            'delay_time': 10,
            'pending_time': 0,
            'armed_away': {
                'delay_time': 1
            },
            'triggered': {
                'pending_time': 1
            },
            'disarm_after_trigger': False
        }})

    entity_id = 'alarm_control_panel.test'

    assert STATE_ALARM_DISARMED == \
        hass.states.get(entity_id).state

    common.async_alarm_arm_away(hass, CODE)
    await hass.async_block_till_done()

    assert STATE_ALARM_ARMED_AWAY == \
        hass.states.get(entity_id).state

    common.async_alarm_trigger(hass, entity_id=entity_id)
    await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state.state == STATE_ALARM_PENDING
    assert state.attributes['post_pending_state'] == STATE_ALARM_TRIGGERED

    future = dt_util.utcnow() + timedelta(seconds=1)
    with patch(('homeassistant.components.manual.alarm_control_panel.'
                'dt_util.utcnow'), return_value=future):
        async_fire_time_changed(hass, future)
        await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state.state == STATE_ALARM_PENDING
    assert state.attributes['post_pending_state'] == STATE_ALARM_TRIGGERED

    future += timedelta(seconds=1)
    with patch(('homeassistant.components.manual.alarm_control_panel.'
                'dt_util.utcnow'), return_value=future):
        async_fire_time_changed(hass, future)
        await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state.state == STATE_ALARM_TRIGGERED
async def test_saving_with_delay(hass, store, hass_storage):
    """Test saving data after a delay."""
    store.async_delay_save(lambda: MOCK_DATA, 1)
    assert store.key not in hass_storage

    async_fire_time_changed(hass, dt.utcnow() + timedelta(seconds=1))
    await hass.async_block_till_done()
    assert hass_storage[store.key] == {
        'version': MOCK_VERSION,
        'key': MOCK_KEY,
        'data': MOCK_DATA,
    }
Beispiel #19
0
async def test_action_delay(hass, calls):
    """Test action delay."""
    assert await async_setup_component(hass, automation.DOMAIN, {
        automation.DOMAIN: {
            'alias': 'hello',
            'trigger': {
                'platform': 'event',
                'event_type': 'test_event',
            },
            'action': [
                {
                    'service': 'test.automation',
                    'data_template': {
                        'some': '{{ trigger.platform }} - '
                                '{{ trigger.event.event_type }}'
                    }
                },
                {'delay': {'minutes': '10'}},
                {
                    'service': 'test.automation',
                    'data_template': {
                        'some': '{{ trigger.platform }} - '
                                '{{ trigger.event.event_type }}'
                    }
                },
            ]
        }
    })

    time = dt_util.utcnow()

    with patch('homeassistant.components.automation.utcnow',
               return_value=time):
        hass.bus.async_fire('test_event')
        await hass.async_block_till_done()

    assert len(calls) == 1
    assert calls[0].data['some'] == 'event - test_event'

    future = dt_util.utcnow() + timedelta(minutes=10)
    async_fire_time_changed(hass, future)
    await hass.async_block_till_done()

    assert len(calls) == 2
    assert calls[1].data['some'] == 'event - test_event'

    state = hass.states.get('automation.hello')
    assert state is not None
    assert state.attributes.get('last_triggered') == time
    state = hass.states.get('group.all_automations')
    assert state is not None
    assert state.attributes.get('entity_id') == ('automation.hello',)
def test_auto_heal_disabled(hass, mock_openzwave):
    """Test network auto-heal disabled."""
    assert (yield from async_setup_component(hass, 'zwave', {
        'zwave': {
            'autoheal': False,
        }}))
    network = hass.data[zwave.DATA_NETWORK]
    assert not network.heal.called

    time = datetime(2017, 5, 6, 0, 0, 0)
    async_fire_time_changed(hass, time)
    yield from hass.async_block_till_done()
    assert not network.heal.called
Beispiel #21
0
async def simulate_time(hass, mock_lj, delta):
    """Test to simulate time."""
    _LOGGER.info(
        '*** simulate time change by %s: %s',
        delta,
        mock_lj.start_time + delta)
    mock_lj.last_delta = delta
    with mock.patch('homeassistant.helpers.condition.dt_util.utcnow',
                    return_value=mock_lj.start_time + delta):
        _LOGGER.info('now=%s', dt_util.utcnow())
        async_fire_time_changed(hass, mock_lj.start_time + delta)
        await hass.async_block_till_done()
        _LOGGER.info('done with now=%s', dt_util.utcnow())
Beispiel #22
0
async def test_available(hass, platforms, main_dtv, mock_now):
    """Test available status."""
    next_update = mock_now + timedelta(minutes=5)
    with patch('homeassistant.util.dt.utcnow', return_value=next_update):
        async_fire_time_changed(hass, next_update)
        await hass.async_block_till_done()

    # Confirm service is currently set to available.
    state = hass.states.get(MAIN_ENTITY_ID)
    assert state.state != STATE_UNAVAILABLE

    # Make update fail 1st time
    next_update = next_update + timedelta(minutes=5)
    with patch.object(
            main_dtv, 'get_standby', side_effect=requests.RequestException), \
            patch('homeassistant.util.dt.utcnow', return_value=next_update):
        async_fire_time_changed(hass, next_update)
        await hass.async_block_till_done()

    state = hass.states.get(MAIN_ENTITY_ID)
    assert state.state != STATE_UNAVAILABLE

    # Make update fail 2nd time within 1 minute
    next_update = next_update + timedelta(seconds=30)
    with patch.object(
            main_dtv, 'get_standby', side_effect=requests.RequestException), \
            patch('homeassistant.util.dt.utcnow', return_value=next_update):
        async_fire_time_changed(hass, next_update)
        await hass.async_block_till_done()

    state = hass.states.get(MAIN_ENTITY_ID)
    assert state.state != STATE_UNAVAILABLE

    # Make update fail 3rd time more then a minute after 1st failure
    next_update = next_update + timedelta(minutes=1)
    with patch.object(
            main_dtv, 'get_standby', side_effect=requests.RequestException), \
            patch('homeassistant.util.dt.utcnow', return_value=next_update):
        async_fire_time_changed(hass, next_update)
        await hass.async_block_till_done()

    state = hass.states.get(MAIN_ENTITY_ID)
    assert state.state == STATE_UNAVAILABLE

    # Recheck state, update should work again.
    next_update = next_update + timedelta(minutes=5)
    with patch('homeassistant.util.dt.utcnow', return_value=next_update):
        async_fire_time_changed(hass, next_update)
        await hass.async_block_till_done()
    state = hass.states.get(MAIN_ENTITY_ID)
    assert state.state != STATE_UNAVAILABLE
Beispiel #23
0
async def test_set_cover_position(hass, setup_comp):
    """Test moving the cover to a specific position."""
    state = hass.states.get(ENTITY_COVER)
    assert 70 == state.attributes.get('current_position')
    await hass.services.async_call(
        DOMAIN, SERVICE_SET_COVER_POSITION,
        {ATTR_ENTITY_ID: ENTITY_COVER, ATTR_POSITION: 10}, blocking=True)
    for _ in range(6):
        future = dt_util.utcnow() + timedelta(seconds=1)
        async_fire_time_changed(hass, future)
        await hass.async_block_till_done()

    state = hass.states.get(ENTITY_COVER)
    assert 10 == state.attributes.get('current_position')
Beispiel #24
0
async def test_open_cover_tilt(hass, setup_comp):
    """Test opening the cover tilt."""
    state = hass.states.get(ENTITY_COVER)
    assert 50 == state.attributes.get('current_tilt_position')
    await hass.services.async_call(
        DOMAIN, SERVICE_OPEN_COVER_TILT,
        {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True)
    for _ in range(7):
        future = dt_util.utcnow() + timedelta(seconds=1)
        async_fire_time_changed(hass, future)
        await hass.async_block_till_done()

    state = hass.states.get(ENTITY_COVER)
    assert 100 == state.attributes.get('current_tilt_position')
Beispiel #25
0
async def test_check_attributes(hass, platforms, mock_now):
    """Test attributes."""
    next_update = mock_now + timedelta(minutes=5)
    with patch('homeassistant.util.dt.utcnow', return_value=next_update):
        async_fire_time_changed(hass, next_update)
        await hass.async_block_till_done()

    # Start playing TV
    with patch('homeassistant.util.dt.utcnow',
               return_value=next_update):
        await async_media_play(hass, CLIENT_ENTITY_ID)
        await hass.async_block_till_done()

    state = hass.states.get(CLIENT_ENTITY_ID)
    assert state.state == STATE_PLAYING

    assert state.attributes.get(mp.ATTR_MEDIA_CONTENT_ID) == \
        RECORDING['programId']
    assert state.attributes.get(mp.ATTR_MEDIA_CONTENT_TYPE) == \
        mp.MEDIA_TYPE_TVSHOW
    assert state.attributes.get(mp.ATTR_MEDIA_DURATION) == \
        RECORDING['duration']
    assert state.attributes.get(mp.ATTR_MEDIA_POSITION) == 2
    assert state.attributes.get(
        mp.ATTR_MEDIA_POSITION_UPDATED_AT) == next_update
    assert state.attributes.get(mp.ATTR_MEDIA_TITLE) == RECORDING['title']
    assert state.attributes.get(mp.ATTR_MEDIA_SERIES_TITLE) == \
        RECORDING['episodeTitle']
    assert state.attributes.get(mp.ATTR_MEDIA_CHANNEL) == \
        "{} ({})".format(RECORDING['callsign'], RECORDING['major'])
    assert state.attributes.get(mp.ATTR_INPUT_SOURCE) == RECORDING['major']
    assert state.attributes.get(ATTR_MEDIA_CURRENTLY_RECORDING) == \
        RECORDING['isRecording']
    assert state.attributes.get(ATTR_MEDIA_RATING) == RECORDING['rating']
    assert state.attributes.get(ATTR_MEDIA_RECORDED)
    assert state.attributes.get(ATTR_MEDIA_START_TIME) == \
        datetime(2018, 11, 10, 19, 0, tzinfo=dt_util.UTC)

    # Test to make sure that ATTR_MEDIA_POSITION_UPDATED_AT is not
    # updated if TV is paused.
    with patch('homeassistant.util.dt.utcnow',
               return_value=next_update + timedelta(minutes=5)):
        await async_media_pause(hass, CLIENT_ENTITY_ID)
        await hass.async_block_till_done()

    state = hass.states.get(CLIENT_ENTITY_ID)
    assert state.state == STATE_PAUSED
    assert state.attributes.get(
        mp.ATTR_MEDIA_POSITION_UPDATED_AT) == next_update
Beispiel #26
0
async def test_set_position_cover(hass_hue, hue_client):
    """Test setting postion cover ."""
    COVER_ID = "cover.living_room_window"
    # Turn the office light off first
    await hass_hue.services.async_call(
        cover.DOMAIN, const.SERVICE_CLOSE_COVER,
        {const.ATTR_ENTITY_ID: COVER_ID},
        blocking=True)

    cover_test = hass_hue.states.get(COVER_ID)
    assert cover_test.state == 'closing'

    for _ in range(7):
        future = dt_util.utcnow() + timedelta(seconds=1)
        async_fire_time_changed(hass_hue, future)
        await hass_hue.async_block_till_done()

    cover_test = hass_hue.states.get(COVER_ID)
    assert cover_test.state == 'closed'

    level = 20
    brightness = round(level/100*255)

    # Go through the API to open
    cover_result = await perform_put_light_state(
        hass_hue, hue_client,
        COVER_ID, False, brightness)

    assert cover_result.status == 200
    assert 'application/json' in cover_result.headers['content-type']

    cover_result_json = await cover_result.json()

    assert len(cover_result_json) == 2
    assert True, cover_result_json[0]['success'][
        '/lights/cover.living_room_window/state/on']
    assert cover_result_json[1]['success'][
        '/lights/cover.living_room_window/state/bri'] == level

    for _ in range(100):
        future = dt_util.utcnow() + timedelta(seconds=1)
        async_fire_time_changed(hass_hue, future)
        await hass_hue.async_block_till_done()

    # Check to make sure the state changed
    cover_test_2 = hass_hue.states.get(COVER_ID)
    assert cover_test_2.state == 'open'
    assert cover_test_2.attributes.get('current_position') == level
Beispiel #27
0
def test_same_version_not_show_entity(hass, mock_get_uuid,
                                      mock_get_newest_version):
    """Test if new entity is created if new version is available."""
    mock_get_uuid.return_value = MOCK_HUUID
    mock_get_newest_version.return_value = mock_coro((MOCK_VERSION, ''))

    res = yield from async_setup_component(
        hass, updater.DOMAIN, {updater.DOMAIN: {}})
    assert res, 'Updater failed to setup'

    with patch('homeassistant.components.updater.CURRENT_VERSION',
               MOCK_VERSION):
        async_fire_time_changed(hass, dt_util.utcnow() + timedelta(hours=1))
        yield from hass.async_block_till_done()

    assert hass.states.get(updater.ENTITY_ID) is None
Beispiel #28
0
async def test_set_tilt_positions(hass, setup_comp):
    """Test set tilt position function."""
    await hass.services.async_call(
        DOMAIN, SERVICE_SET_COVER_TILT_POSITION,
        {ATTR_ENTITY_ID: COVER_GROUP, ATTR_TILT_POSITION: 80}, blocking=True)
    for _ in range(3):
        future = dt_util.utcnow() + timedelta(seconds=1)
        async_fire_time_changed(hass, future)
        await hass.async_block_till_done()

    state = hass.states.get(COVER_GROUP)
    assert state.state == STATE_OPEN
    assert state.attributes.get(ATTR_CURRENT_TILT_POSITION) == 80

    assert hass.states.get(DEMO_COVER_TILT) \
        .attributes.get(ATTR_CURRENT_TILT_POSITION) == 80
Beispiel #29
0
def test_wait_till_timer_expires(hass):
    """Test for a timer to end."""
    hass.state = CoreState.starting

    yield from async_setup_component(hass, DOMAIN, {
        DOMAIN: {
            'test1': {
                CONF_DURATION: 10,
            }
        }})

    state = hass.states.get('timer.test1')
    assert state
    assert state.state == STATUS_IDLE

    results = []

    def fake_event_listener(event):
        """Fake event listener for trigger."""
        results.append(event)

    hass.bus.async_listen(EVENT_TIMER_STARTED, fake_event_listener)
    hass.bus.async_listen(EVENT_TIMER_PAUSED, fake_event_listener)
    hass.bus.async_listen(EVENT_TIMER_FINISHED, fake_event_listener)
    hass.bus.async_listen(EVENT_TIMER_CANCELLED, fake_event_listener)

    yield from hass.services.async_call(DOMAIN,
                                        SERVICE_START,
                                        {CONF_ENTITY_ID: 'timer.test1'})
    yield from hass.async_block_till_done()

    state = hass.states.get('timer.test1')
    assert state
    assert state.state == STATUS_ACTIVE

    assert results[-1].event_type == EVENT_TIMER_STARTED
    assert len(results) == 1

    async_fire_time_changed(hass, utcnow() + timedelta(seconds=10))
    yield from hass.async_block_till_done()

    state = hass.states.get('timer.test1')
    assert state
    assert state.state == STATUS_IDLE

    assert results[-1].event_type == EVENT_TIMER_FINISHED
    assert len(results) == 2
Beispiel #30
0
async def test_stop_cover(hass, setup_comp):
    """Test stopping the cover."""
    state = hass.states.get(ENTITY_COVER)
    assert 70 == state.attributes.get('current_position')
    await hass.services.async_call(
        DOMAIN, SERVICE_OPEN_COVER,
        {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True)
    future = dt_util.utcnow() + timedelta(seconds=1)
    async_fire_time_changed(hass, future)
    await hass.async_block_till_done()
    await hass.services.async_call(
        DOMAIN, SERVICE_STOP_COVER,
        {ATTR_ENTITY_ID: ENTITY_COVER}, blocking=True)
    async_fire_time_changed(hass, future)
    await hass.async_block_till_done()
    state = hass.states.get(ENTITY_COVER)
    assert 80 == state.attributes.get('current_position')
async def test_arm_away_after_disabled_disarmed(hass):
    """Test pending state with and without zero trigger time."""
    assert await async_setup_component(
        hass,
        alarm_control_panel.DOMAIN,
        {
            "alarm_control_panel": {
                "platform": "manual",
                "name": "test",
                "code": CODE,
                "pending_time": 0,
                "delay_time": 1,
                "armed_away": {"pending_time": 1},
                "disarmed": {"trigger_time": 0},
                "disarm_after_trigger": False,
            }
        },
    )

    entity_id = "alarm_control_panel.test"

    assert STATE_ALARM_DISARMED == hass.states.get(entity_id).state

    await common.async_alarm_arm_away(hass, CODE)

    state = hass.states.get(entity_id)
    assert STATE_ALARM_PENDING == state.state
    assert STATE_ALARM_DISARMED == state.attributes["pre_pending_state"]
    assert STATE_ALARM_ARMED_AWAY == state.attributes["post_pending_state"]

    await common.async_alarm_trigger(hass, entity_id=entity_id)

    state = hass.states.get(entity_id)
    assert STATE_ALARM_PENDING == state.state
    assert STATE_ALARM_DISARMED == state.attributes["pre_pending_state"]
    assert STATE_ALARM_ARMED_AWAY == state.attributes["post_pending_state"]

    future = dt_util.utcnow() + timedelta(seconds=1)
    with patch(
        ("homeassistant.components.manual.alarm_control_panel.dt_util.utcnow"),
        return_value=future,
    ):
        async_fire_time_changed(hass, future)
        await hass.async_block_till_done()

        state = hass.states.get(entity_id)
        assert STATE_ALARM_ARMED_AWAY == state.state

        await common.async_alarm_trigger(hass, entity_id=entity_id)

        state = hass.states.get(entity_id)
        assert STATE_ALARM_PENDING == state.state
        assert STATE_ALARM_ARMED_AWAY == state.attributes["pre_pending_state"]
        assert STATE_ALARM_TRIGGERED == state.attributes["post_pending_state"]

    future += timedelta(seconds=1)
    with patch(
        ("homeassistant.components.manual.alarm_control_panel.dt_util.utcnow"),
        return_value=future,
    ):
        async_fire_time_changed(hass, future)
        await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert STATE_ALARM_TRIGGERED == state.state
Beispiel #32
0
async def test_if_fires_on_state_change(opp, calls):
    """Test for turn_on and turn_off triggers firing."""
    opp.states.async_set(
        "humidifier.entity",
        STATE_ON,
        {
            const.ATTR_HUMIDITY: 23,
            ATTR_MODE: "home",
            const.ATTR_AVAILABLE_MODES: ["home", "away"],
            ATTR_SUPPORTED_FEATURES: 1,
        },
    )

    assert await async_setup_component(
        opp,
        automation.DOMAIN,
        {
            automation.DOMAIN: [
                {
                    "trigger": {
                        "platform": "device",
                        "domain": DOMAIN,
                        "device_id": "",
                        "entity_id": "humidifier.entity",
                        "type": "target_humidity_changed",
                        "below": 20,
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some": "target_humidity_changed_below"
                        },
                    },
                },
                {
                    "trigger": {
                        "platform": "device",
                        "domain": DOMAIN,
                        "device_id": "",
                        "entity_id": "humidifier.entity",
                        "type": "target_humidity_changed",
                        "above": 30,
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some": "target_humidity_changed_above"
                        },
                    },
                },
                {
                    "trigger": {
                        "platform": "device",
                        "domain": DOMAIN,
                        "device_id": "",
                        "entity_id": "humidifier.entity",
                        "type": "target_humidity_changed",
                        "above": 30,
                        "for": {
                            "seconds": 5
                        },
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some": "target_humidity_changed_above_for"
                        },
                    },
                },
                {
                    "trigger": {
                        "platform": "device",
                        "domain": DOMAIN,
                        "device_id": "",
                        "entity_id": "humidifier.entity",
                        "type": "turned_on",
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some":
                            "turn_on {{ trigger.%s }}" %
                            "}} - {{ trigger.".join((
                                "platform",
                                "entity_id",
                                "from_state.state",
                                "to_state.state",
                                "for",
                            ))
                        },
                    },
                },
                {
                    "trigger": {
                        "platform": "device",
                        "domain": DOMAIN,
                        "device_id": "",
                        "entity_id": "humidifier.entity",
                        "type": "turned_off",
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some":
                            "turn_off {{ trigger.%s }}" %
                            "}} - {{ trigger.".join((
                                "platform",
                                "entity_id",
                                "from_state.state",
                                "to_state.state",
                                "for",
                            ))
                        },
                    },
                },
            ]
        },
    )

    # Fake that the humidity is changing
    opp.states.async_set("humidifier.entity", STATE_ON,
                         {const.ATTR_HUMIDITY: 7})
    await opp.async_block_till_done()
    assert len(calls) == 1
    assert calls[0].data["some"] == "target_humidity_changed_below"

    # Fake that the humidity is changing
    opp.states.async_set("humidifier.entity", STATE_ON,
                         {const.ATTR_HUMIDITY: 37})
    await opp.async_block_till_done()
    assert len(calls) == 2
    assert calls[1].data["some"] == "target_humidity_changed_above"

    # Wait 6 minutes
    async_fire_time_changed(opp,
                            dt_util.utcnow() + datetime.timedelta(minutes=6))
    await opp.async_block_till_done()
    assert len(calls) == 3
    assert calls[2].data["some"] == "target_humidity_changed_above_for"

    # Fake turn off
    opp.states.async_set("humidifier.entity", STATE_OFF,
                         {const.ATTR_HUMIDITY: 37})
    await opp.async_block_till_done()
    assert len(calls) == 4
    assert (calls[3].data["some"] ==
            "turn_off device - humidifier.entity - on - off - None")

    # Fake turn on
    opp.states.async_set("humidifier.entity", STATE_ON,
                         {const.ATTR_HUMIDITY: 37})
    await opp.async_block_till_done()
    assert len(calls) == 5
    assert (calls[4].data["some"] ==
            "turn_on device - humidifier.entity - off - on - None")
Beispiel #33
0
async def test_not_available_at_startup(hass: HomeAssistant):
    """Test when configured devices are not available."""
    config = {
        tplink.DOMAIN: {
            CONF_DISCOVERY: False,
            CONF_SWITCH: [{
                CONF_HOST: "321.321.321.321"
            }],
        }
    }

    with patch(
            "homeassistant.components.tplink.common.Discover.discover"
    ), patch(
            "homeassistant.components.tplink.get_static_devices"
    ) as get_static_devices, patch(
            "homeassistant.components.tplink.common.SmartDevice._query_helper"
    ), patch(
            "homeassistant.components.tplink.light.async_setup_entry",
            return_value=mock_coro(True),
    ), patch("homeassistant.components.tplink.common.SmartPlug.is_dimmable",
             False):

        switch = SmartPlug("321.321.321.321")
        switch.get_sysinfo = MagicMock(side_effect=SmartDeviceException())
        get_static_devices.return_value = SmartDevices([], [switch])

        # run setup while device unreachable
        await async_setup_component(hass, tplink.DOMAIN, config)
        await hass.async_block_till_done()

        entries = hass.config_entries.async_entries(tplink.DOMAIN)
        assert len(entries) == 1
        assert entries[0].state is config_entries.ConfigEntryState.LOADED

        entities = hass.states.async_entity_ids(SWITCH_DOMAIN)
        assert len(entities) == 0

        # retrying with still unreachable device
        async_fire_time_changed(hass, dt.utcnow() + UNAVAILABLE_RETRY_DELAY)
        await hass.async_block_till_done()

        entries = hass.config_entries.async_entries(tplink.DOMAIN)
        assert len(entries) == 1
        assert entries[0].state is config_entries.ConfigEntryState.LOADED

        entities = hass.states.async_entity_ids(SWITCH_DOMAIN)
        assert len(entities) == 0

        # retrying with now reachable device
        switch.get_sysinfo = MagicMock(
            return_value=SMARTPLUG_HS100_DATA["sysinfo"])
        async_fire_time_changed(hass, dt.utcnow() + UNAVAILABLE_RETRY_DELAY)
        await hass.async_block_till_done()

        entries = hass.config_entries.async_entries(tplink.DOMAIN)
        assert len(entries) == 1
        assert entries[0].state is config_entries.ConfigEntryState.LOADED

        entities = hass.states.async_entity_ids(SWITCH_DOMAIN)
        assert len(entities) == 1
Beispiel #34
0
async def test_location_change_with_overlapping_udn_st_combinations(
        hass, aioclient_mock):
    """Test handling when a UDN and ST broadcast multiple locations."""
    mock_get_ssdp = {
        "test_integration": [{
            "manufacturer": "test_manufacturer",
            "modelName": "test_model"
        }]
    }

    hue_response = """
<root xmlns="urn:schemas-upnp-org:device-1-0">
<device>
<manufacturer>test_manufacturer</manufacturer>
<modelName>test_model</modelName>
</device>
</root>
    """

    aioclient_mock.get(
        "http://192.168.72.1:49154/wps_device.xml",
        text=hue_response.format(ip_address="192.168.72.1"),
    )
    aioclient_mock.get(
        "http://192.168.72.1:49152/wps_device.xml",
        text=hue_response.format(ip_address="192.168.72.1"),
    )
    ssdp_response_without_location = {
        "ST": "upnp:rootdevice",
        "_udn": "uuid:a793d3cc-e802-44fb-84f4-5a30f33115b6",
        "USN": "uuid:a793d3cc-e802-44fb-84f4-5a30f33115b6::upnp:rootdevice",
        "EXT": "",
    }

    port_49154_response = CaseInsensitiveDict(
        **ssdp_response_without_location,
        **{"LOCATION": "http://192.168.72.1:49154/wps_device.xml"},
    )
    port_49152_response = CaseInsensitiveDict(
        **ssdp_response_without_location,
        **{"LOCATION": "http://192.168.72.1:49152/wps_device.xml"},
    )
    mock_ssdp_response = port_49154_response

    def _generate_fake_ssdp_listener(*args, **kwargs):
        listener = SSDPListener(*args, **kwargs)

        async def _async_callback(*_):
            pass

        @callback
        def _callback(*_):
            hass.async_create_task(listener.async_callback(mock_ssdp_response))

        listener.async_start = _async_callback
        listener.async_search = _callback
        return listener

    with patch(
            "homeassistant.components.ssdp.async_get_ssdp",
            return_value=mock_get_ssdp,
    ), patch(
            "homeassistant.components.ssdp.SSDPListener",
            new=_generate_fake_ssdp_listener,
    ), patch.object(hass.config_entries.flow, "async_init") as mock_init:
        assert await async_setup_component(hass, ssdp.DOMAIN,
                                           {ssdp.DOMAIN: {}})
        await hass.async_block_till_done()
        hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
        await hass.async_block_till_done()
        async_fire_time_changed(hass,
                                dt_util.utcnow() + timedelta(seconds=200))
        await hass.async_block_till_done()
        assert len(mock_init.mock_calls) == 1
        assert mock_init.mock_calls[0][1][0] == "test_integration"
        assert mock_init.mock_calls[0][2]["context"] == {
            "source": config_entries.SOURCE_SSDP
        }
        assert (mock_init.mock_calls[0][2]["data"][ssdp.ATTR_SSDP_LOCATION] ==
                port_49154_response["location"])

        mock_init.reset_mock()
        mock_ssdp_response = port_49152_response
        async_fire_time_changed(hass,
                                dt_util.utcnow() + timedelta(seconds=400))
        await hass.async_block_till_done()
        assert mock_init.mock_calls[0][1][0] == "test_integration"
        assert mock_init.mock_calls[0][2]["context"] == {
            "source": config_entries.SOURCE_SSDP
        }
        assert (mock_init.mock_calls[0][2]["data"][ssdp.ATTR_SSDP_LOCATION] ==
                port_49152_response["location"])

        mock_init.reset_mock()
        mock_ssdp_response = port_49154_response
        async_fire_time_changed(hass,
                                dt_util.utcnow() + timedelta(seconds=600))
        await hass.async_block_till_done()
        assert mock_init.mock_calls[0][1][0] == "test_integration"
        assert mock_init.mock_calls[0][2]["context"] == {
            "source": config_entries.SOURCE_SSDP
        }
        assert (mock_init.mock_calls[0][2]["data"][ssdp.ATTR_SSDP_LOCATION] ==
                port_49154_response["location"])
Beispiel #35
0
 def increment_time(time):
     mock_utc.return_value += time
     mock_utc_weather.return_value += time
     async_fire_time_changed(hass, mock_utc.return_value)
async def test_see_passive_zone_state(
    hass, mock_device_tracker_conf, enable_custom_integrations
):
    """Test that the device tracker sets gps for passive trackers."""
    now = dt_util.utcnow()

    register_time = datetime(now.year + 1, 9, 15, 23, tzinfo=dt_util.UTC)
    scan_time = datetime(now.year + 1, 9, 15, 23, 1, tzinfo=dt_util.UTC)

    with assert_setup_component(1, zone.DOMAIN):
        zone_info = {
            "name": "Home",
            "latitude": 1,
            "longitude": 2,
            "radius": 250,
            "passive": False,
        }

        await async_setup_component(hass, zone.DOMAIN, {"zone": zone_info})

    scanner = getattr(hass.components, "test.device_tracker").SCANNER
    scanner.reset()
    scanner.come_home("dev1")

    with patch(
        "homeassistant.components.device_tracker.legacy.dt_util.utcnow",
        return_value=register_time,
    ), assert_setup_component(1, device_tracker.DOMAIN):
        assert await async_setup_component(
            hass,
            device_tracker.DOMAIN,
            {
                device_tracker.DOMAIN: {
                    CONF_PLATFORM: "test",
                    device_tracker.CONF_CONSIDER_HOME: 59,
                }
            },
        )
        await hass.async_block_till_done()

    state = hass.states.get("device_tracker.dev1")
    attrs = state.attributes
    assert state.state == STATE_HOME
    assert state.object_id == "dev1"
    assert state.name == "dev1"
    assert attrs.get("friendly_name") == "dev1"
    assert attrs.get("latitude") == 1
    assert attrs.get("longitude") == 2
    assert attrs.get("gps_accuracy") == 0
    assert attrs.get("source_type") == device_tracker.SOURCE_TYPE_ROUTER

    scanner.leave_home("dev1")

    with patch(
        "homeassistant.components.device_tracker.legacy.dt_util.utcnow",
        return_value=scan_time,
    ):
        async_fire_time_changed(hass, scan_time)
        await hass.async_block_till_done()

    state = hass.states.get("device_tracker.dev1")
    attrs = state.attributes
    assert state.state == STATE_NOT_HOME
    assert state.object_id == "dev1"
    assert state.name == "dev1"
    assert attrs.get("friendly_name") == "dev1"
    assert attrs.get("latitude") is None
    assert attrs.get("longitude") is None
    assert attrs.get("gps_accuracy") is None
    assert attrs.get("source_type") == device_tracker.SOURCE_TYPE_ROUTER
Beispiel #37
0
async def test_location_change_evicts_prior_location_from_cache(
        hass, aioclient_mock):
    """Test that a location change for a UDN will evict the prior location from the cache."""
    mock_get_ssdp = {
        "hue": [{
            "manufacturer": "Signify",
            "modelName": "Philips hue bridge 2015"
        }]
    }

    hue_response = """
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</specVersion>
<URLBase>http://{ip_address}:80/</URLBase>
<device>
<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>
<friendlyName>Philips hue ({ip_address})</friendlyName>
<manufacturer>Signify</manufacturer>
<manufacturerURL>http://www.philips-hue.com</manufacturerURL>
<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>
<modelName>Philips hue bridge 2015</modelName>
<modelNumber>BSB002</modelNumber>
<modelURL>http://www.philips-hue.com</modelURL>
<serialNumber>001788a36abf</serialNumber>
<UDN>uuid:2f402f80-da50-11e1-9b23-001788a36abf</UDN>
</device>
</root>
    """

    aioclient_mock.get(
        "http://192.168.212.23/description.xml",
        text=hue_response.format(ip_address="192.168.212.23"),
    )
    aioclient_mock.get(
        "http://169.254.8.155/description.xml",
        text=hue_response.format(ip_address="169.254.8.155"),
    )
    ssdp_response_without_location = {
        "ST": "uuid:2f402f80-da50-11e1-9b23-001788a36abf",
        "_udn": "uuid:2f402f80-da50-11e1-9b23-001788a36abf",
        "USN": "uuid:2f402f80-da50-11e1-9b23-001788a36abf",
        "SERVER": "Hue/1.0 UPnP/1.0 IpBridge/1.44.0",
        "hue-bridgeid": "001788FFFEA36ABF",
        "EXT": "",
    }

    mock_good_ip_ssdp_response = CaseInsensitiveDict(
        **ssdp_response_without_location,
        **{"LOCATION": "http://192.168.212.23/description.xml"},
    )
    mock_link_local_ip_ssdp_response = CaseInsensitiveDict(
        **ssdp_response_without_location,
        **{"LOCATION": "http://169.254.8.155/description.xml"},
    )
    mock_ssdp_response = mock_good_ip_ssdp_response

    def _generate_fake_ssdp_listener(*args, **kwargs):
        listener = SSDPListener(*args, **kwargs)

        async def _async_callback(*_):
            pass

        @callback
        def _callback(*_):
            hass.async_create_task(listener.async_callback(mock_ssdp_response))

        listener.async_start = _async_callback
        listener.async_search = _callback
        return listener

    with patch(
            "homeassistant.components.ssdp.async_get_ssdp",
            return_value=mock_get_ssdp,
    ), patch(
            "homeassistant.components.ssdp.SSDPListener",
            new=_generate_fake_ssdp_listener,
    ), patch.object(hass.config_entries.flow, "async_init") as mock_init:
        assert await async_setup_component(hass, ssdp.DOMAIN,
                                           {ssdp.DOMAIN: {}})
        await hass.async_block_till_done()
        hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
        await hass.async_block_till_done()
        async_fire_time_changed(hass,
                                dt_util.utcnow() + timedelta(seconds=200))
        await hass.async_block_till_done()
        assert len(mock_init.mock_calls) == 1
        assert mock_init.mock_calls[0][1][0] == "hue"
        assert mock_init.mock_calls[0][2]["context"] == {
            "source": config_entries.SOURCE_SSDP
        }
        assert (mock_init.mock_calls[0][2]["data"][ssdp.ATTR_SSDP_LOCATION] ==
                mock_good_ip_ssdp_response["location"])

        mock_init.reset_mock()
        mock_ssdp_response = mock_link_local_ip_ssdp_response
        async_fire_time_changed(hass,
                                dt_util.utcnow() + timedelta(seconds=400))
        await hass.async_block_till_done()
        assert mock_init.mock_calls[0][1][0] == "hue"
        assert mock_init.mock_calls[0][2]["context"] == {
            "source": config_entries.SOURCE_SSDP
        }
        assert (mock_init.mock_calls[0][2]["data"][ssdp.ATTR_SSDP_LOCATION] ==
                mock_link_local_ip_ssdp_response["location"])

        mock_init.reset_mock()
        mock_ssdp_response = mock_good_ip_ssdp_response
        async_fire_time_changed(hass,
                                dt_util.utcnow() + timedelta(seconds=600))
        await hass.async_block_till_done()
        assert mock_init.mock_calls[0][1][0] == "hue"
        assert mock_init.mock_calls[0][2]["context"] == {
            "source": config_entries.SOURCE_SSDP
        }
        assert (mock_init.mock_calls[0][2]["data"][ssdp.ATTR_SSDP_LOCATION] ==
                mock_good_ip_ssdp_response["location"])
Beispiel #38
0
async def test_binary_sensor_get_state(hass, init_integration, entity_id: str,
                                       uid: str, name: str, model: str):
    """Test states of the binary_sensor."""
    init_integration
    registry = er.async_get(hass)
    registry_device = dr.async_get(hass)

    device = registry_device.async_get_device({("freedompro", uid)})
    assert device is not None
    assert device.identifiers == {("freedompro", uid)}
    assert device.manufacturer == "Freedompro"
    assert device.name == name
    assert device.model == model

    state = hass.states.get(entity_id)
    assert state
    assert state.attributes.get("friendly_name") == name

    entry = registry.async_get(entity_id)
    assert entry
    assert entry.unique_id == uid

    assert state.state == STATE_OFF

    with patch(
            "homeassistant.components.freedompro.get_states",
            return_value=[],
    ):

        async_fire_time_changed(hass, utcnow() + timedelta(hours=2))
        await hass.async_block_till_done()

        state = hass.states.get(entity_id)
        assert state
        assert state.attributes.get("friendly_name") == name

        entry = registry.async_get(entity_id)
        assert entry
        assert entry.unique_id == uid

        assert state.state == STATE_OFF

    get_states_response = list(DEVICES_STATE)
    for state_response in get_states_response:
        if state_response["uid"] == uid:
            if state_response["type"] == "smokeSensor":
                state_response["state"]["smokeDetected"] = True
            if state_response["type"] == "occupancySensor":
                state_response["state"]["occupancyDetected"] = True
            if state_response["type"] == "motionSensor":
                state_response["state"]["motionDetected"] = True
            if state_response["type"] == "contactSensor":
                state_response["state"]["contactSensorState"] = True
    with patch(
            "homeassistant.components.freedompro.get_states",
            return_value=get_states_response,
    ):

        async_fire_time_changed(hass, utcnow() + timedelta(hours=2))
        await hass.async_block_till_done()

        state = hass.states.get(entity_id)
        assert state
        assert state.attributes.get("friendly_name") == name

        entry = registry.async_get(entity_id)
        assert entry
        assert entry.unique_id == uid

        assert state.state == STATE_ON
Beispiel #39
0
async def test_expiration_on_discovery_and_discovery_update_of_binary_sensor(
        hass, mqtt_mock_entry_no_yaml_config, caplog):
    """Test that binary_sensor with expire_after set behaves correctly on discovery and discovery update."""
    await mqtt_mock_entry_no_yaml_config()
    config = {
        "name": "Test",
        "state_topic": "test-topic",
        "expire_after": 4,
        "force_update": True,
    }

    config_msg = json.dumps(config)

    # Set time and publish config message to create binary_sensor via discovery with 4 s expiry
    realnow = dt_util.utcnow()
    now = datetime(realnow.year + 1, 1, 1, 1, tzinfo=dt_util.UTC)
    with patch(("homeassistant.helpers.event.dt_util.utcnow"),
               return_value=now):
        async_fire_time_changed(hass, now)
        async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config",
                                config_msg)
        await hass.async_block_till_done()

    # Test that binary_sensor is not available
    state = hass.states.get("binary_sensor.test")
    assert state.state == STATE_UNAVAILABLE

    # Publish state message
    with patch(("homeassistant.helpers.event.dt_util.utcnow"),
               return_value=now):
        async_fire_mqtt_message(hass, "test-topic", "ON")
        await hass.async_block_till_done()

    # Test that binary_sensor has correct state
    state = hass.states.get("binary_sensor.test")
    assert state.state == STATE_ON

    # Advance +3 seconds
    now = now + timedelta(seconds=3)
    with patch(("homeassistant.helpers.event.dt_util.utcnow"),
               return_value=now):
        async_fire_time_changed(hass, now)
        await hass.async_block_till_done()

    # binary_sensor is not yet expired
    state = hass.states.get("binary_sensor.test")
    assert state.state == STATE_ON

    # Resend config message to update discovery
    with patch(("homeassistant.helpers.event.dt_util.utcnow"),
               return_value=now):
        async_fire_time_changed(hass, now)
        async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config",
                                config_msg)
        await hass.async_block_till_done()

    # Test that binary_sensor has not expired
    state = hass.states.get("binary_sensor.test")
    assert state.state == STATE_ON

    # Add +2 seconds
    now = now + timedelta(seconds=2)
    with patch(("homeassistant.helpers.event.dt_util.utcnow"),
               return_value=now):
        async_fire_time_changed(hass, now)
        await hass.async_block_till_done()

    # Test that binary_sensor has expired
    state = hass.states.get("binary_sensor.test")
    assert state.state == STATE_UNAVAILABLE

    # Resend config message to update discovery
    with patch(("homeassistant.helpers.event.dt_util.utcnow"),
               return_value=now):
        async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config",
                                config_msg)
        await hass.async_block_till_done()

    # Test that binary_sensor is still expired
    state = hass.states.get("binary_sensor.test")
    assert state.state == STATE_UNAVAILABLE
Beispiel #40
0
async def test_sensors_sensors(
    hass: HomeAssistant,
    mock_fully_kiosk: MagicMock,
    init_integration: MockConfigEntry,
) -> None:
    """Test standard Fully Kiosk sensors."""
    entity_registry = er.async_get(hass)
    device_registry = dr.async_get(hass)

    state = hass.states.get("sensor.amazon_fire_battery")
    assert state
    assert state.state == "100"
    assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.BATTERY
    assert state.attributes.get(ATTR_FRIENDLY_NAME) == "Amazon Fire Battery"
    assert state.attributes.get(
        ATTR_STATE_CLASS) == SensorStateClass.MEASUREMENT

    entry = entity_registry.async_get("sensor.amazon_fire_battery")
    assert entry
    assert entry.unique_id == "abcdef-123456-batteryLevel"

    state = hass.states.get("sensor.amazon_fire_screen_orientation")
    assert state
    assert state.state == "90"
    assert state.attributes.get(
        ATTR_FRIENDLY_NAME) == "Amazon Fire Screen orientation"

    entry = entity_registry.async_get("sensor.amazon_fire_screen_orientation")
    assert entry
    assert entry.unique_id == "abcdef-123456-screenOrientation"

    state = hass.states.get("sensor.amazon_fire_foreground_app")
    assert state
    assert state.state == "de.ozerov.fully"
    assert state.attributes.get(
        ATTR_FRIENDLY_NAME) == "Amazon Fire Foreground app"

    entry = entity_registry.async_get("sensor.amazon_fire_foreground_app")
    assert entry
    assert entry.unique_id == "abcdef-123456-foregroundApp"

    state = hass.states.get("sensor.amazon_fire_current_page")
    assert state
    assert state.state == "https://homeassistant.local"
    assert state.attributes.get(ATTR_DEVICE_CLASS) is None
    assert state.attributes.get(
        ATTR_FRIENDLY_NAME) == "Amazon Fire Current page"

    entry = entity_registry.async_get("sensor.amazon_fire_current_page")
    assert entry
    assert entry.unique_id == "abcdef-123456-currentPage"

    state = hass.states.get("sensor.amazon_fire_internal_storage_free_space")
    assert state
    assert state.state == "11675.5"
    assert state.attributes.get(ATTR_DEVICE_CLASS) is None
    assert (state.attributes.get(ATTR_FRIENDLY_NAME) ==
            "Amazon Fire Internal storage free space")
    assert state.attributes.get(
        ATTR_STATE_CLASS) == SensorStateClass.MEASUREMENT

    entry = entity_registry.async_get(
        "sensor.amazon_fire_internal_storage_free_space")
    assert entry
    assert entry.unique_id == "abcdef-123456-internalStorageFreeSpace"
    assert entry.entity_category == EntityCategory.DIAGNOSTIC

    state = hass.states.get("sensor.amazon_fire_internal_storage_total_space")
    assert state
    assert state.state == "12938.5"
    assert state.attributes.get(ATTR_DEVICE_CLASS) is None
    assert (state.attributes.get(ATTR_FRIENDLY_NAME) ==
            "Amazon Fire Internal storage total space")
    assert state.attributes.get(
        ATTR_STATE_CLASS) == SensorStateClass.MEASUREMENT

    entry = entity_registry.async_get(
        "sensor.amazon_fire_internal_storage_total_space")
    assert entry
    assert entry.unique_id == "abcdef-123456-internalStorageTotalSpace"
    assert entry.entity_category == EntityCategory.DIAGNOSTIC

    state = hass.states.get("sensor.amazon_fire_free_memory")
    assert state
    assert state.state == "362.4"
    assert state.attributes.get(ATTR_DEVICE_CLASS) is None
    assert state.attributes.get(
        ATTR_FRIENDLY_NAME) == "Amazon Fire Free memory"
    assert state.attributes.get(
        ATTR_STATE_CLASS) == SensorStateClass.MEASUREMENT

    entry = entity_registry.async_get("sensor.amazon_fire_free_memory")
    assert entry
    assert entry.unique_id == "abcdef-123456-ramFreeMemory"
    assert entry.entity_category == EntityCategory.DIAGNOSTIC

    state = hass.states.get("sensor.amazon_fire_total_memory")
    assert state
    assert state.state == "1440.1"
    assert state.attributes.get(ATTR_DEVICE_CLASS) is None
    assert state.attributes.get(
        ATTR_FRIENDLY_NAME) == "Amazon Fire Total memory"
    assert state.attributes.get(
        ATTR_STATE_CLASS) == SensorStateClass.MEASUREMENT

    entry = entity_registry.async_get("sensor.amazon_fire_total_memory")
    assert entry
    assert entry.unique_id == "abcdef-123456-ramTotalMemory"
    assert entry.entity_category == EntityCategory.DIAGNOSTIC

    assert entry.device_id
    device_entry = device_registry.async_get(entry.device_id)
    assert device_entry
    assert device_entry.configuration_url == "http://192.168.1.234:2323"
    assert device_entry.entry_type is None
    assert device_entry.hw_version is None
    assert device_entry.identifiers == {(DOMAIN, "abcdef-123456")}
    assert device_entry.manufacturer == "amzn"
    assert device_entry.model == "KFDOWI"
    assert device_entry.name == "Amazon Fire"
    assert device_entry.sw_version == "1.42.5"

    # Test unknown/missing data
    mock_fully_kiosk.getDeviceInfo.return_value = {}
    async_fire_time_changed(hass, dt.utcnow() + UPDATE_INTERVAL)
    await hass.async_block_till_done()

    state = hass.states.get("sensor.amazon_fire_internal_storage_free_space")
    assert state
    assert state.state == STATE_UNKNOWN

    # Test failed update
    mock_fully_kiosk.getDeviceInfo.side_effect = FullyKioskError(
        "error", "status")
    async_fire_time_changed(hass, dt.utcnow() + UPDATE_INTERVAL)
    await hass.async_block_till_done()

    state = hass.states.get("sensor.amazon_fire_internal_storage_free_space")
    assert state
    assert state.state == STATE_UNAVAILABLE
Beispiel #41
0
async def time_changed(hass: HomeAssistant, seconds: int) -> None:
    """Trigger time changed."""
    next_update = dt_util.utcnow() + timedelta(seconds)
    async_fire_time_changed(hass, next_update)
    await hass.async_block_till_done()
Beispiel #42
0
async def test_setup(hass):
    """Test the general setup of the integration."""
    # Set up some mock feed entries for this test.
    mock_entry_1 = _generate_mock_feed_entry(
        "1234",
        "Description 1",
        15.5,
        (38.0, -3.0),
        event_name="Name 1",
        event_type_short="DR",
        event_type="Drought",
        alert_level="Alert Level 1",
        country="Country 1",
        attribution="Attribution 1",
        from_date=datetime.datetime(2020,
                                    1,
                                    10,
                                    8,
                                    0,
                                    tzinfo=datetime.timezone.utc),
        to_date=datetime.datetime(2020,
                                  1,
                                  20,
                                  8,
                                  0,
                                  tzinfo=datetime.timezone.utc),
        duration_in_week=1,
        population="Population 1",
        severity="Severity 1",
        vulnerability="Vulnerability 1",
    )
    mock_entry_2 = _generate_mock_feed_entry(
        "2345",
        "Description 2",
        20.5,
        (38.1, -3.1),
        event_name="Name 2",
        event_type_short="TC",
        event_type="Tropical Cyclone",
    )
    mock_entry_3 = _generate_mock_feed_entry(
        "3456",
        "Description 3",
        25.5,
        (38.2, -3.2),
        event_name="Name 3",
        event_type_short="TC",
        event_type="Tropical Cyclone",
        country="Country 2",
    )
    mock_entry_4 = _generate_mock_feed_entry("4567", "Description 4", 12.5,
                                             (38.3, -3.3))

    # Patching 'utcnow' to gain more control over the timed update.
    utcnow = dt_util.utcnow()
    with patch("homeassistant.util.dt.utcnow", return_value=utcnow), patch(
            "aio_georss_client.feed.GeoRssFeed.update") as mock_feed_update:
        mock_feed_update.return_value = "OK", [
            mock_entry_1, mock_entry_2, mock_entry_3
        ]
        assert await async_setup_component(hass, gdacs.DOMAIN, CONFIG)
        # Artificially trigger update and collect events.
        hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
        await hass.async_block_till_done()

        all_states = hass.states.async_all()
        # 3 geolocation and 1 sensor entities
        assert len(all_states) == 4
        entity_registry = await async_get_registry(hass)
        assert len(entity_registry.entities) == 4

        state = hass.states.get("geo_location.drought_name_1")
        assert state is not None
        assert state.name == "Drought: Name 1"
        assert state.attributes == {
            ATTR_EXTERNAL_ID:
            "1234",
            ATTR_LATITUDE:
            38.0,
            ATTR_LONGITUDE:
            -3.0,
            ATTR_FRIENDLY_NAME:
            "Drought: Name 1",
            ATTR_DESCRIPTION:
            "Description 1",
            ATTR_COUNTRY:
            "Country 1",
            ATTR_ATTRIBUTION:
            "Attribution 1",
            ATTR_FROM_DATE:
            datetime.datetime(2020, 1, 10, 8, 0, tzinfo=datetime.timezone.utc),
            ATTR_TO_DATE:
            datetime.datetime(2020, 1, 20, 8, 0, tzinfo=datetime.timezone.utc),
            ATTR_DURATION_IN_WEEK:
            1,
            ATTR_ALERT_LEVEL:
            "Alert Level 1",
            ATTR_POPULATION:
            "Population 1",
            ATTR_EVENT_TYPE:
            "Drought",
            ATTR_SEVERITY:
            "Severity 1",
            ATTR_VULNERABILITY:
            "Vulnerability 1",
            ATTR_UNIT_OF_MEASUREMENT:
            "km",
            ATTR_SOURCE:
            "gdacs",
            ATTR_ICON:
            "mdi:water-off",
        }
        assert float(state.state) == 15.5

        state = hass.states.get("geo_location.tropical_cyclone_name_2")
        assert state is not None
        assert state.name == "Tropical Cyclone: Name 2"
        assert state.attributes == {
            ATTR_EXTERNAL_ID: "2345",
            ATTR_LATITUDE: 38.1,
            ATTR_LONGITUDE: -3.1,
            ATTR_FRIENDLY_NAME: "Tropical Cyclone: Name 2",
            ATTR_DESCRIPTION: "Description 2",
            ATTR_EVENT_TYPE: "Tropical Cyclone",
            ATTR_UNIT_OF_MEASUREMENT: "km",
            ATTR_SOURCE: "gdacs",
            ATTR_ICON: "mdi:weather-hurricane",
        }
        assert float(state.state) == 20.5

        state = hass.states.get("geo_location.tropical_cyclone_name_3")
        assert state is not None
        assert state.name == "Tropical Cyclone: Name 3"
        assert state.attributes == {
            ATTR_EXTERNAL_ID: "3456",
            ATTR_LATITUDE: 38.2,
            ATTR_LONGITUDE: -3.2,
            ATTR_FRIENDLY_NAME: "Tropical Cyclone: Name 3",
            ATTR_DESCRIPTION: "Description 3",
            ATTR_EVENT_TYPE: "Tropical Cyclone",
            ATTR_COUNTRY: "Country 2",
            ATTR_UNIT_OF_MEASUREMENT: "km",
            ATTR_SOURCE: "gdacs",
            ATTR_ICON: "mdi:weather-hurricane",
        }
        assert float(state.state) == 25.5

        # Simulate an update - two existing, one new entry, one outdated entry
        mock_feed_update.return_value = "OK", [
            mock_entry_1, mock_entry_4, mock_entry_3
        ]
        async_fire_time_changed(hass, utcnow + DEFAULT_SCAN_INTERVAL)
        await hass.async_block_till_done()

        all_states = hass.states.async_all()
        assert len(all_states) == 4

        # Simulate an update - empty data, but successful update,
        # so no changes to entities.
        mock_feed_update.return_value = "OK_NO_DATA", None
        async_fire_time_changed(hass, utcnow + 2 * DEFAULT_SCAN_INTERVAL)
        await hass.async_block_till_done()

        all_states = hass.states.async_all()
        assert len(all_states) == 4

        # Simulate an update - empty data, removes all entities
        mock_feed_update.return_value = "ERROR", None
        async_fire_time_changed(hass, utcnow + 3 * DEFAULT_SCAN_INTERVAL)
        await hass.async_block_till_done()

        all_states = hass.states.async_all()
        assert len(all_states) == 1
        assert len(entity_registry.entities) == 1
Beispiel #43
0
async def test_action_delay(hass, calls):
    """Test action delay."""
    assert await async_setup_component(
        hass,
        automation.DOMAIN,
        {
            automation.DOMAIN: {
                "alias":
                "hello",
                "trigger": {
                    "platform": "event",
                    "event_type": "test_event"
                },
                "action": [
                    {
                        "service": "test.automation",
                        "data_template": {
                            "some":
                            "{{ trigger.platform }} - "
                            "{{ trigger.event.event_type }}"
                        },
                    },
                    {
                        "delay": {
                            "minutes": "10"
                        }
                    },
                    {
                        "service": "test.automation",
                        "data_template": {
                            "some":
                            "{{ trigger.platform }} - "
                            "{{ trigger.event.event_type }}"
                        },
                    },
                ],
            }
        },
    )

    time = dt_util.utcnow()

    with patch("homeassistant.components.automation.utcnow",
               return_value=time):
        hass.bus.async_fire("test_event")
        await hass.async_block_till_done()

    assert len(calls) == 1
    assert calls[0].data["some"] == "event - test_event"

    future = dt_util.utcnow() + timedelta(minutes=10)
    async_fire_time_changed(hass, future)
    await hass.async_block_till_done()

    assert len(calls) == 2
    assert calls[1].data["some"] == "event - test_event"

    state = hass.states.get("automation.hello")
    assert state is not None
    assert state.attributes.get("last_triggered") == time
    state = hass.states.get("group.all_automations")
    assert state is not None
    assert state.attributes.get("entity_id") == ("automation.hello", )
async def test_report_state(hass, caplog, legacy_patchable_time):
    """Test report state works."""
    hass.states.async_set("light.ceiling", "off")
    hass.states.async_set("switch.ac", "on")

    with patch.object(BASIC_CONFIG, "async_report_state_all",
                      AsyncMock()) as mock_report, patch.object(
                          report_state, "INITIAL_REPORT_DELAY", 0):
        unsub = report_state.async_enable_report_state(hass, BASIC_CONFIG)

        async_fire_time_changed(hass, utcnow())
        await hass.async_block_till_done()

    # Test that enabling report state does a report on all entities
    assert len(mock_report.mock_calls) == 1
    assert mock_report.mock_calls[0][1][0] == {
        "devices": {
            "states": {
                "light.ceiling": {
                    "on": False,
                    "online": True
                },
                "switch.ac": {
                    "on": True,
                    "online": True
                },
            }
        }
    }

    with patch.object(BASIC_CONFIG, "async_report_state_all",
                      AsyncMock()) as mock_report:
        hass.states.async_set("light.kitchen", "on")
        await hass.async_block_till_done()

    assert len(mock_report.mock_calls) == 1
    assert mock_report.mock_calls[0][1][0] == {
        "devices": {
            "states": {
                "light.kitchen": {
                    "on": True,
                    "online": True
                }
            }
        }
    }

    # Test that state changes that change something that Google doesn't care about
    # do not trigger a state report.
    with patch.object(BASIC_CONFIG, "async_report_state_all",
                      AsyncMock()) as mock_report:
        hass.states.async_set("light.kitchen", "on",
                              {"irrelevant": "should_be_ignored"})
        await hass.async_block_till_done()

    assert len(mock_report.mock_calls) == 0

    # Test that entities that we can't query don't report a state
    with patch.object(BASIC_CONFIG, "async_report_state_all", AsyncMock(
    )) as mock_report, patch(
            "homeassistant.components.google_assistant.report_state.GoogleEntity.query_serialize",
            side_effect=error.SmartHomeError("mock-error", "mock-msg"),
    ):
        hass.states.async_set("light.kitchen", "off")
        await hass.async_block_till_done()

    assert "Not reporting state for light.kitchen: mock-error"
    assert len(mock_report.mock_calls) == 0

    unsub()

    with patch.object(BASIC_CONFIG, "async_report_state_all",
                      AsyncMock()) as mock_report:
        hass.states.async_set("light.kitchen", "on")
        await hass.async_block_till_done()

    assert len(mock_report.mock_calls) == 0
Beispiel #45
0
async def test_bind_failure_skips_adapter(hass, caplog):
    """Test that an adapter with a bind failure is skipped."""
    mock_get_ssdp = {
        "mock-domain": [{
            ssdp.ATTR_UPNP_DEVICE_TYPE: "ABC",
        }]
    }
    create_args = []
    search_args = []

    @callback
    def _callback(*args):
        nonlocal search_args
        search_args.append(args)
        pass

    def _generate_failing_ssdp_listener(*args, **kwargs):
        create_args.append([args, kwargs])
        listener = SSDPListener(*args, **kwargs)

        async def _async_callback(*_):
            if kwargs["source_ip"] == IPv6Address("2001:db8::"):
                raise OSError
            pass

        listener.async_start = _async_callback
        listener.async_search = _callback
        return listener

    with patch(
            "homeassistant.components.ssdp.async_get_ssdp",
            return_value=mock_get_ssdp,
    ), patch(
            "homeassistant.components.ssdp.SSDPListener",
            new=_generate_failing_ssdp_listener,
    ), patch(
            "homeassistant.components.ssdp.network.async_get_adapters",
            return_value=_ADAPTERS_WITH_MANUAL_CONFIG,
    ):
        assert await async_setup_component(hass, ssdp.DOMAIN,
                                           {ssdp.DOMAIN: {}})
        await hass.async_block_till_done()
        hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
        await hass.async_block_till_done()

    argset = set()
    for argmap in create_args:
        argset.add((argmap[1].get("source_ip"), argmap[1].get("target_ip")))

    assert argset == {
        (IPv6Address("2001:db8::"), None),
        (IPv4Address("192.168.1.5"), None),
    }
    assert "Failed to setup listener for" in caplog.text

    async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=200))
    await hass.async_block_till_done()
    assert set(search_args) == {
        (),
        ((
            "255.255.255.255",
            1900,
        ), ),
    }
Beispiel #46
0
async def base_test(
    hass,
    config_device,
    device_name,
    entity_domain,
    array_name_discovery,
    array_name_old_config,
    register_words,
    expected,
    method_discovery=False,
    check_config_only=False,
    config_modbus=None,
    scan_interval=None,
    expect_init_to_fail=False,
    expect_setup_to_fail=False,
):
    """Run test on device for given config."""

    if config_modbus is None:
        config_modbus = {
            DOMAIN: {
                CONF_NAME: DEFAULT_HUB,
                CONF_TYPE: "tcp",
                CONF_HOST: "modbusTest",
                CONF_PORT: 5001,
            },
        }

    mock_sync = mock.MagicMock()
    with mock.patch(
        "homeassistant.components.modbus.modbus.ModbusTcpClient", return_value=mock_sync
    ), mock.patch(
        "homeassistant.components.modbus.modbus.ModbusSerialClient",
        return_value=mock_sync,
    ), mock.patch(
        "homeassistant.components.modbus.modbus.ModbusUdpClient", return_value=mock_sync
    ):

        # Setup inputs for the sensor
        if register_words is None:
            mock_sync.read_coils.side_effect = ModbusException("fail read_coils")
            mock_sync.read_discrete_inputs.side_effect = ModbusException(
                "fail read_coils"
            )
            mock_sync.read_input_registers.side_effect = ModbusException(
                "fail read_coils"
            )
            mock_sync.read_holding_registers.side_effect = ModbusException(
                "fail read_coils"
            )
        else:
            read_result = ReadResult(register_words)
            mock_sync.read_coils.return_value = read_result
            mock_sync.read_discrete_inputs.return_value = read_result
            mock_sync.read_input_registers.return_value = read_result
            mock_sync.read_holding_registers.return_value = read_result

        # mock timer and add old/new config
        now = dt_util.utcnow()
        with mock.patch("homeassistant.helpers.event.dt_util.utcnow", return_value=now):
            if method_discovery and config_device is not None:
                # setup modbus which in turn does setup for the devices
                config_modbus[DOMAIN].update(
                    {array_name_discovery: [{**config_device}]}
                )
                config_device = None
            assert (
                await async_setup_component(hass, DOMAIN, config_modbus)
                is not expect_setup_to_fail
            )
            await hass.async_block_till_done()

            # setup platform old style
            if config_device is not None:
                config_device = {
                    entity_domain: {
                        CONF_PLATFORM: DOMAIN,
                        array_name_old_config: [
                            {
                                **config_device,
                            }
                        ],
                    }
                }
                if scan_interval is not None:
                    config_device[entity_domain][CONF_SCAN_INTERVAL] = scan_interval
                assert await async_setup_component(hass, entity_domain, config_device)
                await hass.async_block_till_done()

        assert (DOMAIN in hass.config.components) is not expect_setup_to_fail
        if config_device is not None:
            entity_id = f"{entity_domain}.{device_name}"
            device = hass.states.get(entity_id)

            if expect_init_to_fail:
                assert device is None
            elif device is None:
                pytest.fail("CONFIG failed, see output")
        if check_config_only:
            return

        # Trigger update call with time_changed event
        now = now + timedelta(seconds=scan_interval + 60)
        with mock.patch("homeassistant.helpers.event.dt_util.utcnow", return_value=now):
            async_fire_time_changed(hass, now)
            await hass.async_block_till_done()

        # Check state
        entity_id = f"{entity_domain}.{device_name}"
        return hass.states.get(entity_id).state
Beispiel #47
0
async def test_scan_second_hit(hass, aioclient_mock, caplog):
    """Test matching on second scan."""
    aioclient_mock.get(
        "http://1.1.1.1",
        text="""
<root>
  <device>
    <deviceType>Paulus</deviceType>
  </device>
</root>
    """,
    )

    mock_ssdp_response = CaseInsensitiveDict(
        **{
            "ST": "mock-st",
            "LOCATION": "http://1.1.1.1",
            "USN":
            "uuid:TIVRTLSR7ANF-D6E-1557809135086-RETAIL::urn:mdx-netflix-com:service:target:3",
            "SERVER": "mock-server",
            "EXT": "",
        })
    mock_get_ssdp = {"mock-domain": [{"st": "mock-st"}]}
    integration_callbacks = []

    @callback
    def _async_integration_callbacks(info):
        integration_callbacks.append(info)

    def _generate_fake_ssdp_listener(*args, **kwargs):
        listener = SSDPListener(*args, **kwargs)

        async def _async_callback(*_):
            pass

        @callback
        def _callback(*_):
            hass.async_create_task(listener.async_callback(mock_ssdp_response))

        listener.async_start = _async_callback
        listener.async_search = _callback
        return listener

    with patch(
            "homeassistant.components.ssdp.async_get_ssdp",
            return_value=mock_get_ssdp,
    ), patch(
            "homeassistant.components.ssdp.SSDPListener",
            new=_generate_fake_ssdp_listener,
    ), patch.object(hass.config_entries.flow,
                    "async_init",
                    return_value=mock_coro()) as mock_init:
        assert await async_setup_component(hass, ssdp.DOMAIN,
                                           {ssdp.DOMAIN: {}})
        await hass.async_block_till_done()
        remove = ssdp.async_register_callback(
            hass,
            _async_integration_callbacks,
            {"st": "mock-st"},
        )
        hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
        await hass.async_block_till_done()
        async_fire_time_changed(hass,
                                dt_util.utcnow() + timedelta(seconds=200))
        await hass.async_block_till_done()
        async_fire_time_changed(hass,
                                dt_util.utcnow() + timedelta(seconds=200))
        await hass.async_block_till_done()
        remove()
        async_fire_time_changed(hass,
                                dt_util.utcnow() + timedelta(seconds=200))
        await hass.async_block_till_done()

    assert len(integration_callbacks) == 4
    assert integration_callbacks[0] == {
        ssdp.ATTR_UPNP_DEVICE_TYPE: "Paulus",
        ssdp.ATTR_SSDP_EXT: "",
        ssdp.ATTR_SSDP_LOCATION: "http://1.1.1.1",
        ssdp.ATTR_SSDP_SERVER: "mock-server",
        ssdp.ATTR_SSDP_ST: "mock-st",
        ssdp.ATTR_SSDP_USN:
        "uuid:TIVRTLSR7ANF-D6E-1557809135086-RETAIL::urn:mdx-netflix-com:service:target:3",
        ssdp.ATTR_UPNP_UDN: "uuid:TIVRTLSR7ANF-D6E-1557809135086-RETAIL",
    }
    assert len(mock_init.mock_calls) == 1
    assert mock_init.mock_calls[0][1][0] == "mock-domain"
    assert mock_init.mock_calls[0][2]["context"] == {
        "source": config_entries.SOURCE_SSDP
    }
    assert mock_init.mock_calls[0][2]["data"] == {
        ssdp.ATTR_UPNP_DEVICE_TYPE: "Paulus",
        ssdp.ATTR_SSDP_ST: "mock-st",
        ssdp.ATTR_SSDP_LOCATION: "http://1.1.1.1",
        ssdp.ATTR_SSDP_SERVER: "mock-server",
        ssdp.ATTR_SSDP_EXT: "",
        ssdp.ATTR_SSDP_USN:
        "uuid:TIVRTLSR7ANF-D6E-1557809135086-RETAIL::urn:mdx-netflix-com:service:target:3",
        ssdp.ATTR_UPNP_UDN: "uuid:TIVRTLSR7ANF-D6E-1557809135086-RETAIL",
    }
    assert "Failed to fetch ssdp data" not in caplog.text
    udn_discovery_info = ssdp.async_get_discovery_info_by_st(hass, "mock-st")
    discovery_info = udn_discovery_info[0]
    assert discovery_info[ssdp.ATTR_SSDP_LOCATION] == "http://1.1.1.1"
    assert discovery_info[ssdp.ATTR_SSDP_ST] == "mock-st"
    assert (discovery_info[ssdp.ATTR_UPNP_UDN] ==
            "uuid:TIVRTLSR7ANF-D6E-1557809135086-RETAIL")
    assert (
        discovery_info[ssdp.ATTR_SSDP_USN] ==
        "uuid:TIVRTLSR7ANF-D6E-1557809135086-RETAIL::urn:mdx-netflix-com:service:target:3"
    )

    st_discovery_info = ssdp.async_get_discovery_info_by_udn(
        hass, "uuid:TIVRTLSR7ANF-D6E-1557809135086-RETAIL")
    discovery_info = st_discovery_info[0]
    assert discovery_info[ssdp.ATTR_SSDP_LOCATION] == "http://1.1.1.1"
    assert discovery_info[ssdp.ATTR_SSDP_ST] == "mock-st"
    assert (discovery_info[ssdp.ATTR_UPNP_UDN] ==
            "uuid:TIVRTLSR7ANF-D6E-1557809135086-RETAIL")
    assert (
        discovery_info[ssdp.ATTR_SSDP_USN] ==
        "uuid:TIVRTLSR7ANF-D6E-1557809135086-RETAIL::urn:mdx-netflix-com:service:target:3"
    )

    discovery_info = ssdp.async_get_discovery_info_by_udn_st(
        hass, "uuid:TIVRTLSR7ANF-D6E-1557809135086-RETAIL", "mock-st")
    assert discovery_info[ssdp.ATTR_SSDP_LOCATION] == "http://1.1.1.1"
    assert discovery_info[ssdp.ATTR_SSDP_ST] == "mock-st"
    assert (discovery_info[ssdp.ATTR_UPNP_UDN] ==
            "uuid:TIVRTLSR7ANF-D6E-1557809135086-RETAIL")
    assert (
        discovery_info[ssdp.ATTR_SSDP_USN] ==
        "uuid:TIVRTLSR7ANF-D6E-1557809135086-RETAIL::urn:mdx-netflix-com:service:target:3"
    )

    assert ssdp.async_get_discovery_info_by_udn_st(hass, "wrong",
                                                   "mock-st") is None
Beispiel #48
0
async def test_periodic_task_clock_rollback(hass):
    """Test periodic tasks with the time rolling backwards."""
    specific_runs = []

    unsub = async_track_utc_time_change(hass,
                                        lambda x: specific_runs.append(1),
                                        hour="/2",
                                        minute=0,
                                        second=0)

    async_fire_time_changed(hass, datetime(2014, 5, 24, 22, 0, 0))
    await hass.async_block_till_done()
    assert len(specific_runs) == 1

    async_fire_time_changed(hass, datetime(2014, 5, 24, 23, 0, 0))
    await hass.async_block_till_done()
    assert len(specific_runs) == 1

    async_fire_time_changed(hass, datetime(2014, 5, 24, 22, 0, 0))
    await hass.async_block_till_done()
    assert len(specific_runs) == 2

    async_fire_time_changed(hass, datetime(2014, 5, 24, 0, 0, 0))
    await hass.async_block_till_done()
    assert len(specific_runs) == 3

    async_fire_time_changed(hass, datetime(2014, 5, 25, 2, 0, 0))
    await hass.async_block_till_done()
    assert len(specific_runs) == 4

    unsub()

    async_fire_time_changed(hass, datetime(2014, 5, 25, 2, 0, 0))
    await hass.async_block_till_done()
    assert len(specific_runs) == 4
Beispiel #49
0
async def test_unsolicited_ssdp_registered_callback(hass, aioclient_mock,
                                                    caplog):
    """Test matching based on callback can handle unsolicited ssdp traffic without st."""
    aioclient_mock.get(
        "http://10.6.9.12:1400/xml/device_description.xml",
        text="""
<root>
  <device>
    <deviceType>Paulus</deviceType>
  </device>
</root>
    """,
    )
    mock_ssdp_response = {
        "location": "http://10.6.9.12:1400/xml/device_description.xml",
        "nt": "uuid:RINCON_1111BB963FD801400",
        "nts": "ssdp:alive",
        "server": "Linux UPnP/1.0 Sonos/63.2-88230 (ZPS12)",
        "usn": "uuid:RINCON_1111BB963FD801400",
        "x-rincon-household": "Sonos_dfjfkdghjhkjfhkdjfhkd",
        "x-rincon-bootseq": "250",
        "bootid.upnp.org": "250",
        "x-rincon-wifimode": "0",
        "x-rincon-variant": "1",
        "household.smartspeaker.audio": "Sonos_v3294823948542543534",
    }
    integration_callbacks = []

    @callback
    def _async_integration_callbacks(info):
        integration_callbacks.append(info)

    def _generate_fake_ssdp_listener(*args, **kwargs):
        listener = SSDPListener(*args, **kwargs)

        async def _async_callback(*_):
            await listener.async_callback(mock_ssdp_response)

        @callback
        def _callback(*_):
            hass.async_create_task(listener.async_callback(mock_ssdp_response))

        listener.async_start = _async_callback
        listener.async_search = _callback
        return listener

    with patch(
            "homeassistant.components.ssdp.SSDPListener",
            new=_generate_fake_ssdp_listener,
    ):
        hass.state = CoreState.stopped
        assert await async_setup_component(hass, ssdp.DOMAIN,
                                           {ssdp.DOMAIN: {}})
        await hass.async_block_till_done()
        ssdp.async_register_callback(
            hass,
            _async_integration_callbacks,
            {
                "nts": "ssdp:alive",
                "x-rincon-bootseq": MATCH_ALL
            },
        )
        await hass.async_block_till_done()
        async_fire_time_changed(hass,
                                dt_util.utcnow() + timedelta(seconds=200))
        await hass.async_block_till_done()
        hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
        hass.state = CoreState.running
        await hass.async_block_till_done()
        async_fire_time_changed(hass,
                                dt_util.utcnow() + timedelta(seconds=200))
        await hass.async_block_till_done()
        assert hass.state == CoreState.running

    assert (len(integration_callbacks) == 4
            )  # unsolicited callbacks without st are not cached
    assert integration_callbacks[0] == {
        "UDN": "uuid:RINCON_1111BB963FD801400",
        "bootid.upnp.org": "250",
        "deviceType": "Paulus",
        "household.smartspeaker.audio": "Sonos_v3294823948542543534",
        "nt": "uuid:RINCON_1111BB963FD801400",
        "nts": "ssdp:alive",
        "ssdp_location": "http://10.6.9.12:1400/xml/device_description.xml",
        "ssdp_server": "Linux UPnP/1.0 Sonos/63.2-88230 (ZPS12)",
        "ssdp_usn": "uuid:RINCON_1111BB963FD801400",
        "x-rincon-bootseq": "250",
        "x-rincon-household": "Sonos_dfjfkdghjhkjfhkdjfhkd",
        "x-rincon-variant": "1",
        "x-rincon-wifimode": "0",
    }
    assert "Failed to callback info" not in caplog.text
Beispiel #50
0
async def test_periodic_task_leaving_dst(hass):
    """Test periodic task behavior when leaving dst."""
    timezone = dt_util.get_time_zone("Europe/Vienna")
    dt_util.set_default_time_zone(timezone)
    specific_runs = []

    now = dt_util.utcnow()

    time_that_will_not_match_right_away = timezone.localize(datetime(
        now.year + 1, 10, 28, 2, 28, 0),
                                                            is_dst=True)

    with patch("homeassistant.util.dt.utcnow",
               return_value=time_that_will_not_match_right_away):
        unsub = async_track_time_change(
            hass,
            callback(lambda x: specific_runs.append(x)),
            hour=2,
            minute=30,
            second=0,
        )

    async_fire_time_changed(
        hass,
        timezone.localize(datetime(now.year + 1, 10, 28, 2, 5, 0, 999999),
                          is_dst=False),
    )
    await hass.async_block_till_done()
    assert len(specific_runs) == 0

    async_fire_time_changed(
        hass,
        timezone.localize(datetime(now.year + 1, 10, 28, 2, 55, 0, 999999),
                          is_dst=False),
    )
    await hass.async_block_till_done()
    assert len(specific_runs) == 1

    async_fire_time_changed(
        hass,
        timezone.localize(datetime(now.year + 2, 10, 28, 2, 45, 0, 999999),
                          is_dst=True),
    )
    await hass.async_block_till_done()
    assert len(specific_runs) == 2

    async_fire_time_changed(
        hass,
        timezone.localize(datetime(now.year + 2, 10, 28, 2, 55, 0, 999999),
                          is_dst=True),
    )
    await hass.async_block_till_done()
    assert len(specific_runs) == 2

    async_fire_time_changed(
        hass,
        timezone.localize(datetime(now.year + 2, 10, 28, 2, 55, 0, 999999),
                          is_dst=True),
    )
    await hass.async_block_till_done()
    assert len(specific_runs) == 2

    unsub()
Beispiel #51
0
async def test_scan_with_registered_callback(hass, aioclient_mock, caplog):
    """Test matching based on callback."""
    aioclient_mock.get(
        "http://1.1.1.1",
        text="""
<root>
  <device>
    <deviceType>Paulus</deviceType>
  </device>
</root>
    """,
    )
    mock_ssdp_response = {
        "st": "mock-st",
        "location": "http://1.1.1.1",
        "usn":
        "uuid:TIVRTLSR7ANF-D6E-1557809135086-RETAIL::urn:mdx-netflix-com:service:target:3",
        "server": "mock-server",
        "x-rincon-bootseq": "55",
        "ext": "",
    }
    not_matching_integration_callbacks = []
    integration_match_all_callbacks = []
    integration_match_all_not_present_callbacks = []
    integration_callbacks = []
    integration_callbacks_from_cache = []
    match_any_callbacks = []

    @callback
    def _async_exception_callbacks(info):
        raise ValueError

    @callback
    def _async_integration_callbacks(info):
        integration_callbacks.append(info)

    @callback
    def _async_integration_match_all_callbacks(info):
        integration_match_all_callbacks.append(info)

    @callback
    def _async_integration_match_all_not_present_callbacks(info):
        integration_match_all_not_present_callbacks.append(info)

    @callback
    def _async_integration_callbacks_from_cache(info):
        integration_callbacks_from_cache.append(info)

    @callback
    def _async_not_matching_integration_callbacks(info):
        not_matching_integration_callbacks.append(info)

    @callback
    def _async_match_any_callbacks(info):
        match_any_callbacks.append(info)

    def _generate_fake_ssdp_listener(*args, **kwargs):
        listener = SSDPListener(*args, **kwargs)

        async def _async_callback(*_):
            await listener.async_callback(mock_ssdp_response)

        @callback
        def _callback(*_):
            hass.async_create_task(listener.async_callback(mock_ssdp_response))

        listener.async_start = _async_callback
        listener.async_search = _callback
        return listener

    with patch(
            "homeassistant.components.ssdp.SSDPListener",
            new=_generate_fake_ssdp_listener,
    ):
        hass.state = CoreState.stopped
        assert await async_setup_component(hass, ssdp.DOMAIN,
                                           {ssdp.DOMAIN: {}})
        await hass.async_block_till_done()
        ssdp.async_register_callback(hass, _async_exception_callbacks, {})
        ssdp.async_register_callback(
            hass,
            _async_integration_callbacks,
            {"st": "mock-st"},
        )
        ssdp.async_register_callback(
            hass,
            _async_integration_match_all_callbacks,
            {"x-rincon-bootseq": MATCH_ALL},
        )
        ssdp.async_register_callback(
            hass,
            _async_integration_match_all_not_present_callbacks,
            {"x-not-there": MATCH_ALL},
        )
        ssdp.async_register_callback(
            hass,
            _async_not_matching_integration_callbacks,
            {"st": "not-match-mock-st"},
        )
        ssdp.async_register_callback(
            hass,
            _async_match_any_callbacks,
        )
        await hass.async_block_till_done()
        async_fire_time_changed(hass,
                                dt_util.utcnow() + timedelta(seconds=200))
        ssdp.async_register_callback(
            hass,
            _async_integration_callbacks_from_cache,
            {"st": "mock-st"},
        )
        await hass.async_block_till_done()
        hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
        hass.state = CoreState.running
        await hass.async_block_till_done()
        async_fire_time_changed(hass,
                                dt_util.utcnow() + timedelta(seconds=200))
        await hass.async_block_till_done()
        assert hass.state == CoreState.running

    assert len(integration_callbacks) == 5
    assert len(integration_callbacks_from_cache) == 5
    assert len(integration_match_all_callbacks) == 5
    assert len(integration_match_all_not_present_callbacks) == 0
    assert len(match_any_callbacks) == 5
    assert len(not_matching_integration_callbacks) == 0
    assert integration_callbacks[0] == {
        ssdp.ATTR_UPNP_DEVICE_TYPE: "Paulus",
        ssdp.ATTR_SSDP_EXT: "",
        ssdp.ATTR_SSDP_LOCATION: "http://1.1.1.1",
        ssdp.ATTR_SSDP_SERVER: "mock-server",
        ssdp.ATTR_SSDP_ST: "mock-st",
        ssdp.ATTR_SSDP_USN:
        "uuid:TIVRTLSR7ANF-D6E-1557809135086-RETAIL::urn:mdx-netflix-com:service:target:3",
        ssdp.ATTR_UPNP_UDN: "uuid:TIVRTLSR7ANF-D6E-1557809135086-RETAIL",
        "x-rincon-bootseq": "55",
    }
    assert "Failed to callback info" in caplog.text
Beispiel #52
0
async def test_track_sunset(hass, legacy_patchable_time):
    """Test track the sunset."""
    latitude = 32.87336
    longitude = 117.22743

    # Setup sun component
    hass.config.latitude = latitude
    hass.config.longitude = longitude
    assert await async_setup_component(hass, sun.DOMAIN,
                                       {sun.DOMAIN: {
                                           sun.CONF_ELEVATION: 0
                                       }})

    # Get next sunrise/sunset
    astral = Astral()
    utc_now = datetime(2014, 5, 24, 12, 0, 0, tzinfo=dt_util.UTC)
    utc_today = utc_now.date()

    mod = -1
    while True:
        next_setting = astral.sunset_utc(utc_today + timedelta(days=mod),
                                         latitude, longitude)
        if next_setting > utc_now:
            break
        mod += 1

    # Track sunset
    runs = []
    with patch("homeassistant.util.dt.utcnow", return_value=utc_now):
        unsub = async_track_sunset(hass, callback(lambda: runs.append(1)))

    offset_runs = []
    offset = timedelta(minutes=30)
    with patch("homeassistant.util.dt.utcnow", return_value=utc_now):
        unsub2 = async_track_sunset(hass,
                                    callback(lambda: offset_runs.append(1)),
                                    offset)

    # Run tests
    async_fire_time_changed(hass, next_setting - offset)
    await hass.async_block_till_done()
    assert len(runs) == 0
    assert len(offset_runs) == 0

    async_fire_time_changed(hass, next_setting)
    await hass.async_block_till_done()
    assert len(runs) == 1
    assert len(offset_runs) == 0

    async_fire_time_changed(hass, next_setting + offset)
    await hass.async_block_till_done()
    assert len(runs) == 1
    assert len(offset_runs) == 1

    unsub()
    unsub2()

    async_fire_time_changed(hass, next_setting + offset)
    await hass.async_block_till_done()
    assert len(runs) == 1
    assert len(offset_runs) == 1
async def test_light_update(hass, mock_light):
    """Test KulerSkyLight update."""
    utcnow = dt_util.utcnow()

    state = hass.states.get("light.bedroom")
    assert state.state == STATE_OFF
    assert dict(state.attributes) == {
        ATTR_FRIENDLY_NAME: "Bedroom",
        ATTR_SUPPORTED_COLOR_MODES: [COLOR_MODE_RGBW],
        ATTR_SUPPORTED_FEATURES: 0,
    }

    # Test an exception during discovery
    mock_light.get_color.side_effect = pykulersky.PykulerskyException("TEST")
    utcnow = utcnow + SCAN_INTERVAL
    async_fire_time_changed(hass, utcnow)
    await hass.async_block_till_done()

    state = hass.states.get("light.bedroom")
    assert state.state == STATE_UNAVAILABLE
    assert dict(state.attributes) == {
        ATTR_FRIENDLY_NAME: "Bedroom",
        ATTR_SUPPORTED_COLOR_MODES: [COLOR_MODE_RGBW],
        ATTR_SUPPORTED_FEATURES: 0,
    }

    mock_light.get_color.side_effect = None
    mock_light.get_color.return_value = (80, 160, 255, 0)
    utcnow = utcnow + SCAN_INTERVAL
    async_fire_time_changed(hass, utcnow)
    await hass.async_block_till_done()

    state = hass.states.get("light.bedroom")
    assert state.state == STATE_ON
    assert dict(state.attributes) == {
        ATTR_FRIENDLY_NAME: "Bedroom",
        ATTR_SUPPORTED_COLOR_MODES: [COLOR_MODE_RGBW],
        ATTR_SUPPORTED_FEATURES: 0,
        ATTR_COLOR_MODE: COLOR_MODE_RGBW,
        ATTR_BRIGHTNESS: 255,
        ATTR_HS_COLOR: (approx(212.571), approx(68.627)),
        ATTR_RGB_COLOR: (80, 160, 255),
        ATTR_RGBW_COLOR: (80, 160, 255, 0),
        ATTR_XY_COLOR: (approx(0.17), approx(0.193)),
    }

    mock_light.get_color.side_effect = None
    mock_light.get_color.return_value = (80, 160, 200, 255)
    utcnow = utcnow + SCAN_INTERVAL
    async_fire_time_changed(hass, utcnow)
    await hass.async_block_till_done()

    state = hass.states.get("light.bedroom")
    assert state.state == STATE_ON
    assert dict(state.attributes) == {
        ATTR_FRIENDLY_NAME: "Bedroom",
        ATTR_SUPPORTED_COLOR_MODES: [COLOR_MODE_RGBW],
        ATTR_SUPPORTED_FEATURES: 0,
        ATTR_COLOR_MODE: COLOR_MODE_RGBW,
        ATTR_BRIGHTNESS: 255,
        ATTR_HS_COLOR: (approx(199.701), approx(26.275)),
        ATTR_RGB_COLOR: (188, 233, 255),
        ATTR_RGBW_COLOR: (80, 160, 200, 255),
        ATTR_XY_COLOR: (approx(0.259), approx(0.306)),
    }

    mock_light.get_color.side_effect = None
    mock_light.get_color.return_value = (80, 160, 200, 240)
    utcnow = utcnow + SCAN_INTERVAL
    async_fire_time_changed(hass, utcnow)
    await hass.async_block_till_done()

    state = hass.states.get("light.bedroom")
    assert state.state == STATE_ON
    assert dict(state.attributes) == {
        ATTR_FRIENDLY_NAME: "Bedroom",
        ATTR_SUPPORTED_COLOR_MODES: [COLOR_MODE_RGBW],
        ATTR_SUPPORTED_FEATURES: 0,
        ATTR_COLOR_MODE: COLOR_MODE_RGBW,
        ATTR_BRIGHTNESS: 240,
        ATTR_HS_COLOR: (approx(200.0), approx(27.059)),
        ATTR_RGB_COLOR: (186, 232, 255),
        ATTR_RGBW_COLOR: (85, 170, 212, 255),
        ATTR_XY_COLOR: (approx(0.257), approx(0.305)),
    }
async def test_smart_strip_custom_random_effect(hass: HomeAssistant) -> None:
    """Test smart strip custom random effects."""
    already_migrated_config_entry = MockConfigEntry(domain=DOMAIN,
                                                    data={},
                                                    unique_id=MAC_ADDRESS)
    already_migrated_config_entry.add_to_hass(hass)
    strip = _mocked_smart_light_strip()

    with _patch_discovery(device=strip), _patch_single_discovery(device=strip):
        await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
        await hass.async_block_till_done()

    entity_id = "light.my_bulb"

    state = hass.states.get(entity_id)
    assert state.state == STATE_ON

    await hass.services.async_call(
        DOMAIN,
        "random_effect",
        {
            ATTR_ENTITY_ID: entity_id,
            "init_states": [340, 20, 50],
            "backgrounds": [[340, 20, 50], [20, 50, 50], [0, 100, 50]],
        },
        blocking=True,
    )
    strip.set_custom_effect.assert_called_once_with({
        "custom":
        1,
        "id":
        "yMwcNpLxijmoKamskHCvvravpbnIqAIN",
        "brightness":
        100,
        "name":
        "Custom",
        "segments": [0],
        "expansion_strategy":
        1,
        "enable":
        1,
        "duration":
        0,
        "transition":
        0,
        "type":
        "random",
        "init_states": [[340, 20, 50]],
        "random_seed":
        100,
        "backgrounds": [(340, 20, 50), (20, 50, 50), (0, 100, 50)],
    })
    strip.set_custom_effect.reset_mock()

    strip.effect = {
        "custom": 1,
        "id": "yMwcNpLxijmoKamskHCvvravpbnIqAIN",
        "brightness": 100,
        "name": "Custom",
        "enable": 1,
    }
    async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10))
    await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state.state == STATE_ON

    strip.is_off = True
    strip.is_on = False
    strip.effect = {
        "custom": 1,
        "id": "yMwcNpLxijmoKamskHCvvravpbnIqAIN",
        "brightness": 100,
        "name": "Custom",
        "enable": 0,
    }
    async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=20))
    await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state.state == STATE_OFF
    assert ATTR_EFFECT not in state.attributes

    await hass.services.async_call(
        LIGHT_DOMAIN,
        "turn_on",
        {ATTR_ENTITY_ID: entity_id},
        blocking=True,
    )
    strip.set_custom_effect.assert_called_once_with({
        "custom":
        1,
        "id":
        "yMwcNpLxijmoKamskHCvvravpbnIqAIN",
        "brightness":
        100,
        "name":
        "Custom",
        "segments": [0],
        "expansion_strategy":
        1,
        "enable":
        1,
        "duration":
        0,
        "transition":
        0,
        "type":
        "random",
        "init_states": [[340, 20, 50]],
        "random_seed":
        100,
        "backgrounds": [(340, 20, 50), (20, 50, 50), (0, 100, 50)],
    })
    strip.set_custom_effect.reset_mock()

    await hass.services.async_call(
        DOMAIN,
        "random_effect",
        {
            ATTR_ENTITY_ID: entity_id,
            "init_states": [340, 20, 50],
            "backgrounds": [[340, 20, 50], [20, 50, 50], [0, 100, 50]],
            "random_seed": 50,
            "brightness": 80,
            "duration": 5000,
            "transition": 2000,
            "fadeoff": 3000,
            "hue_range": [0, 360],
            "saturation_range": [0, 100],
            "brightness_range": [0, 100],
            "transition_range": [2000, 3000],
        },
    )
    await hass.async_block_till_done()

    strip.set_custom_effect.assert_called_once_with({
        "custom":
        1,
        "id":
        "yMwcNpLxijmoKamskHCvvravpbnIqAIN",
        "brightness":
        80,
        "name":
        "Custom",
        "segments": [0],
        "expansion_strategy":
        1,
        "enable":
        1,
        "duration":
        5000,
        "transition":
        0,
        "type":
        "random",
        "init_states": [[340, 20, 50]],
        "random_seed":
        50,
        "backgrounds": [(340, 20, 50), (20, 50, 50), (0, 100, 50)],
        "fadeoff":
        3000,
        "hue_range": [0, 360],
        "saturation_range": [0, 100],
        "brightness_range": [0, 100],
        "transition_range": [2000, 3000],
    })
    strip.set_custom_effect.reset_mock()
async def test_setup(hass):
    """Test the general setup of the platform."""
    # Set up some mock feed entries for this test.
    mock_entry_1 = _generate_mock_feed_entry(
        "1234",
        "Title 1",
        15.5,
        (-31.0, 150.0),
        category="Category 1",
        location="Location 1",
        attribution="Attribution 1",
        publication_date=datetime.datetime(2018,
                                           9,
                                           22,
                                           8,
                                           0,
                                           tzinfo=datetime.timezone.utc),
        council_area="Council Area 1",
        status="Status 1",
        entry_type="Type 1",
        size="Size 1",
        responsible_agency="Agency 1",
    )
    mock_entry_2 = _generate_mock_feed_entry("2345",
                                             "Title 2",
                                             20.5, (-31.1, 150.1),
                                             fire=False)
    mock_entry_3 = _generate_mock_feed_entry("3456", "Title 3", 25.5,
                                             (-31.2, 150.2))
    mock_entry_4 = _generate_mock_feed_entry("4567", "Title 4", 12.5,
                                             (-31.3, 150.3))

    # Patching 'utcnow' to gain more control over the timed update.
    utcnow = dt_util.utcnow()
    with patch("homeassistant.util.dt.utcnow", return_value=utcnow), patch(
            "aio_geojson_client.feed.GeoJsonFeed.update") as mock_feed_update:
        mock_feed_update.return_value = (
            "OK",
            [mock_entry_1, mock_entry_2, mock_entry_3],
        )
        with assert_setup_component(1, geo_location.DOMAIN):
            assert await async_setup_component(hass, geo_location.DOMAIN,
                                               CONFIG)
            await hass.async_block_till_done()
            # Artificially trigger update.
            hass.bus.async_fire(EVENT_HOMEASSISTANT_START)
            # Collect events.
            await hass.async_block_till_done()

            all_states = hass.states.async_all()
            assert len(all_states) == 3

            state = hass.states.get("geo_location.title_1")
            assert state is not None
            assert state.name == "Title 1"
            assert state.attributes == {
                ATTR_EXTERNAL_ID:
                "1234",
                ATTR_LATITUDE:
                -31.0,
                ATTR_LONGITUDE:
                150.0,
                ATTR_FRIENDLY_NAME:
                "Title 1",
                ATTR_CATEGORY:
                "Category 1",
                ATTR_LOCATION:
                "Location 1",
                ATTR_ATTRIBUTION:
                "Attribution 1",
                ATTR_PUBLICATION_DATE:
                datetime.datetime(2018,
                                  9,
                                  22,
                                  8,
                                  0,
                                  tzinfo=datetime.timezone.utc),
                ATTR_FIRE:
                True,
                ATTR_COUNCIL_AREA:
                "Council Area 1",
                ATTR_STATUS:
                "Status 1",
                ATTR_TYPE:
                "Type 1",
                ATTR_SIZE:
                "Size 1",
                ATTR_RESPONSIBLE_AGENCY:
                "Agency 1",
                ATTR_UNIT_OF_MEASUREMENT:
                LENGTH_KILOMETERS,
                ATTR_SOURCE:
                "nsw_rural_fire_service_feed",
                ATTR_ICON:
                "mdi:fire",
            }
            assert round(abs(float(state.state) - 15.5), 7) == 0

            state = hass.states.get("geo_location.title_2")
            assert state is not None
            assert state.name == "Title 2"
            assert state.attributes == {
                ATTR_EXTERNAL_ID: "2345",
                ATTR_LATITUDE: -31.1,
                ATTR_LONGITUDE: 150.1,
                ATTR_FRIENDLY_NAME: "Title 2",
                ATTR_FIRE: False,
                ATTR_UNIT_OF_MEASUREMENT: LENGTH_KILOMETERS,
                ATTR_SOURCE: "nsw_rural_fire_service_feed",
                ATTR_ICON: "mdi:alarm-light",
            }
            assert round(abs(float(state.state) - 20.5), 7) == 0

            state = hass.states.get("geo_location.title_3")
            assert state is not None
            assert state.name == "Title 3"
            assert state.attributes == {
                ATTR_EXTERNAL_ID: "3456",
                ATTR_LATITUDE: -31.2,
                ATTR_LONGITUDE: 150.2,
                ATTR_FRIENDLY_NAME: "Title 3",
                ATTR_FIRE: True,
                ATTR_UNIT_OF_MEASUREMENT: LENGTH_KILOMETERS,
                ATTR_SOURCE: "nsw_rural_fire_service_feed",
                ATTR_ICON: "mdi:fire",
            }
            assert round(abs(float(state.state) - 25.5), 7) == 0

            # Simulate an update - one existing, one new entry,
            # one outdated entry
            mock_feed_update.return_value = (
                "OK",
                [mock_entry_1, mock_entry_4, mock_entry_3],
            )
            async_fire_time_changed(hass, utcnow + SCAN_INTERVAL)
            await hass.async_block_till_done()

            all_states = hass.states.async_all()
            assert len(all_states) == 3

            # Simulate an update - empty data, but successful update,
            # so no changes to entities.
            mock_feed_update.return_value = "OK_NO_DATA", None
            async_fire_time_changed(hass, utcnow + 2 * SCAN_INTERVAL)
            await hass.async_block_till_done()

            all_states = hass.states.async_all()
            assert len(all_states) == 3

            # Simulate an update - empty data, removes all entities
            mock_feed_update.return_value = "ERROR", None
            async_fire_time_changed(hass, utcnow + 3 * SCAN_INTERVAL)
            await hass.async_block_till_done()

            all_states = hass.states.async_all()
            assert len(all_states) == 0

            # Artificially trigger update.
            hass.bus.async_fire(EVENT_HOMEASSISTANT_STOP)
            # Collect events.
            await hass.async_block_till_done()
async def test_smart_strip_effects(hass: HomeAssistant) -> None:
    """Test smart strip effects."""
    already_migrated_config_entry = MockConfigEntry(domain=DOMAIN,
                                                    data={},
                                                    unique_id=MAC_ADDRESS)
    already_migrated_config_entry.add_to_hass(hass)
    strip = _mocked_smart_light_strip()

    with _patch_discovery(device=strip), _patch_single_discovery(device=strip):
        await async_setup_component(hass, tplink.DOMAIN, {tplink.DOMAIN: {}})
        await hass.async_block_till_done()

    entity_id = "light.my_bulb"

    state = hass.states.get(entity_id)
    assert state.state == STATE_ON
    assert state.attributes[ATTR_EFFECT] == "Effect1"
    assert state.attributes[ATTR_EFFECT_LIST] == ["Effect1", "Effect2"]

    await hass.services.async_call(
        LIGHT_DOMAIN,
        "turn_on",
        {
            ATTR_ENTITY_ID: entity_id,
            ATTR_EFFECT: "Effect2"
        },
        blocking=True,
    )
    strip.set_effect.assert_called_once_with("Effect2")
    strip.set_effect.reset_mock()

    strip.effect = {"name": "Effect1", "enable": 0, "custom": 0}
    async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10))
    await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state.state == STATE_ON
    assert ATTR_EFFECT not in state.attributes

    strip.is_off = True
    strip.is_on = False
    async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=20))
    await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state.state == STATE_OFF
    assert ATTR_EFFECT not in state.attributes

    await hass.services.async_call(
        LIGHT_DOMAIN,
        "turn_on",
        {ATTR_ENTITY_ID: entity_id},
        blocking=True,
    )
    strip.set_effect.assert_called_once_with("Effect1")
    strip.set_effect.reset_mock()

    strip.is_off = False
    strip.is_on = True
    strip.effect_list = None
    async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=30))
    await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state.state == STATE_ON
    assert state.attributes[ATTR_EFFECT_LIST] is None
Beispiel #57
0
async def test_lock_update_via_pubnub(hass):
    """Test creation of a lock with doorsense and bridge."""
    lock_one = await _mock_doorsense_enabled_august_lock_detail(hass)
    assert lock_one.pubsub_channel == "pubsub"
    pubnub = AugustPubNub()

    activities = await _mock_activities_from_fixture(hass,
                                                     "get_activity.lock.json")
    config_entry = await _create_august_with_devices(hass, [lock_one],
                                                     activities=activities,
                                                     pubnub=pubnub)
    pubnub.connected = True

    lock_online_with_doorsense_name = hass.states.get(
        "lock.online_with_doorsense_name")

    assert lock_online_with_doorsense_name.state == STATE_LOCKED

    pubnub.message(
        pubnub,
        Mock(
            channel=lock_one.pubsub_channel,
            timetoken=dt_util.utcnow().timestamp() * 10000000,
            message={
                "status": "kAugLockState_Unlocking",
            },
        ),
    )

    await hass.async_block_till_done()
    await hass.async_block_till_done()

    lock_online_with_doorsense_name = hass.states.get(
        "lock.online_with_doorsense_name")
    assert lock_online_with_doorsense_name.state == STATE_UNLOCKING

    pubnub.message(
        pubnub,
        Mock(
            channel=lock_one.pubsub_channel,
            timetoken=(dt_util.utcnow().timestamp() + 1) * 10000000,
            message={
                "status": "kAugLockState_Locking",
            },
        ),
    )

    await hass.async_block_till_done()
    await hass.async_block_till_done()

    lock_online_with_doorsense_name = hass.states.get(
        "lock.online_with_doorsense_name")
    assert lock_online_with_doorsense_name.state == STATE_LOCKING

    async_fire_time_changed(hass,
                            dt_util.utcnow() + datetime.timedelta(seconds=30))
    await hass.async_block_till_done()
    lock_online_with_doorsense_name = hass.states.get(
        "lock.online_with_doorsense_name")
    assert lock_online_with_doorsense_name.state == STATE_LOCKING

    pubnub.connected = True
    async_fire_time_changed(hass,
                            dt_util.utcnow() + datetime.timedelta(seconds=30))
    await hass.async_block_till_done()
    lock_online_with_doorsense_name = hass.states.get(
        "lock.online_with_doorsense_name")
    assert lock_online_with_doorsense_name.state == STATE_LOCKING

    # Ensure pubnub status is always preserved
    async_fire_time_changed(hass,
                            dt_util.utcnow() + datetime.timedelta(hours=2))
    await hass.async_block_till_done()
    lock_online_with_doorsense_name = hass.states.get(
        "lock.online_with_doorsense_name")
    assert lock_online_with_doorsense_name.state == STATE_LOCKING

    pubnub.message(
        pubnub,
        Mock(
            channel=lock_one.pubsub_channel,
            timetoken=(dt_util.utcnow().timestamp() + 2) * 10000000,
            message={
                "status": "kAugLockState_Unlocking",
            },
        ),
    )
    await hass.async_block_till_done()
    await hass.async_block_till_done()

    lock_online_with_doorsense_name = hass.states.get(
        "lock.online_with_doorsense_name")
    assert lock_online_with_doorsense_name.state == STATE_UNLOCKING

    async_fire_time_changed(hass,
                            dt_util.utcnow() + datetime.timedelta(hours=4))
    await hass.async_block_till_done()
    lock_online_with_doorsense_name = hass.states.get(
        "lock.online_with_doorsense_name")
    assert lock_online_with_doorsense_name.state == STATE_UNLOCKING

    await hass.config_entries.async_unload(config_entry.entry_id)
    await hass.async_block_till_done()
async def test_off_delay(hass, monkeypatch):
    """Test off_delay option."""
    # setup mocking rflink module
    event_callback, create, _, _ = await mock_rflink(hass, CONFIG, DOMAIN,
                                                     monkeypatch)

    # make sure arguments are passed
    assert create.call_args_list[0][1]['ignore']

    events = []

    on_event = {
        'id': 'test2',
        'command': 'on',
    }

    @ha.callback
    def callback(event):
        """Verify event got called."""
        events.append(event)

    hass.bus.async_listen(EVENT_STATE_CHANGED, callback)

    now = dt_util.utcnow()
    # fake time and turn on sensor
    future = now + timedelta(seconds=0)
    with patch(('homeassistant.helpers.event.'
                'dt_util.utcnow'),
               return_value=future):
        async_fire_time_changed(hass, future)
        event_callback(on_event)
        await hass.async_block_till_done()
    state = hass.states.get('binary_sensor.test2')
    assert state.state == STATE_ON
    assert len(events) == 1

    # fake time and turn on sensor again
    future = now + timedelta(seconds=15)
    with patch(('homeassistant.helpers.event.'
                'dt_util.utcnow'),
               return_value=future):
        async_fire_time_changed(hass, future)
        event_callback(on_event)
        await hass.async_block_till_done()
    state = hass.states.get('binary_sensor.test2')
    assert state.state == STATE_ON
    assert len(events) == 2

    # fake time and verify sensor still on (de-bounce)
    future = now + timedelta(seconds=35)
    with patch(('homeassistant.helpers.event.'
                'dt_util.utcnow'),
               return_value=future):
        async_fire_time_changed(hass, future)
        await hass.async_block_till_done()
    state = hass.states.get('binary_sensor.test2')
    assert state.state == STATE_ON
    assert len(events) == 2

    # fake time and verify sensor is off
    future = now + timedelta(seconds=45)
    with patch(('homeassistant.helpers.event.'
                'dt_util.utcnow'),
               return_value=future):
        async_fire_time_changed(hass, future)
        await hass.async_block_till_done()
    state = hass.states.get('binary_sensor.test2')
    assert state.state == STATE_OFF
    assert len(events) == 3
Beispiel #59
0
async def fire_alarm(hass, point_in_time):
    """Fire an alarm and wait for callbacks to run."""
    with patch("homeassistant.util.dt.utcnow", return_value=point_in_time):
        async_fire_time_changed(hass, point_in_time)
        await hass.async_block_till_done()
Beispiel #60
0
async def _ffwd_next_update_interval(hass):
    now = dt_util.utcnow()
    async_fire_time_changed(hass, now + UPDATE_INTERVAL)
    await hass.async_block_till_done()