def update_from_latest_data(self): """Update the state.""" data = self.openuv.data[DATA_PROTECTION_WINDOW] if not data: self._available = False return self._available = True for key in ("from_time", "to_time", "from_uv", "to_uv"): if not data.get(key): LOGGER.info("Skipping update due to missing data: %s", key) return if self._sensor_type == TYPE_PROTECTION_WINDOW: self._state = (parse_datetime(data["from_time"]) <= utcnow() <= parse_datetime(data["to_time"])) self._attrs.update({ ATTR_PROTECTION_WINDOW_ENDING_TIME: as_local(parse_datetime(data["to_time"])), ATTR_PROTECTION_WINDOW_ENDING_UV: data["to_uv"], ATTR_PROTECTION_WINDOW_STARTING_UV: data["from_uv"], ATTR_PROTECTION_WINDOW_STARTING_TIME: as_local(parse_datetime(data["from_time"])), })
def _update_internal_state(self, time_date): time = dt_util.as_local(time_date).strftime(TIME_STR_FORMAT) time_utc = time_date.strftime(TIME_STR_FORMAT) date = dt_util.as_local(time_date).date().isoformat() date_utc = time_date.date().isoformat() if self.type == "time": self._state = time elif self.type == "date": self._state = date elif self.type == "date_time": self._state = f"{date}, {time}" elif self.type == "date_time_utc": self._state = f"{date_utc}, {time_utc}" elif self.type == "time_date": self._state = f"{time}, {date}" elif self.type == "time_utc": self._state = time_utc elif self.type == "beat": # Calculate Swatch Internet Time. time_bmt = time_date + timedelta(hours=1) delta = timedelta( hours=time_bmt.hour, minutes=time_bmt.minute, seconds=time_bmt.second, microseconds=time_bmt.microsecond, ) # Use integers to better handle rounding. For example, # int(63763.2/86.4) = 737 but 637632//864 = 738. beat = int(delta.total_seconds() * 10) // 864 self._state = f"@{beat:03d}" elif self.type == "date_time_iso": self._state = dt_util.parse_datetime(f"{date} {time}").isoformat()
def _update_internal_state(self, time_date): time = dt_util.as_local(time_date).strftime(TIME_STR_FORMAT) time_utc = time_date.strftime(TIME_STR_FORMAT) date = dt_util.as_local(time_date).date().isoformat() date_utc = time_date.date().isoformat() # Calculate Swatch Internet Time. time_bmt = time_date + timedelta(hours=1) delta = timedelta( hours=time_bmt.hour, minutes=time_bmt.minute, seconds=time_bmt.second, microseconds=time_bmt.microsecond, ) beat = int((delta.seconds + delta.microseconds / 1000000.0) / 86.4) if self.type == "time": self._state = time elif self.type == "date": self._state = date elif self.type == "date_time": self._state = f"{date}, {time}" elif self.type == "date_time_utc": self._state = f"{date_utc}, {time_utc}" elif self.type == "time_date": self._state = f"{time}, {date}" elif self.type == "time_utc": self._state = time_utc elif self.type == "beat": self._state = f"@{beat:03d}" elif self.type == "date_time_iso": self._state = dt_util.parse_datetime(f"{date} {time}").isoformat()
def sun( opp: OpenPeerPower, before: Optional[str] = None, after: Optional[str] = None, before_offset: Optional[timedelta] = None, after_offset: Optional[timedelta] = None, ) -> bool: """Test if current time matches sun requirements.""" utcnow = dt_util.utcnow() today = dt_util.as_local(utcnow).date() before_offset = before_offset or timedelta(0) after_offset = after_offset or timedelta(0) sunrise_today = get_astral_event_date(opp, SUN_EVENT_SUNRISE, today) sunset_today = get_astral_event_date(opp, SUN_EVENT_SUNSET, today) sunrise = sunrise_today sunset = sunset_today if today > dt_util.as_local(cast( datetime, sunrise_today)).date() and SUN_EVENT_SUNRISE in (before, after): tomorrow = dt_util.as_local(utcnow + timedelta(days=1)).date() sunrise_tomorrow = get_astral_event_date(opp, SUN_EVENT_SUNRISE, tomorrow) sunrise = sunrise_tomorrow if today > dt_util.as_local(cast( datetime, sunset_today)).date() and SUN_EVENT_SUNSET in (before, after): tomorrow = dt_util.as_local(utcnow + timedelta(days=1)).date() sunset_tomorrow = get_astral_event_date(opp, SUN_EVENT_SUNSET, tomorrow) sunset = sunset_tomorrow if sunrise is None and SUN_EVENT_SUNRISE in (before, after): # There is no sunrise today return False if sunset is None and SUN_EVENT_SUNSET in (before, after): # There is no sunset today return False if before == SUN_EVENT_SUNRISE and utcnow > cast(datetime, sunrise) + before_offset: return False if before == SUN_EVENT_SUNSET and utcnow > cast(datetime, sunset) + before_offset: return False if after == SUN_EVENT_SUNRISE and utcnow < cast(datetime, sunrise) + after_offset: return False if after == SUN_EVENT_SUNSET and utcnow < cast(datetime, sunset) + after_offset: return False return True
def update_period(self): """Parse the templates and store a datetime tuple in _period.""" start = None end = None # Parse start if self._start is not None: try: start_rendered = self._start.async_render() except (TemplateError, TypeError) as ex: HistoryStatsHelper.handle_template_exception(ex, "start") return if isinstance(start_rendered, str): start = dt_util.parse_datetime(start_rendered) if start is None: try: start = dt_util.as_local( dt_util.utc_from_timestamp( math.floor(float(start_rendered)))) except ValueError: _LOGGER.error( "Parsing error: start must be a datetime or a timestamp" ) return # Parse end if self._end is not None: try: end_rendered = self._end.async_render() except (TemplateError, TypeError) as ex: HistoryStatsHelper.handle_template_exception(ex, "end") return if isinstance(end_rendered, str): end = dt_util.parse_datetime(end_rendered) if end is None: try: end = dt_util.as_local( dt_util.utc_from_timestamp( math.floor(float(end_rendered)))) except ValueError: _LOGGER.error( "Parsing error: end must be a datetime or a timestamp") return # Calculate start or end using the duration if start is None: start = end - self._duration if end is None: end = start + self._duration if start > dt_util.now(): # History hasn't been written yet for this period return if dt_util.now() < end: # No point in making stats of the future end = dt_util.now() self._period = start, end
def step2_exchange(now): """Keep trying to validate the user_code until it expires.""" if now >= dt.as_local(dev_flow.user_code_expiry): opp.components.persistent_notification.create( "Authentication code expired, please restart " "Open-Peer-Power and try again", title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID, ) listener() try: credentials = oauth.step2_exchange(device_flow_info=dev_flow) except FlowExchangeError: # not ready yet, call again return storage = Storage(opp.config.path(TOKEN_FILE)) storage.put(credentials) do_setup(opp, opp_config, config) listener() opp.components.persistent_notification.create( (f"We are all setup now. Check {YAML_DEVICES} for calendars that have " f"been found"), title=NOTIFICATION_TITLE, notification_id=NOTIFICATION_ID, )
def async_set_datetime(self, date=None, time=None, datetime=None, timestamp=None): """Set a new date / time.""" if timestamp: datetime = dt_util.as_local(dt_util.utc_from_timestamp(timestamp)) if datetime: date = datetime.date() time = datetime.time() if not self.has_date: date = None if not self.has_time: time = None if not date and not time: raise vol.Invalid("Nothing to set") if not date: date = self._current_datetime.date() if not time: time = self._current_datetime.time() self._current_datetime = py_datetime.datetime.combine( date, time, dt_util.DEFAULT_TIME_ZONE) self.async_write_op_state()
def extra_state_attributes(self): """Return status of device.""" attrs = self.device.device_status attrs["last_heard_from"] = as_local(self.last_update).strftime( "%Y-%m-%d %H:%M:%S" ) return attrs
def calculate_next(now: datetime) -> None: """Calculate and set the next time the trigger should fire.""" nonlocal next_time localized_now = dt_util.as_local(now) if local else now next_time = dt_util.find_next_time_expression_time( localized_now, matching_seconds, matching_minutes, matching_hours)
def get_location_astral_event_next( location: "astral.Location", event: str, utc_point_in_time: Optional[datetime.datetime] = None, offset: Optional[datetime.timedelta] = None, ) -> datetime.datetime: """Calculate the next specified solar event.""" from astral import AstralError if offset is None: offset = datetime.timedelta() if utc_point_in_time is None: utc_point_in_time = dt_util.utcnow() mod = -1 while True: try: next_dt: datetime.datetime = (getattr(location, event)( dt_util.as_local(utc_point_in_time).date() + datetime.timedelta(days=mod), local=False, ) + offset) if next_dt > utc_point_in_time: return next_dt except AstralError: pass mod += 1
def get_date(date): """Get the dateTime from date or dateTime as a local.""" if "date" in date: return dt.start_of_local_day( dt.dt.datetime.combine(dt.parse_date(date["date"]), dt.dt.time.min)) return dt.as_local(dt.parse_datetime(date["dateTime"]))
def timestamp_local(value): """Filter to convert given timestamp to local date/time.""" try: return dt_util.as_local( dt_util.utc_from_timestamp(value)).strftime(DATE_STR_FORMAT) except (ValueError, TypeError): # If timestamp can't be converted return value
def to_datetime(obj): """Return a datetime.""" if isinstance(obj, datetime): if obj.tzinfo is None: # floating value, not bound to any time zone in particular # represent same time regardless of which time zone is currently being observed return obj.replace(tzinfo=dt.DEFAULT_TIME_ZONE) return obj return dt.as_local(dt.dt.datetime.combine(obj, dt.dt.time.min))
def test_as_local_with_utc_object(): """Test local time with UTC object.""" dt_util.set_default_time_zone(dt_util.get_time_zone(TEST_TIME_ZONE)) utcnow = dt_util.utcnow() localnow = dt_util.as_local(utcnow) assert localnow == utcnow assert localnow.tzinfo != utcnow.tzinfo
def _purge_old(self): """Remove states which are older than self._max_age.""" now = dt_util.utcnow() _LOGGER.debug( "%s: purging records older then %s(%s)", self.entity_id, dt_util.as_local(now - self._max_age), self._max_age, ) while self.ages and (now - self.ages[0]) > self._max_age: _LOGGER.debug( "%s: purging record with datetime %s(%s)", self.entity_id, dt_util.as_local(self.ages[0]), (now - self.ages[0]), ) self.ages.popleft() self.states.popleft()
def timestamp_custom(value, date_format=DATE_STR_FORMAT, local=True): """Filter to convert given timestamp to format.""" try: date = dt_util.utc_from_timestamp(value) if local: date = dt_util.as_local(date) return date.strftime(date_format) except (ValueError, TypeError): # If timestamp can't be converted return value
def pattern_time_change_listener(_: datetime) -> None: """Listen for matching time_changed events.""" nonlocal time_listener now = time_tracker_utcnow() opp.async_run_opp_job(job, dt_util.as_local(now) if local else now) time_listener = async_track_point_in_utc_time( opp, pattern_time_change_listener, calculate_next(now + timedelta(seconds=1)), )
def __repr__(self) -> str: """Return the representation of the states.""" attrs = ( "; {}".format(util.repr_helper(self.attributes)) if self.attributes else "" ) return "<state {}={}{} @ {}>".format( self.entity_id, self.state, attrs, dt_util.as_local(self.last_changed).isoformat(), )
def get_next_interval(self, now=None): """Compute next time an update should occur.""" if now is None: now = dt_util.utcnow() if self.type == "date": now = dt_util.start_of_local_day(dt_util.as_local(now)) return now + timedelta(seconds=86400) if self.type == "beat": interval = 86.4 else: interval = 60 timestamp = int(dt_util.as_timestamp(now)) delta = interval - (timestamp % interval) return now + timedelta(seconds=delta)
async def async_update(self): """Get the time and updates the state.""" today = as_local(utcnow()).date() month = int(today.month) day = int(today.day) for sign in ZODIAC_BY_DATE: if (month == sign[0][1] and day >= sign[0][0]) or ( month == sign[1][1] and day <= sign[1][0] ): self._state = sign[2] self._attrs = sign[3] break
def extra_state_attributes(self): """Return the attributes of the sensor.""" val = {ATTR_ATTRIBUTION: ATTRIBUTION} if self._email not in self._data.data: return val for idx, value in enumerate(self._data.data[self._email]): tmpname = f"breach {idx + 1}" datetime_local = dt_util.as_local( dt_util.parse_datetime(value["AddedDate"])) tmpvalue = f"{value['Title']} {datetime_local.strftime(DATE_STR_FORMAT)}" val[tmpname] = tmpvalue return val
def pattern_time_change_listener(event: Event) -> None: """Listen for matching time_changed events.""" nonlocal next_time, last_now now = event.data[ATTR_NOW] if last_now is None or now < last_now: # Time rolled back or next time not yet calculated calculate_next(now) last_now = now if next_time <= now: opp.async_run_job(action, dt_util.as_local(now) if local else now) calculate_next(now + timedelta(seconds=1))
async def async_parse_last_reboot(uid: str, msg) -> Event: """Handle parsing event message. Topic: tns1:Monitoring/OperatingTime/LastReboot """ try: return Event( f"{uid}_{msg.Topic._value_1}", "Last Reboot", "sensor", "timestamp", None, dt_util.as_local( dt_util.parse_datetime(msg.Message._value_1.Data.SimpleItem[0].Value) ), ) except (AttributeError, KeyError, ValueError): return None
def relative_time(value): """ Take a datetime and return its "age" as a string. The age can be in second, minute, hour, day, month or year. Only the biggest unit is considered, e.g. if it's 2 days and 3 hours, "2 days" will be returned. Make sure date is not in the future, or else it will return None. If the input are not a datetime object the input will be returned unmodified. """ if not isinstance(value, datetime): return value if not value.tzinfo: value = dt_util.as_local(value) if dt_util.now() < value: return value return dt_util.get_age(value)
async def async_update(self): """Get the latest data and updates the state.""" _LOGGER.debug("Pulling data from %s sensor", self._name) await self._camera.update() if self._sensor_type == "last_activity_time": last_activity = await self._camera.get_last_activity(force_refresh=True) if last_activity is not None: last_activity_time = as_local(last_activity.end_time_utc) self._state = ( f"{last_activity_time.hour:0>2}:{last_activity_time.minute:0>2}" ) else: state = getattr(self._camera, self._sensor_type, None) if isinstance(state, bool): self._state = STATE_ON if state is True else STATE_OFF else: self._state = state self._state = state
def extra_state_attributes(self): """Return the state attributes.""" if self.type.startswith(PRECIPITATION_FORECAST): result = {ATTR_ATTRIBUTION: self._attribution} if self._timeframe is not None: result[TIMEFRAME_LABEL] = "%d min" % (self._timeframe) return result result = { ATTR_ATTRIBUTION: self._attribution, SENSOR_TYPES["stationname"][0]: self._stationname, } if self._measured is not None: # convert datetime (Europe/Amsterdam) into local datetime local_dt = dt_util.as_local(self._measured) result[MEASURED_LABEL] = local_dt.strftime("%c") return result
def update_from_latest_data(self): """Update the state.""" data = self.openuv.data[DATA_UV].get("result") if not data: self._available = False return self._available = True if self._sensor_type == TYPE_CURRENT_OZONE_LEVEL: self._state = data["ozone"] elif self._sensor_type == TYPE_CURRENT_UV_INDEX: self._state = data["uv"] elif self._sensor_type == TYPE_CURRENT_UV_LEVEL: if data["uv"] >= 11: self._state = UV_LEVEL_EXTREME elif data["uv"] >= 8: self._state = UV_LEVEL_VHIGH elif data["uv"] >= 6: self._state = UV_LEVEL_HIGH elif data["uv"] >= 3: self._state = UV_LEVEL_MODERATE else: self._state = UV_LEVEL_LOW elif self._sensor_type == TYPE_MAX_UV_INDEX: self._state = data["uv_max"] self._attrs.update({ ATTR_MAX_UV_TIME: as_local(parse_datetime(data["uv_max_time"])) }) elif self._sensor_type in ( TYPE_SAFE_EXPOSURE_TIME_1, TYPE_SAFE_EXPOSURE_TIME_2, TYPE_SAFE_EXPOSURE_TIME_3, TYPE_SAFE_EXPOSURE_TIME_4, TYPE_SAFE_EXPOSURE_TIME_5, TYPE_SAFE_EXPOSURE_TIME_6, ): self._state = data["safe_exposure_time"][EXPOSURE_TYPE_MAP[ self._sensor_type]]
def get_astral_event_date( opp: OpenPeerPowerType, event: str, date: Union[datetime.date, datetime.datetime, None] = None, ) -> Optional[datetime.datetime]: """Calculate the astral event time for the specified date.""" from astral import AstralError location = get_astral_location(opp) if date is None: date = dt_util.now().date() if isinstance(date, datetime.datetime): date = dt_util.as_local(date).date() try: return getattr(location, event)(date, local=False) # type: ignore except AstralError: # Event never occurs for specified date. return None
def get_next_interval(self): """Compute next time an update should occur.""" now = dt_util.utcnow() if self.type == "date": tomorrow = dt_util.as_local(now) + timedelta(days=1) return dt_util.start_of_local_day(tomorrow) if self.type == "beat": # Add 1 hour because @0 beats is at 23:00:00 UTC. timestamp = dt_util.as_timestamp(now + timedelta(hours=1)) interval = 86.4 else: timestamp = dt_util.as_timestamp(now) interval = 60 delta = interval - (timestamp % interval) next_interval = now + timedelta(seconds=delta) _LOGGER.debug("%s + %s -> %s (%s)", now, delta, next_interval, self.type) return next_interval
def utc_converter(utc_now: datetime) -> None: """Convert passed in UTC now to local now.""" opp.async_run_opp_job(job, dt_util.as_local(utc_now))