Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add calendar platform to Habitica integration #128248

Open
wants to merge 16 commits into
base: dev
Choose a base branch
from

Conversation

tr4nt0r
Copy link
Contributor

@tr4nt0r tr4nt0r commented Oct 12, 2024

Proposed change

This adds the calendar platform to the Habitica integration and adds three calendar entities.

To-do's:

Provides due dates of to-dos as a calendar. Due dates are all-day events.

Dailies

Provides a calendar listing with all dailies for today and all future recurrences of dailies. Dailies for today will only be listed as long as they were not completed. The state of the calendar entity will be on as long as there is still tasks to do for the day and off when all is done.

Reminders

Habitica dailies and to-dos allow setting reminders, these will be listed in this calendar, displaying the name of the event the reminder belongs to. Reminders don't have a duration, but the calendar status will show reminders as active for up to 1hr, unless another reminder goes off.

Removed for now, needs some more tweaking, will be added in separate PR

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New integration (thank you!)
  • New feature (which adds functionality to an existing integration)
  • Deprecation (breaking change to happen in the future)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

Checklist

  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • I have followed the perfect PR recommendations
  • The code has been formatted using Ruff (ruff format homeassistant tests)
  • Tests have been added to verify that the new code works.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • The manifest file has all fields filled out correctly.
    Updated and included derived files by running: python3 -m script.hassfest.
  • New or updated dependencies have been added to requirements_all.txt.
    Updated by running python3 -m script.gen_requirements_all.
  • For the updated dependencies - a link to the changelog, or at minimum a diff between library versions is added to the PR description.

To help with the load of incoming pull requests:

@home-assistant
Copy link

Hey there @asmfreak, @leikoilja, mind taking a look at this pull request as it has been labeled with an integration (habitica) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of habitica can trigger bot actions by commenting:

  • @home-assistant close Closes the pull request.
  • @home-assistant rename Awesome new title Renames the pull request.
  • @home-assistant reopen Reopen the pull request.
  • @home-assistant unassign habitica Removes the current integration label and assignees on the pull request, add the integration domain after the command.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component) to the pull request.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component) on the pull request.

homeassistant/components/habitica/calendar.py Outdated Show resolved Hide resolved
homeassistant/components/habitica/calendar.py Outdated Show resolved Hide resolved
homeassistant/components/habitica/calendar.py Outdated Show resolved Hide resolved
homeassistant/components/habitica/calendar.py Outdated Show resolved Hide resolved
homeassistant/components/habitica/calendar.py Outdated Show resolved Hide resolved
@home-assistant home-assistant bot marked this pull request as draft October 13, 2024 06:00
@home-assistant
Copy link

Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍

Learn more about our pull request process.

@tr4nt0r tr4nt0r marked this pull request as ready for review October 13, 2024 14:35
homeassistant/components/habitica/calendar.py Outdated Show resolved Hide resolved
homeassistant/components/habitica/calendar.py Outdated Show resolved Hide resolved
homeassistant/components/habitica/calendar.py Show resolved Hide resolved
"""Return calendar events within a datetime range."""

today = to_date(self.coordinator.data.user["lastCron"])
# returns only todays and future dailies.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also is not meeting the get_event spec. get_events should work for any start/end date range. A calendar can render events from the past as well, and triggers work based on past events.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Habitica the start of the day can be set to a different time (in my account it is 4:00 am for example. If at that time all dailies that were due have been completed the cron runs at 4 and resets all dailies, marking the start of the day. If there are incompleted dailies from the past day (called yesterdailies), the user gets a last chance to mark tasks as completed (in case the task was done but forgotten to mark as completed) and then the user presses the button 'start my day', which then marks the start of the day. That's what I want to reflect here.
That's also why it doesn't make sense to render events from the past, dailies are reset every day.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also there is no data about past dailies. I could generate events based on the current recurrence settings but that would be a wild guess, because they can be changed anytime and I don't know if they were possibly different in the past

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, though completed tasks should probably still be returned here, consistent with how other todos on calendar show up. If needed, we can add more rfc5545 attributes to calendar events and render them different in the UI in the future.

I don't really see that we need to bring in the cron stuff here, rather than ignoring it and letting it show up on the calendar how it shows up on the calendar. (t's very hard to reason about given it seems independent of the recurrence rule and not on a single timeline, so maybe i'm missing it). It feels like its trying to implement todo status tracking and i think we should just add support for todo status tracking if we want that.

I'm worried getting fancy here and not following the spec is going to break triggers/automations since it expects this to be confirming

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't the triggers based on the calendar entities on/off state?
I checked the Todoist integration, it also provides a calendar for tasks with due dates. If a task is completed, it is not shown in the calendar view anymore. That's as far as I can see the only other integration that implements a calendar for tasks. Maybe in the future we could render completed tasks in the calendar in grey, that would be a cool feature, but for now I would prefer to do it like the Todoist integration does it already.

I can't ignore the cron. I need it to determine on what day to render the tasks. That's the only way to know if the task is from yesterday or from today.

@home-assistant home-assistant bot marked this pull request as draft October 13, 2024 15:03
@allenporter
Copy link
Contributor

I realize what you're effectively wanting here is a different behavior from calendar events, given these are todos. This hasn't really been agreed upon, so i'm reviewing this in the currently defined calendar event spec. There is a proposed recurring todo spec here but it hasn't really been decided upon yet.

@tr4nt0r
Copy link
Contributor Author

tr4nt0r commented Oct 13, 2024

I realize what you're effectively wanting here is a different behavior from calendar events, given these are todos. This hasn't really been agreed upon, so i'm reviewing this in the currently defined calendar event spec. There is a proposed recurring todo spec here but it hasn't really been decided upon yet.

Had a quick look and I think that sounds promising. If it gets approved I'm eager to implement it for Habitica 😁

@tr4nt0r tr4nt0r marked this pull request as ready for review October 14, 2024 02:39
homeassistant/components/habitica/calendar.py Outdated Show resolved Hide resolved
homeassistant/components/habitica/calendar.py Show resolved Hide resolved
homeassistant/components/habitica/calendar.py Outdated Show resolved Hide resolved
events = [
CalendarEvent(
start=next_recurrence.date(),
end=self.calculate_end_date(next_recurrence),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should always be next_recurrence.date() + timedelta(days=1)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intention is, if there still are unresolved tasks from yesterday, they are still the active tasks, so the enddate is the end of today so the state of the entity stays on. Until these aren't resolved by either completing or skipping them and then starting the new day, the tasks for today are still not the active or next upcoming tasks, they are calculated "future" recurrences. When the daily tasks are reset, the state will advance to the next task that is due.
I know it sounds a bit complicated or I may not be the best in explaining. Maybe this is more helpful https://habitica.fandom.com/wiki/Cron

for task in self.coordinator.data.tasks
if task["type"] == HabiticaTaskType.DAILY and task["everyX"]
for recurrence in build_rrule(task).between(start_date, end_date, inc=True)
if (start := recurrence.date()) > self.today.date()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

given between above, is this greater than check needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is, to differentiate todays active tasks from the future calculated recurrences.

homeassistant/components/habitica/calendar.py Outdated Show resolved Hide resolved
"""Return calendar events within a datetime range."""

today = to_date(self.coordinator.data.user["lastCron"])
# returns only todays and future dailies.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, though completed tasks should probably still be returned here, consistent with how other todos on calendar show up. If needed, we can add more rfc5545 attributes to calendar events and render them different in the UI in the future.

I don't really see that we need to bring in the cron stuff here, rather than ignoring it and letting it show up on the calendar how it shows up on the calendar. (t's very hard to reason about given it seems independent of the recurrence rule and not on a single timeline, so maybe i'm missing it). It feels like its trying to implement todo status tracking and i think we should just add support for todo status tracking if we want that.

I'm worried getting fancy here and not following the spec is going to break triggers/automations since it expects this to be confirming

homeassistant/components/habitica/util.py Outdated Show resolved Hide resolved
def extra_state_attributes(self) -> dict[str, bool] | None:
"""Return entity specific state attributes."""
if event := self.event:
return {"yesterdaily": event.start < date.today()}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attributes should always be returned, but may have a None value. See home-assistant/architecture#680

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll change that, no problem. But the default state attributes itself aren't returned either if there is no upcoming task. So Home Assistant seems inconsistent here.

image

@home-assistant home-assistant bot marked this pull request as draft October 22, 2024 04:13
@tr4nt0r tr4nt0r marked this pull request as ready for review October 22, 2024 22:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants