1 """Habitica button platform."""
3 from __future__
import annotations
5 from collections.abc
import Callable
6 from dataclasses
import dataclass
7 from enum
import StrEnum
8 from http
import HTTPStatus
11 from aiohttp
import ClientResponseError
14 DOMAIN
as BUTTON_DOMAIN,
16 ButtonEntityDescription,
23 from .const
import ASSETS_URL, DOMAIN, HEALER, MAGE, ROGUE, WARRIOR
24 from .coordinator
import HabiticaData, HabiticaDataUpdateCoordinator
25 from .entity
import HabiticaBase
26 from .types
import HabiticaConfigEntry
31 @dataclass(kw_only=True, frozen=True)
33 """Describes Habitica button entity."""
35 press_fn: Callable[[HabiticaDataUpdateCoordinator], Any]
36 available_fn: Callable[[HabiticaData], bool] |
None =
None
37 class_needed: str |
None =
None
38 entity_picture: str |
None =
None
42 """Habitica button entities."""
45 BUY_HEALTH_POTION =
"buy_health_potion"
46 ALLOCATE_ALL_STAT_POINTS =
"allocate_all_stat_points"
51 DEFENSIVE_STANCE =
"defensive_stance"
52 VALOROUS_PRESENCE =
"valorous_presence"
53 INTIMIDATE =
"intimidate"
54 TOOLS_OF_TRADE =
"tools_of_trade"
57 PROTECT_AURA =
"protect_aura"
58 BRIGHTNESS =
"brightness"
62 BUTTON_DESCRIPTIONS: tuple[HabiticaButtonEntityDescription, ...] = (
64 key=HabitipyButtonEntity.RUN_CRON,
65 translation_key=HabitipyButtonEntity.RUN_CRON,
66 press_fn=
lambda coordinator: coordinator.api.cron.post(),
67 available_fn=
lambda data: data.user[
"needsCron"],
70 key=HabitipyButtonEntity.BUY_HEALTH_POTION,
71 translation_key=HabitipyButtonEntity.BUY_HEALTH_POTION,
73 lambda coordinator: coordinator.api[
"user"][
"buy-health-potion"].
post()
76 lambda data: data.user[
"stats"][
"gp"] >= 25
77 and data.user[
"stats"][
"hp"] < 50
79 entity_picture=
"shop_potion.png",
82 key=HabitipyButtonEntity.ALLOCATE_ALL_STAT_POINTS,
83 translation_key=HabitipyButtonEntity.ALLOCATE_ALL_STAT_POINTS,
84 press_fn=
lambda coordinator: coordinator.api[
"user"][
"allocate-now"].
post(),
86 lambda data: data.user[
"preferences"].
get(
"automaticAllocation")
is True
87 and data.user[
"stats"][
"points"] > 0
91 key=HabitipyButtonEntity.REVIVE,
92 translation_key=HabitipyButtonEntity.REVIVE,
93 press_fn=
lambda coordinator: coordinator.api[
"user"][
"revive"].
post(),
94 available_fn=
lambda data: data.user[
"stats"][
"hp"] == 0,
99 CLASS_SKILLS: tuple[HabiticaButtonEntityDescription, ...] = (
101 key=HabitipyButtonEntity.MPHEAL,
102 translation_key=HabitipyButtonEntity.MPHEAL,
103 press_fn=
lambda coordinator: coordinator.api.user.class_.cast[
"mpheal"].
post(),
105 lambda data: data.user[
"stats"][
"lvl"] >= 12
106 and data.user[
"stats"][
"mp"] >= 30
109 entity_picture=
"shop_mpheal.png",
112 key=HabitipyButtonEntity.EARTH,
113 translation_key=HabitipyButtonEntity.EARTH,
114 press_fn=
lambda coordinator: coordinator.api.user.class_.cast[
"earth"].
post(),
116 lambda data: data.user[
"stats"][
"lvl"] >= 13
117 and data.user[
"stats"][
"mp"] >= 35
120 entity_picture=
"shop_earth.png",
123 key=HabitipyButtonEntity.FROST,
124 translation_key=HabitipyButtonEntity.FROST,
125 press_fn=
lambda coordinator: coordinator.api.user.class_.cast[
"frost"].
post(),
128 lambda data: data.user[
"stats"][
"lvl"] >= 14
129 and data.user[
"stats"][
"mp"] >= 40
130 and not data.user[
"stats"][
"buffs"][
"streaks"]
133 entity_picture=
"shop_frost.png",
136 key=HabitipyButtonEntity.DEFENSIVE_STANCE,
137 translation_key=HabitipyButtonEntity.DEFENSIVE_STANCE,
139 lambda coordinator: coordinator.api.user.class_.cast[
144 lambda data: data.user[
"stats"][
"lvl"] >= 12
145 and data.user[
"stats"][
"mp"] >= 25
147 class_needed=WARRIOR,
148 entity_picture=
"shop_defensiveStance.png",
151 key=HabitipyButtonEntity.VALOROUS_PRESENCE,
152 translation_key=HabitipyButtonEntity.VALOROUS_PRESENCE,
154 lambda coordinator: coordinator.api.user.class_.cast[
159 lambda data: data.user[
"stats"][
"lvl"] >= 13
160 and data.user[
"stats"][
"mp"] >= 20
162 class_needed=WARRIOR,
163 entity_picture=
"shop_valorousPresence.png",
166 key=HabitipyButtonEntity.INTIMIDATE,
167 translation_key=HabitipyButtonEntity.INTIMIDATE,
169 lambda coordinator: coordinator.api.user.class_.cast[
"intimidate"].
post()
172 lambda data: data.user[
"stats"][
"lvl"] >= 14
173 and data.user[
"stats"][
"mp"] >= 15
175 class_needed=WARRIOR,
176 entity_picture=
"shop_intimidate.png",
179 key=HabitipyButtonEntity.TOOLS_OF_TRADE,
180 translation_key=HabitipyButtonEntity.TOOLS_OF_TRADE,
182 lambda coordinator: coordinator.api.user.class_.cast[
"toolsOfTrade"].
post()
185 lambda data: data.user[
"stats"][
"lvl"] >= 13
186 and data.user[
"stats"][
"mp"] >= 25
189 entity_picture=
"shop_toolsOfTrade.png",
192 key=HabitipyButtonEntity.STEALTH,
193 translation_key=HabitipyButtonEntity.STEALTH,
195 lambda coordinator: coordinator.api.user.class_.cast[
"stealth"].
post()
200 lambda data: data.user[
"stats"][
"lvl"] >= 14
201 and data.user[
"stats"][
"mp"] >= 45
202 and data.user[
"stats"][
"buffs"][
"stealth"]
207 if r.get(
"type") ==
"daily"
208 and r.get(
"isDue")
is True
209 and r.get(
"completed")
is False
214 entity_picture=
"shop_stealth.png",
217 key=HabitipyButtonEntity.HEAL,
218 translation_key=HabitipyButtonEntity.HEAL,
219 press_fn=
lambda coordinator: coordinator.api.user.class_.cast[
"heal"].
post(),
221 lambda data: data.user[
"stats"][
"lvl"] >= 11
222 and data.user[
"stats"][
"mp"] >= 15
223 and data.user[
"stats"][
"hp"] < 50
226 entity_picture=
"shop_heal.png",
229 key=HabitipyButtonEntity.BRIGHTNESS,
230 translation_key=HabitipyButtonEntity.BRIGHTNESS,
232 lambda coordinator: coordinator.api.user.class_.cast[
"brightness"].
post()
235 lambda data: data.user[
"stats"][
"lvl"] >= 12
236 and data.user[
"stats"][
"mp"] >= 15
239 entity_picture=
"shop_brightness.png",
242 key=HabitipyButtonEntity.PROTECT_AURA,
243 translation_key=HabitipyButtonEntity.PROTECT_AURA,
245 lambda coordinator: coordinator.api.user.class_.cast[
"protectAura"].
post()
248 lambda data: data.user[
"stats"][
"lvl"] >= 13
249 and data.user[
"stats"][
"mp"] >= 30
252 entity_picture=
"shop_protectAura.png",
255 key=HabitipyButtonEntity.HEAL_ALL,
256 translation_key=HabitipyButtonEntity.HEAL_ALL,
257 press_fn=
lambda coordinator: coordinator.api.user.class_.cast[
"healAll"].
post(),
259 lambda data: data.user[
"stats"][
"lvl"] >= 14
260 and data.user[
"stats"][
"mp"] >= 25
263 entity_picture=
"shop_healAll.png",
270 entry: HabiticaConfigEntry,
271 async_add_entities: AddEntitiesCallback,
273 """Set up buttons from a config entry."""
275 coordinator = entry.runtime_data
276 skills_added: set[str] = set()
280 """Add or remove a skillset based on the player's class."""
282 nonlocal skills_added
284 entity_registry = er.async_get(hass)
286 for description
in CLASS_SKILLS:
288 coordinator.data.user[
"stats"][
"lvl"] >= 10
289 and coordinator.data.user[
"flags"][
"classSelected"]
290 and not coordinator.data.user[
"preferences"][
"disableClasses"]
291 and description.class_needed == coordinator.data.user[
"stats"][
"class"]
293 if description.key
not in skills_added:
295 skills_added.add(description.key)
296 elif description.key
in skills_added:
297 if entity_id := entity_registry.async_get_entity_id(
300 f
"{coordinator.config_entry.unique_id}_{description.key}",
302 entity_registry.async_remove(entity_id)
303 skills_added.remove(description.key)
308 coordinator.async_add_listener(add_entities)
312 HabiticaButton(coordinator, description)
for description
in BUTTON_DESCRIPTIONS
317 """Representation of a Habitica button."""
319 entity_description: HabiticaButtonEntityDescription
322 """Handle the button press."""
325 except ClientResponseError
as e:
326 if e.status == HTTPStatus.TOO_MANY_REQUESTS:
328 translation_domain=DOMAIN,
329 translation_key=
"setup_rate_limit_exception",
331 if e.status == HTTPStatus.UNAUTHORIZED:
333 translation_domain=DOMAIN,
334 translation_key=
"service_call_unallowed",
337 translation_domain=DOMAIN,
338 translation_key=
"service_call_exception",
345 """Is entity available."""
346 if not super().available:
354 """Return the entity picture to use in the frontend, if any."""
356 return f
"{ASSETS_URL}{entity_picture}"
None async_request_refresh(self)
None add_entities(AsusWrtRouter router, AddEntitiesCallback async_add_entities, set[str] tracked)
web.Response post(self, web.Request request, str config_key)
web.Response get(self, web.Request request, str config_key)