def test_state_changes_during_period(self): self.init_recorder() entity_id = "media_player.test" def set_state(state): self.hass.states.set(entity_id, state) self.hass.pool.block_till_done() recorder._INSTANCE.block_till_done() return self.hass.states.get(entity_id) set_state("idle") set_state("YouTube") start = dt_util.utcnow() time.sleep(1) states = [set_state("idle"), set_state("Netflix"), set_state("Plex"), set_state("YouTube")] time.sleep(1) end = dt_util.utcnow() set_state("Netflix") set_state("Plex") self.assertEqual({entity_id: states}, history.state_changes_during_period(start, end, entity_id))
def test_state_changes_during_period(self): self.init_recorder() entity_id = 'media_player.test' def set_state(state): self.hass.states.set(entity_id, state) self.hass.pool.block_till_done() recorder._INSTANCE.block_till_done() return self.hass.states.get(entity_id) set_state('idle') set_state('YouTube') start = dt_util.utcnow() time.sleep(1) states = [ set_state('idle'), set_state('Netflix'), set_state('Plex'), set_state('YouTube'), ] time.sleep(1) end = dt_util.utcnow() set_state('Netflix') set_state('Plex') self.assertEqual({entity_id: states}, history.state_changes_during_period( start, end, entity_id))
def on_duration(hass: HomeAssistant, start: datetime, end: datetime, entity_id: str) -> timedelta: """Return the total on time between start and end""" history_list = history.state_changes_during_period(hass, start, end, entity_id) elapsed = timedelta() current_state: str = None current_time: datetime = None if len(history_list) > 0: for item in history_list.get(entity_id): # Initialise on first pass if current_state is None: current_state = item.state current_time = item.last_changed continue if current_state == STATE_ON and item.state != STATE_ON: elapsed += item.last_changed - current_time current_state = item.state current_time = item.last_changed if current_state == STATE_ON: elapsed += end - current_time return timedelta(seconds=round(elapsed.total_seconds()))
def test_state_changes_during_period(hass_history): """Test state change during period.""" hass = hass_history entity_id = "media_player.test" def set_state(state): """Set the state.""" hass.states.set(entity_id, state) 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) assert states == hist[entity_id]
def test_state_changes_during_period(self): self.init_recorder() entity_id = 'media_player.test' def set_state(state): self.hass.states.set(entity_id, state) self.wait_recording_done() return self.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(start, end, entity_id) self.assertEqual(states, hist[entity_id])
def test_state_changes_during_period(self): self.init_recorder() entity_id = 'media_player.test' def set_state(state): self.hass.states.set(entity_id, state) self.hass.pool.block_till_done() recorder._INSTANCE.block_till_done() return self.hass.states.get(entity_id) set_state('idle') set_state('YouTube') start = dt_util.utcnow() point = start + timedelta(seconds=1) end = point + timedelta(seconds=1) with patch('homeassistant.util.dt.utcnow', return_value=point): states = [ set_state('idle'), set_state('Netflix'), set_state('Plex'), set_state('YouTube'), ] with patch('homeassistant.util.dt.utcnow', return_value=end): set_state('Netflix') set_state('Plex') self.assertEqual({entity_id: states}, history.state_changes_during_period( start, end, entity_id))
def test_state_changes_during_period(self): self.init_recorder() entity_id = 'media_player.test' def set_state(state): self.hass.states.set(entity_id, state) self.hass.pool.block_till_done() recorder._INSTANCE.block_till_done() return self.hass.states.get(entity_id) set_state('idle') set_state('YouTube') start = dt_util.utcnow() point = start + timedelta(seconds=1) end = point + timedelta(seconds=1) with patch('homeassistant.util.dt.utcnow', return_value=point): states = [ set_state('idle'), set_state('Netflix'), set_state('Plex'), set_state('YouTube'), ] with patch('homeassistant.util.dt.utcnow', return_value=end): set_state('Netflix') set_state('Plex') self.assertEqual( {entity_id: states}, history.state_changes_during_period(start, end, entity_id))
def update(self): """Get the latest data and updates the states.""" # Parse templates self.update_period() start, end = self._period # Convert to UTC start = dt_util.as_utc(start) end = dt_util.as_utc(end) # Get history between start and end history_list = history.state_changes_during_period( self.hass, start, end, str(self._entity_id)) if self._entity_id not in history_list.keys(): return # Get the first state last_state = history.get_state(self.hass, start, self._entity_id) last_state = (last_state is not None and last_state == self._entity_state) last_time = dt_util.as_timestamp(start) elapsed = 0 count = 0 # Make calculations for item in history_list.get(self._entity_id): current_state = item.state == self._entity_state 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(dt_util.as_timestamp(end), dt_util.as_timestamp(datetime.datetime.now())) elapsed += measure_end - last_time # Save value in hours self.value = elapsed / 3600 # Save counter self.count = count
def update(self): """Get the latest data and updates the states.""" # Parse templates self.update_period() start, end = self._period # Convert to UTC start = dt_util.as_utc(start) end = dt_util.as_utc(end) # Get history between start and end history_list = history.state_changes_during_period( self.hass, start, end, str(self._entity_id)) if self._entity_id not in history_list.keys(): return # Get the first state last_state = history.get_state(self.hass, start, self._entity_id) last_state = (last_state is not None and last_state == self._entity_state) last_time = dt_util.as_timestamp(start) elapsed = 0 count = 0 # Make calculations for item in history_list.get(self._entity_id): current_state = item.state == self._entity_state 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(dt_util.as_timestamp(end), dt_util.as_timestamp( datetime.datetime.now())) elapsed += measure_end - last_time # Save value in hours self.value = elapsed / 3600 # Save counter self.count = count
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)) if self._entity_id not in history_list: return # Get the first state last_state = history.get_state(self.hass, start, self._entity_id) 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
def update(self): """Get the latest data and updates the states.""" # Parse templates self.update_period() start, end = self._period # Convert to UTC start = dt_util.as_utc(start) end = dt_util.as_utc(end) # Get history between start and end history_list = history.state_changes_during_period( start, end, str(self._entity_id)) if self._entity_id not in history_list.keys(): return # Get the first state last_state = history.get_state(start, self._entity_id) last_state = (last_state is not None and last_state == self._entity_state) last_time = dt_util.as_timestamp(start) elapsed = 0 # Make calculations for item in history_list.get(self._entity_id): current_state = item.state == self._entity_state current_time = item.last_changed.timestamp() if last_state: elapsed += current_time - last_time last_state = current_state last_time = current_time # Save value in hours self.value = elapsed / 3600
def update(self): """Get the latest data and updates the states.""" # Get previous values of start and end p_start, p_end = self._period # Parse templates self.update_period() start, end = self._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) now = datetime.datetime.now() # Compute integer timestamps start_timestamp = math.floor(dt_util.as_timestamp(start)) end_timestamp = math.floor(dt_util.as_timestamp(end)) p_start_timestamp = math.floor(dt_util.as_timestamp(p_start)) p_end_timestamp = math.floor(dt_util.as_timestamp(p_end)) now_timestamp = math.floor(dt_util.as_timestamp(now)) # If period has not changed and current time after the period end... if start_timestamp == p_start_timestamp and \ end_timestamp == p_end_timestamp and \ end_timestamp <= now_timestamp: # Don't compute anything as the value cannot have changed return # Get history between start and end history_list = history.state_changes_during_period( self.hass, start, end, str(self._entity_id)) if self._entity_id not in history_list.keys(): return # Get the first state last_state = history.get_state(self.hass, start, self._entity_id) last_state = (last_state is not None and last_state == self._entity_state) last_time = start_timestamp elapsed = 0 count = 0 # Make calculations for item in history_list.get(self._entity_id): current_state = item.state == self._entity_state 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
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 if self._temperature_mode is None: domain = split_entity_id(state.entity_id)[0] self._device_class = state.attributes.get(ATTR_DEVICE_CLASS) self._unit_of_measurement = state.attributes.get( ATTR_UNIT_OF_MEASUREMENT) self._temperature_mode = ( self._device_class == DEVICE_CLASS_TEMPERATURE or domain in (WEATHER_DOMAIN, CLIMATE_DOMAIN, WATER_HEATER_DOMAIN) or self._unit_of_measurement in TEMPERATURE_UNITS) if self._temperature_mode: _LOGGER.debug("%s is a temperature entity.", entity_id) self._device_class = DEVICE_CLASS_TEMPERATURE self._unit_of_measurement = self._hass.config.units.temperature_unit else: _LOGGER.debug("%s is NOT a temperature entity.", entity_id) self._icon = state.attributes.get(ATTR_ICON) 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._state = round(sum(values) / len(values), self._precision) else: self._state = None _LOGGER.debug("Total average state: %s", self._state)
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 for entity_id in self._entity_ids: # pylint: disable=r1702 _LOGGER.debug('Processing entity "%s"', entity_id) entity = self._hass.states.get(entity_id) if entity is None: _LOGGER.error('Unable to find an entity "%s"', entity_id) continue if self._temperature_mode is None: self._temperature_mode = self._is_temperature(entity) if self._temperature_mode: self._unit_of_measurement = \ self._hass.config.units.temperature_unit self._icon = 'mdi:thermometer' else: self._unit_of_measurement = \ entity.attributes.get(ATTR_UNIT_OF_MEASUREMENT) self._icon = \ entity.attributes.get(ATTR_ICON) value = 0 elapsed = 0 if self._period is None: # Get current state value = self._get_entity_state(entity) _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_entity_state(entity) _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_entity_state(item) # Get the other states for item in history_list.get(entity_id): _LOGGER.debug('Historical state: %s', item) if self._has_state(item.state): current_state = self._get_entity_state(item) current_time = item.last_changed.timestamp() if last_state: 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: 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._state = round(sum(values) / len(values), self._precision) else: self._state = None _LOGGER.debug('Total average state: %s', self._state)
def update(self): """Get the latest data and updates the states.""" # Get previous values of start and end p_start, p_end = self._period # Parse templates self.update_period() start, end = self._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) now = datetime.datetime.now() # Compute integer timestamps start_timestamp = math.floor(dt_util.as_timestamp(start)) end_timestamp = math.floor(dt_util.as_timestamp(end)) p_start_timestamp = math.floor(dt_util.as_timestamp(p_start)) p_end_timestamp = math.floor(dt_util.as_timestamp(p_end)) now_timestamp = math.floor(dt_util.as_timestamp(now)) # If period has not changed and current time after the period end... if start_timestamp == p_start_timestamp and \ end_timestamp == p_end_timestamp and \ end_timestamp <= now_timestamp: # Don't compute anything as the value cannot have changed return # Get history between start and end history_list = history.state_changes_during_period( self.hass, start, end, str(self._entity_id)) if self._entity_id not in history_list.keys(): return # Get the first state last_state = history.get_state(self.hass, start, self._entity_id) last_state = (last_state is not None and last_state == self._entity_state) last_time = start_timestamp elapsed = 0 count = 0 # Make calculations for item in history_list.get(self._entity_id): current_state = item.state == self._entity_state 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
async def async_update(self): """Update the sensor state.""" start = now = start_timestamp = now_timestamp = None if self._duration is not None: now = dt_util.now() start = dt_util.as_utc(now - self._duration) now = dt_util.as_utc(now) # Compute integer timestamps start_timestamp = math.floor(dt_util.as_timestamp(start)) now_timestamp = math.floor(dt_util.as_timestamp(now)) values = [] for entity_id in self._entities: _LOGGER.debug('Processing entity \'%s\'', entity_id) entity = self._hass.states.get(entity_id) if entity is None: raise HomeAssistantError( 'Unable to find an entity called {}'.format(entity_id)) value = 0 elapsed = 0 if self._duration is None: # Get current state value = self._get_temperature(entity) _LOGGER.debug('Current temperature: %s', value) else: # Get history between start and now history_list = history.state_changes_during_period( self.hass, start, now, str(entity_id)) if entity_id not in history_list.keys(): value = self._get_temperature(entity) _LOGGER.warning( 'Historical data not found for entity \'%s\'.' ' Current temperature 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_timestamp if item is not None and item.state is not None: last_state = self._get_temperature(item) # Get the other states for item in history_list.get(entity_id): _LOGGER.debug('Historical state: %s', item) if item.state is not None: current_state = self._get_temperature(item) current_time = item.last_changed.timestamp() if last_state: 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: last_elapsed = now_timestamp - last_time value += last_state * last_elapsed elapsed += last_elapsed value /= elapsed _LOGGER.debug('Historical average temperature: %s', value) values.append(value) if values: self._state = round(sum(values) / len(values), 1) else: self._state = None _LOGGER.debug('Total average temperature: %s', self._state)