示例#1
0
 def _update_from_database(self, start: datetime.datetime,
                           end: datetime.datetime) -> list[State]:
     return history.state_changes_during_period(
         self.hass,
         start,
         end,
         self.entity_id,
         include_start_time_state=True,
         no_attributes=True,
     ).get(self.entity_id, [])
示例#2
0
def test_state_changes_during_period(hass_recorder, attributes, no_attributes,
                                     limit):
    """Test state change during period."""
    hass = hass_recorder()
    entity_id = "media_player.test"

    def set_state(state):
        """Set the state."""
        hass.states.set(entity_id, state, attributes)
        wait_recording_done(hass)
        return hass.states.get(entity_id)

    start = dt_util.utcnow()
    point = start + timedelta(seconds=1)
    end = point + timedelta(seconds=1)

    with patch("homeassistant.components.recorder.dt_util.utcnow",
               return_value=start):
        set_state("idle")
        set_state("YouTube")

    with patch("homeassistant.components.recorder.dt_util.utcnow",
               return_value=point):
        states = [
            set_state("idle"),
            set_state("Netflix"),
            set_state("Plex"),
            set_state("YouTube"),
        ]

    with patch("homeassistant.components.recorder.dt_util.utcnow",
               return_value=end):
        set_state("Netflix")
        set_state("Plex")

    hist = history.state_changes_during_period(hass,
                                               start,
                                               end,
                                               entity_id,
                                               no_attributes,
                                               limit=limit)

    assert states[:limit] == hist[entity_id]
示例#3
0
    def _update(self, start, end, now_timestamp, start_timestamp,
                end_timestamp):
        # Get history between start and end
        history_list = history.state_changes_during_period(
            self.hass, start, end, str(self._entity_id), no_attributes=True)

        if self._entity_id not in history_list:
            return

        # Get the first state
        last_state = history.get_state(self.hass,
                                       start,
                                       self._entity_id,
                                       no_attributes=True)
        last_state = last_state is not None and last_state in self._entity_states
        last_time = start_timestamp
        elapsed = 0
        count = 0

        # Make calculations
        for item in history_list.get(self._entity_id):
            current_state = item.state in self._entity_states
            current_time = item.last_changed.timestamp()

            if last_state:
                elapsed += current_time - last_time
            if current_state and not last_state:
                count += 1

            last_state = current_state
            last_time = current_time

        # Count time elapsed between last history state and end of measure
        if last_state:
            measure_end = min(end_timestamp, now_timestamp)
            elapsed += measure_end - last_time

        # Save value in hours
        self.value = elapsed / 3600

        # Save counter
        self.count = count
示例#4
0
文件: sensor.py 项目: jcgoette/core
 def _fetch_states_from_database(self) -> list[State]:
     """Fetch the states from the database."""
     _LOGGER.debug("%s: initializing values from the database",
                   self.entity_id)
     lower_entity_id = self._source_entity_id.lower()
     if self._samples_max_age is not None:
         start_date = (dt_util.utcnow() - self._samples_max_age -
                       timedelta(microseconds=1))
         _LOGGER.debug(
             "%s: retrieve records not older then %s",
             self.entity_id,
             start_date,
         )
     else:
         start_date = datetime.fromtimestamp(0, tz=dt_util.UTC)
         _LOGGER.debug("%s: retrieving all records", self.entity_id)
     return history.state_changes_during_period(
         self.hass,
         start_date,
         entity_id=lower_entity_id,
         descending=True,
         limit=self._samples_max_buffer_size,
         include_start_time_state=False,
     ).get(lower_entity_id, [])
示例#5
0
def state_changes_during_period(hass, start_time, end_time=None, entity_id=None):
    """Return states changes during UTC period start_time - end_time."""
    return history.state_changes_during_period(
        hass, start_time, end_time=None, entity_id=None
    )
示例#6
0
async def test_state_changes_during_period_query_during_migration_to_schema_25(
    hass: ha.HomeAssistant,
    async_setup_recorder_instance: SetupRecorderInstanceT,
):
    """Test we can query data prior to schema 25 and during migration to schema 25."""
    instance = await async_setup_recorder_instance(hass, {})

    start = dt_util.utcnow()
    point = start + timedelta(seconds=1)
    end = point + timedelta(seconds=1)
    entity_id = "light.test"
    await hass.async_add_executor_job(_add_db_entries, hass, point,
                                      [entity_id])

    no_attributes = True
    hist = history.state_changes_during_period(hass,
                                               start,
                                               end,
                                               entity_id,
                                               no_attributes,
                                               include_start_time_state=False)
    state = hist[entity_id][0]
    assert state.attributes == {}

    no_attributes = False
    hist = history.state_changes_during_period(hass,
                                               start,
                                               end,
                                               entity_id,
                                               no_attributes,
                                               include_start_time_state=False)
    state = hist[entity_id][0]
    assert state.attributes == {"name": "the shared light"}

    with instance.engine.connect() as conn:
        conn.execute(text("update states set attributes_id=NULL;"))
        conn.execute(text("drop table state_attributes;"))
        conn.commit()

    with patch.object(instance, "migration_in_progress", True):
        no_attributes = True
        hist = history.state_changes_during_period(
            hass,
            start,
            end,
            entity_id,
            no_attributes,
            include_start_time_state=False)
        state = hist[entity_id][0]
        assert state.attributes == {}

        no_attributes = False
        hist = history.state_changes_during_period(
            hass,
            start,
            end,
            entity_id,
            no_attributes,
            include_start_time_state=False)
        state = hist[entity_id][0]
        assert state.attributes == {"name": "the light"}
示例#7
0
    def _update_state(self):  # pylint: disable=r0914,r0912,r0915
        """Update the sensor state."""
        _LOGGER.debug('Updating sensor "%s"', self.name)
        start = end = start_ts = end_ts = None
        p_period = self._period

        # Parse templates
        self._update_period()

        if self._period is not None:
            now = datetime.datetime.now()
            start, end = self._period
            if p_period is None:
                p_start = p_end = now
            else:
                p_start, p_end = p_period

            # Convert times to UTC
            start = dt_util.as_utc(start)
            end = dt_util.as_utc(end)
            p_start = dt_util.as_utc(p_start)
            p_end = dt_util.as_utc(p_end)

            # Compute integer timestamps
            now_ts = math.floor(dt_util.as_timestamp(now))
            start_ts = math.floor(dt_util.as_timestamp(start))
            end_ts = math.floor(dt_util.as_timestamp(end))
            p_start_ts = math.floor(dt_util.as_timestamp(p_start))
            p_end_ts = math.floor(dt_util.as_timestamp(p_end))

            # If period has not changed and current time after the period end..
            if start_ts == p_start_ts and end_ts == p_end_ts and end_ts <= now_ts:
                # Don't compute anything as the value cannot have changed
                return

        self.available_sources = 0
        values = []
        self.count = 0
        self.min_value = self.max_value = None

        # pylint: disable=too-many-nested-blocks
        for entity_id in self.sources:
            _LOGGER.debug('Processing entity "%s"', entity_id)

            state = self.hass.states.get(entity_id)  # type: LazyState

            if state is None:
                _LOGGER.error('Unable to find an entity "%s"', entity_id)
                continue

            self._init_mode(state)

            value = 0
            elapsed = 0

            if self._period is None:
                # Get current state
                value = self._get_state_value(state)
                _LOGGER.debug("Current state: %s", value)

            else:
                # Get history between start and now
                history_list = history.state_changes_during_period(
                    self.hass, start, end, str(entity_id)
                )

                if entity_id not in history_list.keys():
                    value = self._get_state_value(state)
                    _LOGGER.warning(
                        'Historical data not found for entity "%s". '
                        "Current state used: %s",
                        entity_id,
                        value,
                    )
                else:
                    # Get the first state
                    item = history.get_state(self.hass, start, entity_id)
                    _LOGGER.debug("Initial historical state: %s", item)
                    last_state = None
                    last_time = start_ts
                    if item is not None and self._has_state(item.state):
                        last_state = self._get_state_value(item)

                    # Get the other states
                    for item in history_list.get(entity_id):
                        _LOGGER.debug("Historical state: %s", item)
                        current_state = self._get_state_value(item)
                        current_time = item.last_changed.timestamp()

                        if last_state is not None:
                            last_elapsed = current_time - last_time
                            value += last_state * last_elapsed
                            elapsed += last_elapsed

                        last_state = current_state
                        last_time = current_time

                    # Count time elapsed between last history state and now
                    if last_state is not None:
                        last_elapsed = end_ts - last_time
                        value += last_state * last_elapsed
                        elapsed += last_elapsed

                    if elapsed:
                        value /= elapsed
                    _LOGGER.debug("Historical average state: %s", value)

            if isinstance(value, numbers.Number):
                values.append(value)
                self.available_sources += 1

        if values:
            self._attr_state = round(sum(values) / len(values), self._precision)
            if self._precision < 1:
                self._attr_state = int(self._attr_state)
        else:
            self._attr_state = None
        _LOGGER.debug("Total average state: %s", self._attr_state)