Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions appdaemon/adapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@
from pathlib import Path
from typing import TYPE_CHECKING, Any, Literal, TypeVar, overload

from appdaemon import dependency
from appdaemon import dependency, utils
from appdaemon import exceptions as ade
from appdaemon import utils
from appdaemon.appdaemon import AppDaemon
from appdaemon.entity import Entity
from appdaemon.events import EventCallback
from appdaemon.logging import Logging
from appdaemon.models.config.app import AppConfig
from appdaemon.parse import resolve_time_str
from appdaemon.state import StateCallbackType

from .types import TimeDeltaLike

T = TypeVar("T")
Expand Down Expand Up @@ -3225,6 +3225,7 @@ async def run_every(
start: str | dt.time | dt.datetime | None = None,
interval: TimeDeltaLike = 0,
*args,
immediate: bool = False,
random_start: TimeDeltaLike | None = None,
random_end: TimeDeltaLike | None = None,
pin: bool | None = None,
Expand Down Expand Up @@ -3257,6 +3258,8 @@ async def run_every(
- If this is a ``timedelta`` object, the current date will be assumed.

*args: Arbitrary positional arguments to be provided to the callback function when it is triggered.
immediate (bool, optional): Whether to immediately fire the callback or wait until the first interval if the
start time is now.
random_start (int, optional): Start of range of the random time.
random_end (int, optional): End of range of the random time.
pin (bool, optional): Optional setting to override the default thread pinning behavior. By default, this is
Expand Down Expand Up @@ -3310,7 +3313,7 @@ def timed_callback(self, **kwargs): ... # example callback

"""
interval = utils.parse_timedelta(interval)
next_period = await self.AD.sched.get_next_period(interval, start)
next_period = await self.AD.sched.get_next_period(interval, start, immediate=immediate)

self.logger.debug(
"Registering %s for run_every in %s intervals, starting %s",
Expand Down
6 changes: 4 additions & 2 deletions appdaemon/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,8 @@ async def get_next_period(
self,
interval: TimeDeltaLike,
start: time | datetime | str | None = None,
*,
immediate: bool = False,
) -> datetime:
interval = utils.parse_timedelta(interval)
start = "now" if start is None else start
Expand All @@ -493,7 +495,7 @@ async def get_next_period(
assert isinstance(aware_start, datetime) and aware_start.tzinfo is not None

# Skip forward to the next period if start is in the past
while aware_start < now:
while aware_start < now or (immediate and aware_start <= now):
aware_start += interval

return aware_start
Expand Down Expand Up @@ -901,7 +903,7 @@ async def parse_datetime(
# Need to force timezone during time-travel mode
if now is None:
now = await self.get_now()
now = now.astimezone(self.AD.tz)
now = utils.ensure_timezone(now, self.AD.tz)
return parse.parse_datetime(
input_=input_,
now=now,
Expand Down
1 change: 1 addition & 0 deletions docs/HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- Reload modified apps on SIGUSR2 - contributed by [chatziko](https://github.com/chatziko)
- Using urlib to create endpoints from URLs - contributed by [cebtenzzre](https://github.com/cebtenzzre)
- Added {py:meth}`~appdaemon.plugins.hass.hassapi.Hass.process_conversation` and {py:meth}`~appdaemon.plugins.hass.hassapi.Hass.reload_conversation` to the {ref}`Hass API <hass-api-usage>`.
- Added `immediate` kwargs to `run_every` to control semantics around `start == "now"`

**Fixes**

Expand Down
Loading