Пример #1
0
def test_run_information(hass_recorder):
    """Ensure run_information returns expected data."""
    before_start_recording = dt_util.utcnow()
    hass = hass_recorder()
    run_info = run_information_from_instance(hass)
    assert isinstance(run_info, RecorderRuns)
    assert run_info.closed_incorrect is False

    with session_scope(hass=hass) as session:
        run_info = run_information_with_session(session)
        assert isinstance(run_info, RecorderRuns)
        assert run_info.closed_incorrect is False

    run_info = run_information(hass)
    assert isinstance(run_info, RecorderRuns)
    assert run_info.closed_incorrect is False

    hass.states.set("test.two", "on", {})
    wait_recording_done(hass)
    run_info = run_information(hass)
    assert isinstance(run_info, RecorderRuns)
    assert run_info.closed_incorrect is False

    run_info = run_information(hass, before_start_recording)
    assert run_info is None

    run_info = run_information(hass, dt_util.utcnow())
    assert isinstance(run_info, RecorderRuns)
    assert run_info.closed_incorrect is False
Пример #2
0
def test_end_incomplete_runs(hass_recorder, caplog):
    """Ensure we can end incomplete runs."""
    hass = hass_recorder()

    with session_scope(hass=hass) as session:
        run_info = run_information_with_session(session)
        assert isinstance(run_info, RecorderRuns)
        assert run_info.closed_incorrect is False

        now = dt_util.utcnow()
        now_without_tz = now.replace(tzinfo=None)
        end_incomplete_runs(session, now)
        run_info = run_information_with_session(session)
        assert run_info.closed_incorrect is True
        assert run_info.end == now_without_tz
        session.flush()

        later = dt_util.utcnow()
        end_incomplete_runs(session, later)
        run_info = run_information_with_session(session)
        assert run_info.end == now_without_tz

    assert "Ended unfinished session" in caplog.text
Пример #3
0
def _get_states_with_session(
    hass: HomeAssistant,
    session: Session,
    utc_point_in_time: datetime,
    entity_ids: list[str] | None = None,
    run: RecorderRuns | None = None,
    filters: Any | None = None,
    no_attributes: bool = False,
) -> list[LazyState]:
    """Return the states at a specific point in time."""
    if entity_ids and len(entity_ids) == 1:
        return _get_single_entity_states_with_session(hass, session,
                                                      utc_point_in_time,
                                                      entity_ids[0],
                                                      no_attributes)

    if (run is None and (run := (recorder.run_information_with_session(
            session, utc_point_in_time))) is None):
        # History did not run before utc_point_in_time
        return []
Пример #4
0
def _get_states_with_session(
    session, utc_point_in_time, entity_ids=None, run=None, filters=None
):
    """Return the states at a specific point in time."""
    query = session.query(*QUERY_STATES)

    if entity_ids and len(entity_ids) == 1:
        # Use an entirely different (and extremely fast) query if we only
        # have a single entity id
        query = (
            query.filter(
                States.last_updated < utc_point_in_time,
                States.entity_id.in_(entity_ids),
            )
            .order_by(States.last_updated.desc())
            .limit(1)
        )
        return [LazyState(row) for row in execute(query)]

    if run is None:
        run = recorder.run_information_with_session(session, utc_point_in_time)

        # History did not run before utc_point_in_time
        if run is None:
            return []

    # We have more than one entity to look at (most commonly we want
    # all entities,) so we need to do a search on all states since the
    # last recorder run started.

    most_recent_states_by_date = session.query(
        States.entity_id.label("max_entity_id"),
        func.max(States.last_updated).label("max_last_updated"),
    ).filter(
        (States.last_updated >= run.start) & (States.last_updated < utc_point_in_time)
    )

    if entity_ids:
        most_recent_states_by_date.filter(States.entity_id.in_(entity_ids))

    most_recent_states_by_date = most_recent_states_by_date.group_by(States.entity_id)

    most_recent_states_by_date = most_recent_states_by_date.subquery()

    most_recent_state_ids = session.query(
        func.max(States.state_id).label("max_state_id")
    ).join(
        most_recent_states_by_date,
        and_(
            States.entity_id == most_recent_states_by_date.c.max_entity_id,
            States.last_updated == most_recent_states_by_date.c.max_last_updated,
        ),
    )

    most_recent_state_ids = most_recent_state_ids.group_by(States.entity_id)

    most_recent_state_ids = most_recent_state_ids.subquery()

    query = query.join(
        most_recent_state_ids, States.state_id == most_recent_state_ids.c.max_state_id,
    ).filter(~States.domain.in_(IGNORE_DOMAINS))

    if filters:
        query = filters.apply(query, entity_ids)

    return [LazyState(row) for row in execute(query)]
Пример #5
0
def _get_states_with_session(
    hass,
    session,
    utc_point_in_time,
    entity_ids=None,
    run=None,
    filters=None,
    no_attributes=False,
):
    """Return the states at a specific point in time."""
    if entity_ids and len(entity_ids) == 1:
        return _get_single_entity_states_with_session(hass, session,
                                                      utc_point_in_time,
                                                      entity_ids[0],
                                                      no_attributes)

    if run is None:
        run = recorder.run_information_with_session(session, utc_point_in_time)

        # History did not run before utc_point_in_time
        if run is None:
            return []

    # We have more than one entity to look at so we need to do a query on states
    # since the last recorder run started.
    query_keys = QUERY_STATE_NO_ATTR if no_attributes else QUERY_STATES
    query = session.query(*query_keys)

    if entity_ids:
        # We got an include-list of entities, accelerate the query by filtering already
        # in the inner query.
        most_recent_state_ids = (session.query(
            func.max(States.state_id).label("max_state_id"), ).filter(
                (States.last_updated >= run.start)
                & (States.last_updated < utc_point_in_time)).filter(
                    States.entity_id.in_(entity_ids)))
        most_recent_state_ids = most_recent_state_ids.group_by(
            States.entity_id)
        most_recent_state_ids = most_recent_state_ids.subquery()
        query = query.join(
            most_recent_state_ids,
            States.state_id == most_recent_state_ids.c.max_state_id,
        )
        if not no_attributes:
            query = query.outerjoin(
                StateAttributes,
                (States.attributes_id == StateAttributes.attributes_id))
    else:
        # We did not get an include-list of entities, query all states in the inner
        # query, then filter out unwanted domains as well as applying the custom filter.
        # This filtering can't be done in the inner query because the domain column is
        # not indexed and we can't control what's in the custom filter.
        most_recent_states_by_date = (session.query(
            States.entity_id.label("max_entity_id"),
            func.max(States.last_updated).label("max_last_updated"),
        ).filter((States.last_updated >= run.start)
                 & (States.last_updated < utc_point_in_time)).group_by(
                     States.entity_id).subquery())
        most_recent_state_ids = (session.query(
            func.max(States.state_id).label("max_state_id")).join(
                most_recent_states_by_date,
                and_(
                    States.entity_id ==
                    most_recent_states_by_date.c.max_entity_id,
                    States.last_updated ==
                    most_recent_states_by_date.c.max_last_updated,
                ),
            ).group_by(States.entity_id).subquery())
        query = query.join(
            most_recent_state_ids,
            States.state_id == most_recent_state_ids.c.max_state_id,
        )
        for entity_domain in IGNORE_DOMAINS_ENTITY_ID_LIKE:
            query = query.filter(~States.entity_id.like(entity_domain))
        if filters:
            query = filters.apply(query)
        if not no_attributes:
            query = query.outerjoin(
                StateAttributes,
                (States.attributes_id == StateAttributes.attributes_id))

    attr_cache = {}
    return [LazyState(row, attr_cache) for row in execute(query)]