mirror of
https://github.com/home-assistant/core.git
synced 2025-07-28 07:37:34 +00:00
Add button platform to Habitica integration (#121461)
This commit is contained in:
parent
cf4bd7fd1c
commit
ea65ff5876
@ -82,7 +82,7 @@ INSTANCE_LIST_SCHEMA = vol.All(
|
||||
)
|
||||
CONFIG_SCHEMA = vol.Schema({DOMAIN: INSTANCE_LIST_SCHEMA}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
PLATFORMS = [Platform.SENSOR, Platform.TODO]
|
||||
PLATFORMS = [Platform.BUTTON, Platform.SENSOR, Platform.TODO]
|
||||
|
||||
SERVICE_API_CALL_SCHEMA = vol.Schema(
|
||||
{
|
||||
|
150
homeassistant/components/habitica/button.py
Normal file
150
homeassistant/components/habitica/button.py
Normal file
@ -0,0 +1,150 @@
|
||||
"""Habitica button platform."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from enum import StrEnum
|
||||
from http import HTTPStatus
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from aiohttp import ClientResponseError
|
||||
|
||||
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
|
||||
from homeassistant.const import CONF_NAME, CONF_URL
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ServiceValidationError
|
||||
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from . import HabiticaConfigEntry
|
||||
from .const import DOMAIN, MANUFACTURER, NAME
|
||||
from .coordinator import HabiticaData, HabiticaDataUpdateCoordinator
|
||||
|
||||
|
||||
@dataclass(kw_only=True, frozen=True)
|
||||
class HabiticaButtonEntityDescription(ButtonEntityDescription):
|
||||
"""Describes Habitica button entity."""
|
||||
|
||||
press_fn: Callable[[HabiticaDataUpdateCoordinator], Any]
|
||||
available_fn: Callable[[HabiticaData], bool] | None = None
|
||||
|
||||
|
||||
class HabitipyButtonEntity(StrEnum):
|
||||
"""Habitica button entities."""
|
||||
|
||||
RUN_CRON = "run_cron"
|
||||
BUY_HEALTH_POTION = "buy_health_potion"
|
||||
ALLOCATE_ALL_STAT_POINTS = "allocate_all_stat_points"
|
||||
REVIVE = "revive"
|
||||
|
||||
|
||||
BUTTON_DESCRIPTIONS: tuple[HabiticaButtonEntityDescription, ...] = (
|
||||
HabiticaButtonEntityDescription(
|
||||
key=HabitipyButtonEntity.RUN_CRON,
|
||||
translation_key=HabitipyButtonEntity.RUN_CRON,
|
||||
press_fn=lambda coordinator: coordinator.api.cron.post(),
|
||||
available_fn=lambda data: data.user["needsCron"],
|
||||
),
|
||||
HabiticaButtonEntityDescription(
|
||||
key=HabitipyButtonEntity.BUY_HEALTH_POTION,
|
||||
translation_key=HabitipyButtonEntity.BUY_HEALTH_POTION,
|
||||
press_fn=(
|
||||
lambda coordinator: coordinator.api["user"]["buy-health-potion"].post()
|
||||
),
|
||||
available_fn=(
|
||||
lambda data: data.user["stats"]["gp"] >= 25
|
||||
and data.user["stats"]["hp"] < 50
|
||||
),
|
||||
),
|
||||
HabiticaButtonEntityDescription(
|
||||
key=HabitipyButtonEntity.ALLOCATE_ALL_STAT_POINTS,
|
||||
translation_key=HabitipyButtonEntity.ALLOCATE_ALL_STAT_POINTS,
|
||||
press_fn=lambda coordinator: coordinator.api["user"]["allocate-now"].post(),
|
||||
available_fn=(
|
||||
lambda data: data.user["preferences"].get("automaticAllocation") is True
|
||||
and data.user["stats"]["points"] > 0
|
||||
),
|
||||
),
|
||||
HabiticaButtonEntityDescription(
|
||||
key=HabitipyButtonEntity.REVIVE,
|
||||
translation_key=HabitipyButtonEntity.REVIVE,
|
||||
press_fn=lambda coordinator: coordinator.api["user"]["revive"].post(),
|
||||
available_fn=lambda data: data.user["stats"]["hp"] == 0,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: HabiticaConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up buttons from a config entry."""
|
||||
|
||||
coordinator = entry.runtime_data
|
||||
|
||||
async_add_entities(
|
||||
HabiticaButton(coordinator, description) for description in BUTTON_DESCRIPTIONS
|
||||
)
|
||||
|
||||
|
||||
class HabiticaButton(CoordinatorEntity[HabiticaDataUpdateCoordinator], ButtonEntity):
|
||||
"""Representation of a Habitica button."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
entity_description: HabiticaButtonEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: HabiticaDataUpdateCoordinator,
|
||||
entity_description: HabiticaButtonEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize a Habitica button."""
|
||||
super().__init__(coordinator)
|
||||
if TYPE_CHECKING:
|
||||
assert coordinator.config_entry.unique_id
|
||||
self.entity_description = entity_description
|
||||
self._attr_unique_id = (
|
||||
f"{coordinator.config_entry.unique_id}_{entity_description.key}"
|
||||
)
|
||||
self._attr_device_info = DeviceInfo(
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
manufacturer=MANUFACTURER,
|
||||
model=NAME,
|
||||
name=coordinator.config_entry.data[CONF_NAME],
|
||||
configuration_url=coordinator.config_entry.data[CONF_URL],
|
||||
identifiers={(DOMAIN, coordinator.config_entry.unique_id)},
|
||||
)
|
||||
|
||||
async def async_press(self) -> None:
|
||||
"""Handle the button press."""
|
||||
try:
|
||||
await self.entity_description.press_fn(self.coordinator)
|
||||
except ClientResponseError as e:
|
||||
if e.status == HTTPStatus.TOO_MANY_REQUESTS:
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="setup_rate_limit_exception",
|
||||
) from e
|
||||
if e.status == HTTPStatus.UNAUTHORIZED:
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_unallowed",
|
||||
) from e
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="service_call_exception",
|
||||
) from e
|
||||
else:
|
||||
await self.coordinator.async_refresh()
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Is entity available."""
|
||||
if not super().available:
|
||||
return False
|
||||
if self.entity_description.available_fn:
|
||||
return self.entity_description.available_fn(self.coordinator.data)
|
||||
return True
|
@ -8,6 +8,20 @@
|
||||
"default": "mdi:calendar-month"
|
||||
}
|
||||
},
|
||||
"button": {
|
||||
"run_cron": {
|
||||
"default": "mdi:weather-sunset"
|
||||
},
|
||||
"buy_health_potion": {
|
||||
"default": "mdi:flask-round-bottom"
|
||||
},
|
||||
"allocate_all_stat_points": {
|
||||
"default": "mdi:chart-box-outline"
|
||||
},
|
||||
"revive": {
|
||||
"default": "mdi:grave-stone"
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
"display_name": {
|
||||
"default": "mdi:account-circle"
|
||||
|
@ -20,6 +20,20 @@
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
"button": {
|
||||
"run_cron": {
|
||||
"name": "Start my day"
|
||||
},
|
||||
"buy_health_potion": {
|
||||
"name": "Buy a health potion"
|
||||
},
|
||||
"allocate_all_stat_points": {
|
||||
"name": "Allocate all stat points"
|
||||
},
|
||||
"revive": {
|
||||
"name": "Revive from death"
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
"display_name": {
|
||||
"name": "Display name"
|
||||
@ -94,6 +108,12 @@
|
||||
},
|
||||
"setup_rate_limit_exception": {
|
||||
"message": "Currently rate limited, try again later"
|
||||
},
|
||||
"service_call_unallowed": {
|
||||
"message": "Unable to carry out this action, because the required conditions are not met"
|
||||
},
|
||||
"service_call_exception": {
|
||||
"message": "Unable to connect to Habitica, try again later"
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user