Example #1
0
    def parse_time_at_default_timezone(time_str: str | None) -> time | None:
        """Parse a time string and add default timezone."""
        if time_str is None:
            return None

        if (parsed_time := dt_util.parse_time(time_str)) is None:
            return None
Example #2
0
async def test_time_window(hass):
    """Test time condition windows."""
    sixam = dt.parse_time("06:00:00")
    sixpm = dt.parse_time("18:00:00")

    with patch(
            "homeassistant.helpers.condition.dt_util.now",
            return_value=dt.now().replace(hour=3),
    ):
        assert not condition.time(hass, after=sixam, before=sixpm)
        assert condition.time(hass, after=sixpm, before=sixam)

    with patch(
            "homeassistant.helpers.condition.dt_util.now",
            return_value=dt.now().replace(hour=9),
    ):
        assert condition.time(hass, after=sixam, before=sixpm)
        assert not condition.time(hass, after=sixpm, before=sixam)

    with patch(
            "homeassistant.helpers.condition.dt_util.now",
            return_value=dt.now().replace(hour=15),
    ):
        assert condition.time(hass, after=sixam, before=sixpm)
        assert not condition.time(hass, after=sixpm, before=sixam)

    with patch(
            "homeassistant.helpers.condition.dt_util.now",
            return_value=dt.now().replace(hour=21),
    ):
        assert not condition.time(hass, after=sixam, before=sixpm)
        assert condition.time(hass, after=sixpm, before=sixam)
Example #3
0
def get_datetime_from_future_time(time: str) -> datetime:
    """Get datetime from future time provided."""
    time = dt_util.parse_time(time)
    now = dt_util.utcnow()
    if time <= now.time():
        now = now + timedelta(days=1)
    return dt_util.as_utc(datetime.combine(now.date(), time))
Example #4
0
    async def async_activate(call):
        LOGGER.debug("Service activated")

        entity_id = call.data[ATTR_ENTITY_ID]
        solar_event = call.data[ATTR_SOLAR_EVENT]
        local_now = dt_util.now()

        _before = set_time_at_date(local_now,
                                   dt_util.parse_time(call.data[ATTR_BEFORE]))

        _after = set_time_at_date(local_now,
                                  dt_util.parse_time(call.data[ATTR_AFTER]))

        # LOGGER.debug("Before: %s, After %s", _before, _after)

        await flow(hass, local_now, _before, _after, entity_id, solar_event)
Example #5
0
def validate_time(time):
    res = OffsetTimePattern.match(time)
    if not res:
        if dt_util.parse_time(time):
            return time
        else:
            raise vol.Invalid("Invalid time entered: {}".format(time))
    else:
        if res.group(1) not in [SUN_EVENT_SUNRISE, SUN_EVENT_SUNSET]:
            raise vol.Invalid("Invalid time entered: {}".format(time))
        elif res.group(2) not in ['+', '-']:
            raise vol.Invalid("Invalid time entered: {}".format(time))
        elif not dt_util.parse_time(res.group(3)):
            raise vol.Invalid("Invalid time entered: {}".format(time))
        else:
            return time
Example #6
0
 async def _lyric_update(self) -> None:
     """Get values from lyric."""
     if self.device:
         if self.key == 'thermostatSetpointStatus':
             status = getattr(self.device, self.key)
             if status == 'NoHold':
                 self._state = 'Following Schedule'
             elif status == 'HoldUntil':
                 self._state = 'Held until {}'.format(
                     self.device.nextPeriodTime[:-3])
             elif status == 'PermanentHold':
                 self._state = 'Held Permanently'
             elif status == 'VacationHold':
                 self._state = 'Holiday'
         else:
             state = getattr(self.device, self.key)
             if self._device_class == DEVICE_CLASS_TIMESTAMP:
                 time = dt_util.parse_time(state)
                 now = dt_util.utcnow()
                 if time <= now.time():
                     now = now + timedelta(days=1)
                 state = dt_util.as_local(
                     dt_util.as_utc(datetime.combine(now.date(), time)))
             self._state = state
         self._available = True
Example #7
0
    async def async_added_to_hass(self):
        """Run when entity about to be added."""
        await super().async_added_to_hass()

        # Priority 1: Initial value
        if self.state is not None:
            return

        # Priority 2: Old state
        old_state = await self.async_get_last_state()
        if old_state is None:
            self._current_datetime = dt_util.parse_datetime(DEFAULT_VALUE)
            return

        if self.has_date and self.has_time:
            date_time = dt_util.parse_datetime(old_state.state)
            if date_time is None:
                self._current_datetime = dt_util.parse_datetime(DEFAULT_VALUE)
                return
            self._current_datetime = date_time
        elif self.has_date:
            date = dt_util.parse_date(old_state.state)
            if date is None:
                self._current_datetime = dt_util.parse_datetime(DEFAULT_VALUE)
                return
            self._current_datetime = datetime.datetime.combine(
                date, DEFAULT_TIME)
        else:
            time = dt_util.parse_time(old_state.state)
            if time is None:
                self._current_datetime = dt_util.parse_datetime(DEFAULT_VALUE)
                return
            self._current_datetime = datetime.datetime.combine(
                DEFAULT_DATE, time)
class InputDatetime(RestoreEntity):
    """Representation of a datetime input."""
    def __init__(self, config: dict) -> None:
        """Initialize a select input."""
        self._config = config
        self.editable = True
        self._current_datetime = None

        if not (initial := config.get(CONF_INITIAL)):
            return

        if self.has_date and self.has_time:
            current_datetime = dt_util.parse_datetime(initial)

        elif self.has_date:
            date = dt_util.parse_date(initial)
            current_datetime = py_datetime.datetime.combine(date, DEFAULT_TIME)

        else:
            time = dt_util.parse_time(initial)
            current_datetime = py_datetime.datetime.combine(
                py_datetime.date.today(), time)

        # If the user passed in an initial value with a timezone, convert it to right tz
        if current_datetime.tzinfo is not None:
            self._current_datetime = current_datetime.astimezone(
                dt_util.DEFAULT_TIME_ZONE)
        else:
            self._current_datetime = current_datetime.replace(
                tzinfo=dt_util.DEFAULT_TIME_ZONE)
Example #9
0
def calculate_datetime_from_entry(time_entry: dict, sun_data):
    if "at" in time_entry:
        time = dt_util.parse_time(time_entry["at"])

        today = dt_util.start_of_local_day()
        time_obj = dt_util.as_utc(datetime.datetime.combine(today, time))

    elif "event" in time_entry:
        if not sun_data:
            raise Exception("no sun data available")

        offset_sign = time_entry["offset"][0]
        offset_string = time_entry["offset"][1:]

        time_offset = datetime.datetime.strptime(offset_string, "%H:%M")
        time_offset = datetime.timedelta(hours=time_offset.hour,
                                         minutes=time_offset.minute)

        sun_event = time_entry["event"]
        time_sun = sun_data[sun_event]

        time_sun = parse_iso_timestamp(time_sun)

        if offset_sign == "+":
            time_obj = time_sun + time_offset
        else:
            time_obj = time_sun - time_offset

    else:
        raise Exception("cannot parse timestamp")

    return time_obj
Example #10
0
async def async_setup_entry(
    hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
    """Set up the Trafikverket sensor entry."""

    train_api = hass.data[DOMAIN][entry.entry_id]["train_api"]
    to_station = hass.data[DOMAIN][entry.entry_id][CONF_TO]
    from_station = hass.data[DOMAIN][entry.entry_id][CONF_FROM]
    get_time: str | None = entry.data.get(CONF_TIME)
    train_time = dt.parse_time(get_time) if get_time else None

    async_add_entities(
        [
            TrainSensor(
                train_api,
                entry.data[CONF_NAME],
                from_station,
                to_station,
                entry.data[CONF_WEEKDAY],
                train_time,
                entry.entry_id,
            )
        ],
        True,
    )
Example #11
0
    async def async_added_to_hass(self):
        """Run when entity about to be added."""
        await super().async_added_to_hass()
        restore_val = None

        # Priority 1: Initial State
        if self._initial is not None:
            restore_val = self._initial

        # Priority 2: Old state
        if restore_val is None:
            old_state = await self.async_get_last_state()
            if old_state is not None:
                restore_val = old_state.state

        if not self.has_date:
            if not restore_val:
                restore_val = DEFAULT_VALUE.split()[1]
            self._current_datetime = dt_util.parse_time(restore_val)
        elif not self.has_time:
            if not restore_val:
                restore_val = DEFAULT_VALUE.split()[0]
            self._current_datetime = dt_util.parse_date(restore_val)
        else:
            if not restore_val:
                restore_val = DEFAULT_VALUE
            self._current_datetime = dt_util.parse_datetime(restore_val)
def convert_time_to_utc(timestr):
    """Take a string like 08:00:00 and convert it to a unix timestamp."""
    combined = datetime.combine(
        dt_util.start_of_local_day(), dt_util.parse_time(timestr))
    if combined < datetime.now():
        combined = combined + timedelta(days=1)
    return dt_util.as_timestamp(combined)
Example #13
0
def convert_time_to_isodate(timestr: str) -> str:
    """Take a string like 08:00:00 and combine it with the current date."""
    combined = datetime.combine(dt.start_of_local_day(),
                                dt.parse_time(timestr))
    if combined < datetime.now():
        combined = combined + timedelta(days=1)
    return combined.isoformat()
Example #14
0
def trigger(hass, config, action):
    """Listen for state changes based on configuration."""
    if CONF_AFTER in config:
        after = dt_util.parse_time(config[CONF_AFTER])
        if after is None:
            _error_time(config[CONF_AFTER], CONF_AFTER)
            return False
        hours, minutes, seconds = after.hour, after.minute, after.second
    elif (CONF_HOURS in config or CONF_MINUTES in config
          or CONF_SECONDS in config):
        hours = config.get(CONF_HOURS)
        minutes = config.get(CONF_MINUTES)
        seconds = config.get(CONF_SECONDS)
    else:
        _LOGGER.error('One of %s, %s, %s OR %s needs to be specified',
                      CONF_HOURS, CONF_MINUTES, CONF_SECONDS, CONF_AFTER)
        return False

    def time_automation_listener(now):
        """Listen for time changes and calls action."""
        action()

    track_time_change(hass,
                      time_automation_listener,
                      hour=hours,
                      minute=minutes,
                      second=seconds)

    return True
Example #15
0
def trigger(hass, config, action):
    """Listen for state changes based on configuration."""
    if CONF_AFTER in config:
        after = dt_util.parse_time(config[CONF_AFTER])
        if after is None:
            _error_time(config[CONF_AFTER], CONF_AFTER)
            return False
        hours, minutes, seconds = after.hour, after.minute, after.second
    elif (CONF_HOURS in config or CONF_MINUTES in config or
          CONF_SECONDS in config):
        hours = config.get(CONF_HOURS)
        minutes = config.get(CONF_MINUTES)
        seconds = config.get(CONF_SECONDS)
    else:
        _LOGGER.error('One of %s, %s, %s OR %s needs to be specified',
                      CONF_HOURS, CONF_MINUTES, CONF_SECONDS, CONF_AFTER)
        return False

    def time_automation_listener(now):
        """Listen for time changes and calls action."""
        action()

    track_time_change(hass, time_automation_listener,
                      hour=hours, minute=minutes, second=seconds)

    return True
Example #16
0
    def __init__(self, config: typing.Dict) -> None:
        """Initialize a select input."""
        self._config = config
        self.editable = True
        self._current_datetime = None

        initial = config.get(CONF_INITIAL)
        if not initial:
            return

        if self.has_date and self.has_time:
            current_datetime = dt_util.parse_datetime(initial)

        elif self.has_date:
            date = dt_util.parse_date(initial)
            current_datetime = py_datetime.datetime.combine(date, DEFAULT_TIME)

        else:
            time = dt_util.parse_time(initial)
            current_datetime = py_datetime.datetime.combine(
                py_datetime.date.today(), time)

        # If the user passed in an initial value with a timezone, convert it to right tz
        if current_datetime.tzinfo is not None:
            self._current_datetime = current_datetime.astimezone(
                dt_util.DEFAULT_TIME_ZONE)
        else:
            self._current_datetime = dt_util.DEFAULT_TIME_ZONE.localize(
                current_datetime)
Example #17
0
def calculate_datetime_from_entry(time: str, sun_data=None):
    res = OffsetTimePattern.match(time)
    if not res:
        time = dt_util.parse_time(time)
        time = time.replace(tzinfo=dt_util.now().tzinfo)

        today = dt_util.now().date()
        time_obj = datetime.datetime.combine(today, time)
    else:
        sun_event = (SUN_EVENT_SUNRISE if res.group(1) == SUN_EVENT_SUNRISE
                     else SUN_EVENT_SUNSET)
        offset_sign = res.group(2)
        offset_string = res.group(3)

        if not sun_data:
            raise Exception("no sun data available")

        time_offset = datetime.datetime.strptime(offset_string, "%H:%M:%S")
        time_offset = datetime.timedelta(hours=time_offset.hour,
                                         minutes=time_offset.minute)

        time_sun = sun_data[sun_event]

        time_sun = parse_iso_timestamp(time_sun)

        if offset_sign == "+":
            time_obj = time_sun + time_offset
        else:
            time_obj = time_sun - time_offset

    return time_obj
Example #18
0
    def update(self):
        """Update probe data."""
        self.api.login(self.username, self.password)
        _LOGGER.debug("Updating data for %s", self.device_id)
        try:
            if self.growatt_type == "total":
                total_info = self.api.plant_info(self.device_id)
                del total_info["deviceList"]
                # PlantMoneyText comes in as "3.1/€" remove anything that isn't part of the number
                total_info["plantMoneyText"] = re.sub(
                    r"[^\d.,]", "", total_info["plantMoneyText"])
                self.data = total_info
            elif self.growatt_type == "inverter":
                inverter_info = self.api.inverter_detail(self.device_id)
                self.data = inverter_info
            elif self.growatt_type == "storage":
                storage_info_detail = self.api.storage_params(
                    self.device_id)["storageDetailBean"]
                storage_energy_overview = self.api.storage_energy_overview(
                    self.plant_id, self.device_id)
                self.data = {**storage_info_detail, **storage_energy_overview}
            elif self.growatt_type == "mix":
                mix_info = self.api.mix_info(self.device_id)
                mix_totals = self.api.mix_totals(self.device_id, self.plant_id)
                mix_system_status = self.api.mix_system_status(
                    self.device_id, self.plant_id)

                mix_detail = self.api.mix_detail(self.device_id, self.plant_id)
                # Get the chart data and work out the time of the last entry, use this as the last time data was published to the Growatt Server
                mix_chart_entries = mix_detail["chartData"]
                sorted_keys = sorted(mix_chart_entries)

                # Create datetime from the latest entry
                date_now = dt.now().date()
                last_updated_time = dt.parse_time(str(sorted_keys[-1]))
                combined_timestamp = datetime.datetime.combine(
                    date_now, last_updated_time)
                # Convert datetime to UTC
                combined_timestamp_utc = dt.as_utc(combined_timestamp)
                mix_detail[
                    "lastdataupdate"] = combined_timestamp_utc.isoformat()

                # Dashboard data is largely inaccurate for mix system but it is the only call with the ability to return the combined
                # imported from grid value that is the combination of charging AND load consumption
                dashboard_data = self.api.dashboard_data(self.plant_id)
                # Dashboard values have units e.g. "kWh" as part of their returned string, so we remove it
                dashboard_values_for_mix = {
                    # etouser is already used by the results from 'mix_detail' so we rebrand it as 'etouser_combined'
                    "etouser_combined":
                    dashboard_data["etouser"].replace("kWh", "")
                }
                self.data = {
                    **mix_info,
                    **mix_totals,
                    **mix_system_status,
                    **mix_detail,
                    **dashboard_values_for_mix,
                }
        except json.decoder.JSONDecodeError:
            _LOGGER.error("Unable to fetch data from Growatt server")
Example #19
0
def convert_time_to_utc(timestr):
    """Take a string like 08:00:00 and convert it to a unix timestamp."""
    combined = datetime.combine(dt_util.start_of_local_day(),
                                dt_util.parse_time(timestr))
    if combined < datetime.now():
        combined = combined + timedelta(days=1)
    return dt_util.as_timestamp(combined)
Example #20
0
def time(value):
    """Validate time."""
    time_val = dt_util.parse_time(value)

    if time_val is None:
        raise vol.Invalid('Invalid time specified: {}'.format(value))

    return time_val
Example #21
0
 def state(self) -> datetime:
     """Return the state of the sensor."""
     device = self.device
     time = dt_util.parse_time(device.changeableValues.nextPeriodTime)
     now = dt_util.utcnow()
     if time <= now.time():
         now = now + timedelta(days=1)
     return dt_util.as_utc(datetime.combine(now.date(), time))
def time(value):
    """Validate time."""
    time_val = dt_util.parse_time(value)

    if time_val is None:
        raise vol.Invalid('Invalid time specified: {}'.format(value))

    return time_val
Example #23
0
def if_action(hass, config):
    """Wrap action method with time based condition."""
    before = config.get(CONF_BEFORE)
    after = config.get(CONF_AFTER)
    weekday = config.get(CONF_WEEKDAY)

    if before is None and after is None and weekday is None:
        _LOGGER.error(
            "Missing if-condition configuration key %s, %s or %s",
            CONF_BEFORE, CONF_AFTER, CONF_WEEKDAY)
        return None

    if before is not None:
        before = dt_util.parse_time(before)
        if before is None:
            _error_time(before, CONF_BEFORE)
            return None

    if after is not None:
        after = dt_util.parse_time(after)
        if after is None:
            _error_time(after, CONF_AFTER)
            return None

    def time_if():
        """Validate time based if-condition."""
        now = dt_util.now()
        if before is not None and now > now.replace(hour=before.hour,
                                                    minute=before.minute):
            return False

        if after is not None and now < now.replace(hour=after.hour,
                                                   minute=after.minute):
            return False

        if weekday is not None:
            now_weekday = WEEKDAYS[now.weekday()]

            if isinstance(weekday, str) and weekday != now_weekday or \
               now_weekday not in weekday:
                return False

        return True

    return time_if
Example #24
0
def get_datetime_from_future_time(time_str: str) -> datetime:
    """Get datetime from future time provided."""
    time = dt_util.parse_time(time_str)
    if time is None:
        raise ValueError(f"Unable to parse time {time_str}")
    now = dt_util.utcnow()
    if time <= now.time():
        now = now + timedelta(days=1)
    return dt_util.as_utc(datetime.combine(now.date(), time))
Example #25
0
def if_action(hass, config):
    """Wrap action method with time based condition."""
    before = config.get(CONF_BEFORE)
    after = config.get(CONF_AFTER)
    weekday = config.get(CONF_WEEKDAY)

    if before is None and after is None and weekday is None:
        _LOGGER.error("Missing if-condition configuration key %s, %s or %s",
                      CONF_BEFORE, CONF_AFTER, CONF_WEEKDAY)
        return None

    if before is not None:
        before = dt_util.parse_time(before)
        if before is None:
            _error_time(before, CONF_BEFORE)
            return None

    if after is not None:
        after = dt_util.parse_time(after)
        if after is None:
            _error_time(after, CONF_AFTER)
            return None

    def time_if():
        """Validate time based if-condition."""
        now = dt_util.now()
        if before is not None and now > now.replace(hour=before.hour,
                                                    minute=before.minute):
            return False

        if after is not None and now < now.replace(hour=after.hour,
                                                   minute=after.minute):
            return False

        if weekday is not None:
            now_weekday = WEEKDAYS[now.weekday()]

            if isinstance(weekday, str) and weekday != now_weekday or \
               now_weekday not in weekday:
                return False

        return True

    return time_if
Example #26
0
    async def async_step_user(self,
                              user_input: dict[str, Any] | None = None
                              ) -> FlowResult:
        """Handle the user step."""
        errors: dict[str, str] = {}

        if user_input is not None:
            api_key: str = user_input[CONF_API_KEY]
            train_from: str = user_input[CONF_FROM]
            train_to: str = user_input[CONF_TO]
            train_time: str | None = user_input.get(CONF_TIME)
            train_days: list = user_input[CONF_WEEKDAY]

            name = f"{train_from} to {train_to}"
            if train_time:
                name = f"{train_from} to {train_to} at {train_time}"

            try:
                await self.validate_input(api_key, train_from, train_to)
            except ValueError as err:
                if str(err) == ERROR_INVALID_AUTH:
                    errors["base"] = "invalid_auth"
                elif str(err) == ERROR_INVALID_STATION:
                    errors["base"] = "invalid_station"
                elif str(err) == ERROR_MULTIPLE_STATION:
                    errors["base"] = "more_stations"
                else:
                    errors["base"] = "cannot_connect"
            else:
                if train_time:
                    if bool(dt_util.parse_time(train_time) is None):
                        errors["base"] = "invalid_time"
                if not errors:
                    unique_id = create_unique_id(train_from, train_to,
                                                 train_time, train_days)
                    await self.async_set_unique_id(unique_id)
                    self._abort_if_unique_id_configured()
                    return self.async_create_entry(
                        title=name,
                        data={
                            CONF_API_KEY: api_key,
                            CONF_NAME: name,
                            CONF_FROM: train_from,
                            CONF_TO: train_to,
                            CONF_TIME: train_time,
                            CONF_WEEKDAY: train_days,
                        },
                    )

        return self.async_show_form(
            step_id="user",
            data_schema=DATA_SCHEMA,
            errors=errors,
        )
Example #27
0
    def parse_time_at_default_timezone(time_str: str) -> time | None:
        """Parse a time string and add default timezone."""
        parsed_time = dt_util.parse_time(time_str)

        if parsed_time is None:
            return None

        return (dt_util.start_of_local_day().replace(
            hour=parsed_time.hour,
            minute=parsed_time.minute,
            second=parsed_time.second,
        ).timetz())
Example #28
0
File: sensor.py Project: Serios/VPT
 async def schedule_update(self, second=10):
     """Schedule an update after seconds."""
     """
         If we only getting lines schedule, no need for constant pooling. 
         Some aprox timing calculations based on nubers of results setted for schedule to return.
      
        Also since city of Varna doesn't have public transport trough the night, there is no need to pool at that time
     """
     if dt_util.parse_time('23:59:00') <= dt_util.parse_time(dt_util.now(
     ).strftime('%H:%M:%S')) <= dt_util.parse_time('04:59:59'):
         future = datetime.combine(
             dt_util.parse_datetime(
                 dt_util.now().strftime('%Y-%m-%d %H:%M:%S%z')),
             dt_util.parse_time('04:59:59')
         )  #future hour - 5:00 in the morning, when the first buses goes from the end stops
         current = datetime.now()  #now
         tdelta = future - current  #return the hours diffrence between the two times, we do calculation here to set next execute after N - hours
         if tdelta.days < 0:  #our interval crosses midnight end time is always earlier than the start time resulting timedalta been negative, lets account for that bellow
             tdelta = timedelta(days=0,
                                seconds=tdelta.seconds,
                                microseconds=tdelta.microseconds)
         nxt = dt_util.utcnow() + tdelta
     else:
         if self._mode == 'schedule':
             if second == 1:
                 nxt = dt_util.utcnow() + timedelta(seconds=1)
             else:
                 if self._max_results <= 10:
                     nxt = dt_util.utcnow() + timedelta(hours=1)
                 elif self._max_results <= 20:
                     nxt = dt_util.utcnow() + timedelta(hours=2)
                 elif self._max_results <= 40:
                     nxt = dt_util.utcnow() + timedelta(hours=4)
                 else:
                     nxt = dt_util.utcnow() + timedelta(hours=6)
         else:
             nxt = dt_util.utcnow() + timedelta(seconds=second)
     _LOGGER.debug("Scheduling next update at %s. UTC time",
                   nxt.strftime('%H:%M:%S'))
     async_track_point_in_utc_time(self._hass, self.async_update, nxt)
Example #29
0
    def parse_time_at_default_timezone(time_str: str) -> Optional[time]:
        """Parse a time string and add default timezone."""
        parsed_time = dt_util.parse_time(time_str)

        if parsed_time is None:
            return None

        return time(
            hour=parsed_time.hour,
            minute=parsed_time.minute,
            second=parsed_time.second,
            tzinfo=dt_util.DEFAULT_TIME_ZONE,
        )
Example #30
0
async def async_setup_entry(hass: HomeAssistant,
                            config_entry: ConfigEntry) -> bool:
    """Set up HERE Travel Time from a config entry."""
    api_key = config_entry.data[CONF_API_KEY]
    here_client = RoutingApi(api_key)
    setup_options(hass, config_entry)

    arrival = (dt.parse_time(config_entry.options[CONF_ARRIVAL_TIME]) if
               config_entry.options[CONF_ARRIVAL_TIME] is not None else None)
    departure = (dt.parse_time(config_entry.options[CONF_DEPARTURE_TIME])
                 if config_entry.options[CONF_DEPARTURE_TIME] is not None else
                 None)

    here_travel_time_config = HERETravelTimeConfig(
        destination_latitude=config_entry.data.get(CONF_DESTINATION_LATITUDE),
        destination_longitude=config_entry.data.get(
            CONF_DESTINATION_LONGITUDE),
        destination_entity_id=config_entry.data.get(
            CONF_DESTINATION_ENTITY_ID),
        origin_latitude=config_entry.data.get(CONF_ORIGIN_LATITUDE),
        origin_longitude=config_entry.data.get(CONF_ORIGIN_LONGITUDE),
        origin_entity_id=config_entry.data.get(CONF_ORIGIN_ENTITY_ID),
        travel_mode=config_entry.data[CONF_MODE],
        route_mode=config_entry.options[CONF_ROUTE_MODE],
        units=config_entry.options[CONF_UNIT_SYSTEM],
        arrival=arrival,
        departure=departure,
    )

    coordinator = HereTravelTimeDataUpdateCoordinator(
        hass,
        here_client,
        here_travel_time_config,
    )
    hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = coordinator
    hass.config_entries.async_setup_platforms(config_entry, PLATFORMS)

    return True
Example #31
0
def calculate_datetime(entry: dict, sun_data):
    """Get datetime object with closest occurance based on time + weekdays input"""

    if "time" in entry:
        time = dt_util.parse_time(entry["time"])

        today = dt_util.start_of_local_day()
        nexttime = dt_util.as_utc(datetime.datetime.combine(today, time))

    elif "event" in entry:
        if not sun_data:
            _LOGGER.error("no sun data available")
            return

        offset_sign = entry["offset"][0]
        offset_string = entry["offset"][1:]

        time_offset = datetime.datetime.strptime(offset_string, "%H:%M")
        time_offset = datetime.timedelta(hours=time_offset.hour,
                                         minutes=time_offset.minute)

        time_sun = (sun_data["sunrise"]
                    if entry["event"] == "sunrise" else sun_data["sunset"])
        time_sun = datetime.datetime.strptime(
            time_sun[:len(time_sun) - 3] + time_sun[len(time_sun) - 2:],
            "%Y-%m-%dT%H:%M:%S%z",
        )

        if offset_sign == "+":
            nexttime = time_sun + time_offset
        else:
            nexttime = time_sun - time_offset

    now = dt_util.now().replace(microsecond=0)

    # check if time has already passed for today
    delta = nexttime - now
    while delta.total_seconds() <= 0:
        nexttime = nexttime + datetime.timedelta(days=1)
        delta = nexttime - now

    # check if timer is restricted in days of the week
    day_list = entry["days"]
    if len(day_list) > 0 and not 0 in day_list:
        weekday = dt_util.as_local(nexttime).isoweekday()
        while weekday not in day_list:
            nexttime = nexttime + datetime.timedelta(days=1)
            weekday = dt_util.as_local(nexttime).isoweekday()

    return nexttime
def time(value: Any) -> time_sys:
    """Validate and transform a time."""
    if isinstance(value, time_sys):
        return value

    try:
        time_val = dt_util.parse_time(value)
    except TypeError as err:
        raise vol.Invalid("Not a parseable type") from err

    if time_val is None:
        raise vol.Invalid(f"Invalid time specified: {value}")

    return time_val
 def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
     """Initialize the Trafikverket coordinator."""
     super().__init__(
         hass,
         _LOGGER,
         name=DOMAIN,
         update_interval=TIME_BETWEEN_UPDATES,
     )
     self._ferry_api = TrafikverketFerry(async_get_clientsession(hass),
                                         entry.data[CONF_API_KEY])
     self._from: str = entry.data[CONF_FROM]
     self._to: str = entry.data[CONF_TO]
     self._time: time | None = dt.parse_time(entry.data[CONF_TIME])
     self._weekdays: list[str] = entry.data[CONF_WEEKDAY]
def time(value) -> time_sys:
    """Validate and transform a time."""
    if isinstance(value, time_sys):
        return value

    try:
        time_val = dt_util.parse_time(value)
    except TypeError:
        raise vol.Invalid('Not a parseable type')

    if time_val is None:
        raise vol.Invalid('Invalid time specified: {}'.format(value))

    return time_val
Example #35
0
def time(value) -> time_sys:
    """Validate and transform a time."""
    if isinstance(value, time_sys):
        return value

    try:
        time_val = dt_util.parse_time(value)
    except TypeError:
        raise vol.Invalid('Not a parseable type')

    if time_val is None:
        raise vol.Invalid('Invalid time specified: {}'.format(value))

    return time_val
Example #36
0
    def test_time_window(self):
        """Test time condition windows."""
        sixam = dt.parse_time("06:00:00")
        sixpm = dt.parse_time("18:00:00")

        with patch('homeassistant.helpers.condition.dt_util.now',
                   return_value=dt.now().replace(hour=3)):
            assert not condition.time(after=sixam, before=sixpm)
            assert condition.time(after=sixpm, before=sixam)

        with patch('homeassistant.helpers.condition.dt_util.now',
                   return_value=dt.now().replace(hour=9)):
            assert condition.time(after=sixam, before=sixpm)
            assert not condition.time(after=sixpm, before=sixam)

        with patch('homeassistant.helpers.condition.dt_util.now',
                   return_value=dt.now().replace(hour=15)):
            assert condition.time(after=sixam, before=sixpm)
            assert not condition.time(after=sixpm, before=sixam)

        with patch('homeassistant.helpers.condition.dt_util.now',
                   return_value=dt.now().replace(hour=21)):
            assert not condition.time(after=sixam, before=sixpm)
            assert condition.time(after=sixpm, before=sixam)
    async def async_added_to_hass(self):
        """Run when entity about to be added."""
        restore_val = None

        # Priority 1: Initial State
        if self._initial is not None:
            restore_val = self._initial

        # Priority 2: Old state
        if restore_val is None:
            old_state = await async_get_last_state(self.hass, self.entity_id)
            if old_state is not None:
                restore_val = old_state.state

        if restore_val is not None:
            if not self.has_date:
                self._current_datetime = dt_util.parse_time(restore_val)
            elif not self.has_time:
                self._current_datetime = dt_util.parse_date(restore_val)
            else:
                self._current_datetime = dt_util.parse_datetime(restore_val)
Example #38
0
def setup(hass, config):
    """ Set up the iCloud Scanner. """
    
    if config.get(DOMAIN) is None:
        return False

    for account, account_config in config[DOMAIN].items():

        if not isinstance(account_config, dict):
            _LOGGER.error("Missing configuration data for account %s", account)
            continue

        if CONF_USERNAME not in account_config:
            _LOGGER.error("Missing username for account %s", account)
            continue
        
        if CONF_PASSWORD not in account_config:
            _LOGGER.error("Missing password for account %s", account)
            continue
        
        # Get the username and password from the configuration
        username = account_config.get(CONF_USERNAME)
        password = account_config.get(CONF_PASSWORD)
        
        ignored_devices = []
        if 'ignored_devices' in account_config:
            ignored_dev = account_config.get('ignored_devices')
            for each_dev in ignored_dev:
                ignored_devices.append(each_dev)
        
        getevents = account_config.get(CONF_EVENTS, DEFAULT_EVENTS)
        
        icloudaccount = Icloud(hass, username, password, account,
                               ignored_devices, getevents)
        icloudaccount.update_ha_state()
        ICLOUDTRACKERS[account] = icloudaccount
        if ICLOUDTRACKERS[account].api is not None:
            for device in ICLOUDTRACKERS[account].devices:
                iclouddevice = ICLOUDTRACKERS[account].devices[device]
                devicename = iclouddevice.devicename.lower()
                track_state_change(hass,
                                   'device_tracker.' + devicename,
                                   iclouddevice.devicechanged)
                                   
        if 'manual_update' in account_config:
            def update_now(now):
                ICLOUDTRACKERS[account].update_icloud(see)
            
            manual_update = account_config.get('manual_update')
            for each_time in manual_update:
                each_time = dt_util.parse_time(each_time)
                track_time_change(hass, update_now,
                                  hour=each_time.hour,
                                  minute=each_time.minute,
                                  second=each_time.second)
        
    if not ICLOUDTRACKERS:
        _LOGGER.error("No ICLOUDTRACKERS added")
        return False
        
    randomseconds = random.randint(10, 59)
        
    def lost_iphone(call):
        """ Calls the lost iphone function if the device is found """
        accountname = call.data.get('accountname')
        devicename = call.data.get('devicename')
        if accountname in ICLOUDTRACKERS:
            ICLOUDTRACKERS[accountname].lost_iphone(devicename)

    hass.services.register(DOMAIN, 'lost_iphone',
                           lost_iphone)
                           
    def update_icloud(call):
        """ Calls the update function of an icloud account """
        accountname = call.data.get('accountname')
        devicename = call.data.get('devicename')
        if accountname in ICLOUDTRACKERS:
            ICLOUDTRACKERS[accountname].update_icloud(see, devicename)
    hass.services.register(DOMAIN,
                           'update_icloud', update_icloud)
            
    def keep_alive(now):
        """ Keeps the api logged in of all account """
        for accountname in ICLOUDTRACKERS:
            try:
                ICLOUDTRACKERS[accountname].keep_alive()
            except ValueError:
                _LOGGER.info("something went wrong for this account, " +
                             "retrying in a minute")
            
    track_utc_time_change(
        hass, keep_alive,
        second=randomseconds
    )
    
    def setinterval(call):
        """ Calls the update function of an icloud account """
        accountname = call.data.get('accountname')
        interval = call.data.get('interval')
        if accountname in ICLOUDTRACKERS:
            ICLOUDTRACKERS[accountname].setinterval(interval)

    hass.services.register(DOMAIN,
                           'setinterval', setinterval)

    # Tells the bootstrapper that the component was successfully initialized
    return True
def setup(hass, config):
    # pylint: disable=too-many-locals,too-many-return-statements,
    # pylint: disable=too-many-statements,too-many-branches
    """ get the zones and offsets from configuration.yaml"""

    thermostat_controls = []

    # no config found
    if config.get(DOMAIN) is None:
        return False

    for control_location, control_config in config[DOMAIN].items():
        # ============== Thermostat checking ==============
        thermostat_entity = "not set"

        # HA does not have a thermostat
        if len(hass.states.entity_ids('thermostat')) == 0:
            _LOGGER.error('HA does not have any thermostats')
            continue

        # a single thermostat has been found so default to it
        if len(hass.states.entity_ids('thermostat')) == 1:
            thermostat_entity = hass.states.entity_ids('thermostat')[0]
            _LOGGER.error('defaulting to thermostat: %s', thermostat_entity)

        # get the thermostat if it's in the config
        if 'thermostat' in control_config:
            thermostat_entity = ('thermostat.' + control_config['thermostat'])

            # check thermostat exists
            if thermostat_entity not in hass.states.entity_ids('thermostat'):
                _LOGGER.error('thermostat_entity not found')
                continue

        # skip processing if we don't have a thermostat
        if thermostat_entity == "not set":
            continue

        _LOGGER.error('thermostat_entity confirmed: %s', thermostat_entity)

        # ============== Schedule checking ==============
        # Config does not include schedule
        if 'schedule' not in control_config:
            _LOGGER.error('no schedule in config')
            continue

        # get maximum set temperature
        max_temp = control_config.get('max_temp', DEFAULT_MAX_TEMP)
        _LOGGER.error('max_temp set to: %s', max_temp)

        # get minimum set temperature
        min_temp = control_config.get('min_temp', DEFAULT_MIN_TEMP)
        _LOGGER.error('min_temp set to: %s', min_temp)

        # check the timers
        schedule_error = 0
        control_schedule = {}

        for each_time in control_config.get('schedule'):
            each_temp = control_config['schedule'][each_time]

            # incorrectly formatted schedule time, mark as an error
            test_time = dt_util.parse_time(each_time)
            if test_time is None:
                schedule_error = 1
                _LOGGER.error('schedule error: incorrectly formatted time: %s',
                              each_time)
                continue

            # schedule temp exceeds max temp, mark as an error
            if each_temp > max_temp:
                schedule_error = 1
                _LOGGER.error('schedule error: temp exceeds max_temp: %s',
                              each_temp)
                continue

            # schedule temp is lower than min temp, mark as an error
            if each_temp < min_temp:
                schedule_error = 1
                _LOGGER.error('schedule error: temp is lower than min_temp:'
                              '%s', each_temp)
                continue

            control_schedule[each_time] = each_temp
            _LOGGER.error('time: %s temp: %s', each_time, each_temp)

        # skip processing if config does not have a properly formatted time
        if schedule_error == 1:
            continue

        _LOGGER.error('schedule read successfully')

        # ============== Proximity checking ==============
        proximity_zone = "not set"
        dist_offset = DEFAULT_OFFSET
        away_distance = DEFAULT_AWAY
        # do we need to add proximity control
        if 'proximity' in control_config:
            # HA does not have a proximity_zone
            if len(hass.states.entity_ids('proximity')) == 0:
                _LOGGER.error('Error in setup: No proximity_zone entities ' +
                              'exist')
                continue

            # Single Prozimity Zone found
            if len(hass.states.entity_ids('proximity')) == 1:
                proximity_zone = hass.states.entity_ids('proximity')[0]
                _LOGGER.error('defaulting to proximity zone: %s',
                              proximity_zone)

            # get the proximity zone if it's in the config
            if 'zone' in control_config['proximity']:
                proximity_zone = ('proximity.' +
                                  control_config['proximity']['zone'])

                _LOGGER.error('proximity_zone in config: %s', proximity_zone)

            # if proximity_zone is "not set" there is a problem in the config
            if proximity_zone == "not set":
                _LOGGER.error('Error in Config: No Proximity zone found')
                continue

            # check proximity zone we are going to use exists
            if proximity_zone not in hass.states.entity_ids('proximity'):
                _LOGGER.error('Error in Config: Specified proximity zone ' +
                              'does not exist')
                continue
            _LOGGER.error('proximity_zone entity confirmed: %s',
                          proximity_zone)

            # get the distance offset
            if 'distance_offset' in control_config['proximity']:
                dist_offset = control_config['proximity']['distance_offset']
                _LOGGER.error('dist_offset: %s', dist_offset)

            # get the away distance
            if 'away_distance' in control_config['proximity']:
                away_distance = control_config['proximity']['away_distance']
                _LOGGER.error('away_distance: %s', away_distance)

            # config contains neither distance offset nor away distance
            # proximity control is useless
            if dist_offset == DEFAULT_OFFSET and away_distance == DEFAULT_AWAY:
                proximity_zone = "not set"

        # ============== Create the thermostat control entities ==============
        # set the entity ID
        entity_id = DOMAIN + '.' + control_location
        _LOGGER.error('entity_id: %s', entity_id)

        # set the friendly name for the created entity
        friendly_name = control_location

        # we have all the information required, now create the entity
        thermostat_control = Thermostatcontrol(hass, thermostat_entity,
                                               dist_offset, away_distance,
                                               control_schedule,
                                               friendly_name, proximity_zone,
                                               max_temp, min_temp)

        thermostat_control.entity_id = entity_id
        thermostat_control.update_ha_state()
        thermostat_controls.append(thermostat_control)
        thermostat_control.check_initial_state()

        # setup the schedule triggers
        for each_time in control_schedule:
            each_time = dt_util.parse_time(each_time)
            track_time_change(hass, thermostat_control.check_time_change,
                              hour=each_time.hour,
                              minute=each_time.minute,
                              second=each_time.second)
        _LOGGER.error('added time triggers: %s triggers',
                      len(control_schedule))

        # setup the thermostat trigger
        track_state_change(hass, thermostat_control.thermostat_entity,
                           thermostat_control.check_thermostat_change)
        _LOGGER.error('added thermostat trigger: %s', thermostat_entity)

        # setup the proximity trigger if required
        if not proximity_zone == "not set":
            track_state_change(hass, thermostat_control.proximity_zone,
                               thermostat_control.check_proximity_change)
            _LOGGER.error('added proximity trigger: %s', proximity_zone)

    if not thermostat_controls:
        _LOGGER.error('No controls defined')
        return False

    # Tell the bootstrapper that the component was successfully initialized
    return True