Skip to content

Commit

Permalink
Migrate Habitica Dailies and To-Do's to the todo platform (home-assis…
Browse files Browse the repository at this point in the history
…tant#116655)

* Add todo platform

* update for DataUpdateCoordinator

* set lastCron as dailies due date

* parse alternative duedate format

* fix tests

* send notification on item drop

* fix drop message

* update exception messages

* Simplified the update of user_fields by using set union

* move userFields to const

* Issue deprecation only if entity is acutally used

* Resolve issues

* user entity registry to get entity_id

* raise ServiceValidationError

* requested changes

* Move next_due_date helper function to util.py module

* some changes

* Move function to util.py
  • Loading branch information
tr4nt0r authored Jul 7, 2024
1 parent 866cdcc commit 7519355
Show file tree
Hide file tree
Showing 9 changed files with 462 additions and 3 deletions.
2 changes: 1 addition & 1 deletion homeassistant/components/habitica/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def has_all_unique_users_names(value):
)
CONFIG_SCHEMA = vol.Schema({DOMAIN: INSTANCE_LIST_SCHEMA}, extra=vol.ALLOW_EXTRA)

PLATFORMS = [Platform.SENSOR]
PLATFORMS = [Platform.SENSOR, Platform.TODO]

SERVICE_API_CALL_SCHEMA = vol.Schema(
{
Expand Down
3 changes: 3 additions & 0 deletions homeassistant/components/habitica/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
CONF_API_USER = "api_user"

DEFAULT_URL = "https://habitica.com"
ASSETS_URL = "https://habitica-assets.s3.amazonaws.com/mobileApp/images/"
DOMAIN = "habitica"

# service constants
Expand All @@ -18,3 +19,5 @@

MANUFACTURER = "HabitRPG, Inc."
NAME = "Habitica"

ADDITIONAL_USER_FIELDS: set[str] = {"lastCron"}
5 changes: 3 additions & 2 deletions homeassistant/components/habitica/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import DOMAIN
from .const import ADDITIONAL_USER_FIELDS, DOMAIN

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -43,11 +43,12 @@ def __init__(self, hass: HomeAssistant, habitipy: HabitipyAsync) -> None:
self.api = habitipy

async def _async_update_data(self) -> HabiticaData:
user_fields = set(self.async_contexts())
user_fields = set(self.async_contexts()) | ADDITIONAL_USER_FIELDS

try:
user_response = await self.api.user.get(userFields=",".join(user_fields))
tasks_response = await self.api.tasks.user.get()
tasks_response.extend(await self.api.tasks.user.get(type="completedTodos"))
except ClientResponseError as error:
raise UpdateFailed(f"Error communicating with API: {error}") from error

Expand Down
8 changes: 8 additions & 0 deletions homeassistant/components/habitica/icons.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
{
"entity": {
"todo": {
"todos": {
"default": "mdi:checkbox-outline"
},
"dailys": {
"default": "mdi:calendar-month"
}
},
"sensor": {
"display_name": {
"default": "mdi:account-circle"
Expand Down
42 changes: 42 additions & 0 deletions homeassistant/components/habitica/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,29 @@
from typing import TYPE_CHECKING, cast

from homeassistant.components.sensor import (
DOMAIN as SENSOR_DOMAIN,
SensorDeviceClass,
SensorEntity,
SensorEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_NAME, CONF_URL
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.issue_registry import (
IssueSeverity,
async_create_issue,
async_delete_issue,
)
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.update_coordinator import CoordinatorEntity

from . import HabiticaConfigEntry
from .const import DOMAIN, MANUFACTURER, NAME
from .coordinator import HabiticaDataUpdateCoordinator
from .util import entity_used_in

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -255,6 +263,7 @@ def native_value(self):
task
for task in self.coordinator.data.tasks
if task.get("type") in self._task_type.path
and not task.get("completed")
]
)

Expand All @@ -278,3 +287,36 @@ def extra_state_attributes(self):
def native_unit_of_measurement(self):
"""Return the unit the value is expressed in."""
return self._task_type.unit

async def async_added_to_hass(self) -> None:
"""Raise issue when entity is registered and was not disabled."""
if TYPE_CHECKING:
assert self.unique_id
if entity_id := er.async_get(self.hass).async_get_entity_id(
SENSOR_DOMAIN, DOMAIN, self.unique_id
):
if (
self.enabled
and self._task_name in ("todos", "dailys")
and entity_used_in(self.hass, entity_id)
):
async_create_issue(
self.hass,
DOMAIN,
f"deprecated_task_entity_{self._task_name}",
breaks_in_ha_version="2025.2.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="deprecated_task_entity",
translation_placeholders={
"task_name": self._task_name,
"entity": entity_id,
},
)
else:
async_delete_issue(
self.hass,
DOMAIN,
f"deprecated_task_entity_{self._task_name}",
)
await super().async_added_to_hass()
38 changes: 38 additions & 0 deletions homeassistant/components/habitica/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,51 @@
"rogue": "Rogue"
}
}
},
"todo": {
"todos": {
"name": "To-Do's"
},
"dailys": {
"name": "Dailies"
}
}
},
"exceptions": {
"delete_todos_failed": {
"message": "Unable to delete {count} Habitica to-do(s), please try again"
},
"move_todos_item_failed": {
"message": "Unable to move the Habitica to-do to position {pos}, please try again"
},
"move_dailys_item_failed": {
"message": "Unable to move the Habitica daily to position {pos}, please try again"
},
"update_todos_item_failed": {
"message": "Unable to update the Habitica to-do `{name}`, please try again"
},
"update_dailys_item_failed": {
"message": "Unable to update the Habitica daily `{name}`, please try again"
},
"score_todos_item_failed": {
"message": "Unable to update the score for your Habitica to-do `{name}`, please try again"
},
"score_dailys_item_failed": {
"message": "Unable to update the score for your Habitica daily `{name}`, please try again"
},
"create_todos_item_failed": {
"message": "Unable to create new to-do `{name}` for Habitica, please try again"
},
"setup_rate_limit_exception": {
"message": "Currently rate limited, try again later"
}
},
"issues": {
"deprecated_task_entity": {
"title": "The Habitica `{task_name}` sensor is deprecated",
"description": "The Habitica entity `{entity}` is deprecated and will be removed in `2024.12`.\nPlease update your automations and scripts to replace the sensor entity with the newly added todo entity.\nWhen you are done migrating you can disable `{entity}`."
}
},
"services": {
"api_call": {
"name": "API name",
Expand Down
Loading

0 comments on commit 7519355

Please sign in to comment.