Unexpected 36-Minute Offset in run_daily Scheduler on Raspberry Pi 5 (HAOS, Python 3.12, ARM64)
What happened?
Describe the bug There is a consistent and repeatable 36-minute offset when scheduling callbacks using run_daily() in AppDaemon on Raspberry Pi 5 with Home Assistant OS (HAOS). The system time, Home Assistant time, and AppDaemon logs all show the correct time, but the callback scheduled by run_daily always fires exactly 36 minutes later than the time specified in the YAML configuration.
Environment
- Hardware: Raspberry Pi 5 (64-bit, ARM)
- Home Assistant OS version: 16.0
- AppDaemon version: 4.5.11 (official addon)
- Python version (as in AppDaemon logs): 3.12.11
- Home Assistant Core version: 2025.7.2
- System time: Confirmed correct with date and in AppDaemon logs
How to reproduce the issue
-
Install AppDaemon 4.x as an official add-on on Home Assistant OS running on a Raspberry Pi 5.
-
Create a simple app, e.g.:
import appdaemon.plugins.hass.hassapi as hass import datetime class LightTimer(hass.Hass): def initialize(self): self.on_time = self.args.get("on_time", "10:00:00") parsed_on = self.parse_time(self.on_time) self.log(f"Parsed on_time: {parsed_on}") self.run_daily(self.turn_on_light, parsed_on) def turn_on_light(self, kwargs): self.log("Light should turn on now.") -
Configure apps.yaml:
light_timer: module: light_timer class: LightTimer light: light.xyz on_time: "10:00:00" -
Restart AppDaemon.
-
Observe that in the AppDaemon UI ("Scheduler Callbacks"), the scheduled time for the callback is always 10:36:00 when "10:00:00" is set, and so on (always +36 minutes).
Observed behavior
- The scheduled callback is always +36 minutes later than the requested time, regardless of the value specified.
- The offset is always exactly 36 minutes (e.g. 09:10:00 becomes 09:46:00, 12:12:00 becomes 12:48:00).
- All system, Home Assistant, and AppDaemon times are correct and in sync.
- No stubs, duplicates, or timezone inconsistencies in configuration.
Expected behavior
- run_daily should schedule the callback at the time specified (e.g. 10:00:00).
Workaround Currently, I am manually subtracting 36 minutes in my app code:
import datetime
parsed_on = self.parse_time(self.on_time)
fixed_on = (datetime.datetime.combine(datetime.date.today(), parsed_on) - datetime.timedelta(minutes=36)).time()
self.run_daily(self.turn_on_light, fixed_on)
But this is just a workaround for a deeper issue.
Additional info
- Full restart of the system does not resolve the issue.
- The problem is present on Raspberry Pi 5, Home Assistant OS 16.0, Python 3.12.11.
- The same code on older hardware or with older versions of AppDaemon/Python does not show this bug.
- No error messages, just the consistent scheduling offset.
Version
4.5.11
Installation type
Home Assistant add-on
Relevant log output
Relevant code in the app or config file that caused the issue
Anything else?
No response
I have the same issue, but in my case it is exactly 67 minutes late.
In my case, I'm using AMD64 hardware for executing AppDaemon in a Docker container.
This was no issue with AppDaemon 4.5.10, but since updating to 4.5.11 the issue happens every time.
I have a run_every(self.my_callback, datetime.time(0, 0)) to execute every day at exactly 00:00. But the callback gets called at 01:07. The same issue with another run_every() at 21:30 which is then called at 22:37.
The issue could be caused by this change which was introduced in 4.5.11: https://github.com/AppDaemon/appdaemon/commit/d135bfe4e6346902935d5349935dea90f0f1cf70
I also have the same issue
+1 (67 minutes for me as well, docker container on raspberry pi)
A temporary fix is to skip the time parsing and let AppDaemon do it for you:
So instead of:
def initialize(self):
self.on_time = self.args.get("on_time", "10:00:00")
parsed_on = self.parse_time(self.on_time)
self.log(f"Parsed on_time: {parsed_on}")
self.run_daily(self.turn_on_light, parsed_on)
use this:
def initialize(self):
self.on_time = self.args.get("on_time", "10:00:00")
self.run_daily(self.turn_on_light, self.on_time)
This is because AppDaemon is using pytz incorrectly. The workaround is to never pass a datetime.time to run_daily (or run_hourly or any of the other methods that uses a start argument). Instead, construct a datetime.datetime object and pass it. Something like this should work:
date = datetime.datetime.now().date()
time = datetime.time(10, 0, 0)
when = self.AD.tz.localize(datetime.datetime.combine(date, time))
self.run_daily(self.turn_on_light, when)
If I'm reading the code correctly, AppDaemon tries to convert the datetime.time object to a datetime.datetime like this, when all abstractions are removed:
zone = pytz.timezone("Europe/Stockholm") # or whatever timezone you are using
if start.tzinfo is None:
start = start.replace(tzinfo=zone)
now = datetime.datetime.now(zone)
now = now.astimezone(zone)
now = now.date()
d = datetime.datetime.combine(now, start)
It then uses d to schedule the callback. (It doesn't actually use the above variable names, though.)
But this isn't allowed. The pytz documentation says:
This library only supports two ways of building a localized time. The first is to use the
localize()method provided by the pytz library. [...] The second way of building a localized time is by converting an existing localized time using the standardastimezone()method
Source: https://pypi.org/project/pytz
This web page has a lot to say about time zones in Python, and it was a very helpful resource when I tried to understand this issue: https://initialxy.com/lesson/2022/03/18/getting-the-right-time-zone-in-python
See also https://stackoverflow.com/questions/50443305/why-do-i-get-the-offset-053-for-timezone-europe-berlin
Thanks for the analysis! We should have a fix out for this shortly.
Maybe it's related to my problem: https://github.com/AppDaemon/appdaemon/issues/2390
@brazoayeye - yes, we believe this is the same issue.
This should all work as expected now
Should be fixed by #2515