1 """Support for Habitica sensors."""
3 from __future__
import annotations
5 from collections.abc
import Callable, Mapping
6 from dataclasses
import dataclass
7 from enum
import StrEnum
9 from typing
import TYPE_CHECKING, Any
12 DOMAIN
as SENSOR_DOMAIN,
15 SensorEntityDescription,
27 from .const
import ASSETS_URL, DOMAIN, UNIT_TASKS
28 from .entity
import HabiticaBase
29 from .types
import HabiticaConfigEntry
30 from .util
import entity_used_in, get_attribute_points, get_attributes_total
32 _LOGGER = logging.getLogger(__name__)
35 @dataclass(kw_only=True, frozen=True)
37 """Habitipy Sensor Description."""
39 value_fn: Callable[[dict[str, Any], dict[str, Any]], StateType]
41 Callable[[dict[str, Any], dict[str, Any]], dict[str, Any] |
None] |
None
43 entity_picture: str |
None =
None
46 @dataclass(kw_only=True, frozen=True)
48 """Habitipy Task Sensor Description."""
50 value_fn: Callable[[list[dict[str, Any]]], list[dict[str, Any]]]
54 """Habitipy Entities."""
56 DISPLAY_NAME =
"display_name"
58 HEALTH_MAX =
"health_max"
61 EXPERIENCE =
"experience"
62 EXPERIENCE_MAX =
"experience_max"
73 INTELLIGENCE =
"intelligence"
74 CONSTITUTION =
"constitution"
75 PERCEPTION =
"perception"
78 SENSOR_DESCRIPTIONS: tuple[HabitipySensorEntityDescription, ...] = (
80 key=HabitipySensorEntity.DISPLAY_NAME,
81 translation_key=HabitipySensorEntity.DISPLAY_NAME,
82 value_fn=
lambda user, _: user.get(
"profile", {}).
get(
"name"),
85 key=HabitipySensorEntity.HEALTH,
86 translation_key=HabitipySensorEntity.HEALTH,
87 native_unit_of_measurement=
"HP",
88 suggested_display_precision=0,
89 value_fn=
lambda user, _: user.get(
"stats", {}).
get(
"hp"),
92 key=HabitipySensorEntity.HEALTH_MAX,
93 translation_key=HabitipySensorEntity.HEALTH_MAX,
94 native_unit_of_measurement=
"HP",
95 entity_registry_enabled_default=
False,
96 value_fn=
lambda user, _: user.get(
"stats", {}).
get(
"maxHealth"),
99 key=HabitipySensorEntity.MANA,
100 translation_key=HabitipySensorEntity.MANA,
101 native_unit_of_measurement=
"MP",
102 suggested_display_precision=0,
103 value_fn=
lambda user, _: user.get(
"stats", {}).
get(
"mp"),
106 key=HabitipySensorEntity.MANA_MAX,
107 translation_key=HabitipySensorEntity.MANA_MAX,
108 native_unit_of_measurement=
"MP",
109 value_fn=
lambda user, _: user.get(
"stats", {}).
get(
"maxMP"),
112 key=HabitipySensorEntity.EXPERIENCE,
113 translation_key=HabitipySensorEntity.EXPERIENCE,
114 native_unit_of_measurement=
"XP",
115 value_fn=
lambda user, _: user.get(
"stats", {}).
get(
"exp"),
118 key=HabitipySensorEntity.EXPERIENCE_MAX,
119 translation_key=HabitipySensorEntity.EXPERIENCE_MAX,
120 native_unit_of_measurement=
"XP",
121 value_fn=
lambda user, _: user.get(
"stats", {}).
get(
"toNextLevel"),
124 key=HabitipySensorEntity.LEVEL,
125 translation_key=HabitipySensorEntity.LEVEL,
126 value_fn=
lambda user, _: user.get(
"stats", {}).
get(
"lvl"),
129 key=HabitipySensorEntity.GOLD,
130 translation_key=HabitipySensorEntity.GOLD,
131 native_unit_of_measurement=
"GP",
132 suggested_display_precision=2,
133 value_fn=
lambda user, _: user.get(
"stats", {}).
get(
"gp"),
136 key=HabitipySensorEntity.CLASS,
137 translation_key=HabitipySensorEntity.CLASS,
138 value_fn=
lambda user, _: user.get(
"stats", {}).
get(
"class"),
139 device_class=SensorDeviceClass.ENUM,
140 options=[
"warrior",
"healer",
"wizard",
"rogue"],
143 key=HabitipySensorEntity.GEMS,
144 translation_key=HabitipySensorEntity.GEMS,
145 value_fn=
lambda user, _: user.get(
"balance", 0) * 4,
146 suggested_display_precision=0,
147 native_unit_of_measurement=
"gems",
148 entity_picture=
"shop_gem.png",
151 key=HabitipySensorEntity.TRINKETS,
152 translation_key=HabitipySensorEntity.TRINKETS,
154 lambda user, _: user.get(
"purchased", {})
156 .
get(
"consecutive", {})
159 suggested_display_precision=0,
160 native_unit_of_measurement=
"⧖",
161 entity_picture=
"notif_subscriber_reward.png",
164 key=HabitipySensorEntity.STRENGTH,
165 translation_key=HabitipySensorEntity.STRENGTH,
168 suggested_display_precision=0,
169 native_unit_of_measurement=
"STR",
172 key=HabitipySensorEntity.INTELLIGENCE,
173 translation_key=HabitipySensorEntity.INTELLIGENCE,
176 suggested_display_precision=0,
177 native_unit_of_measurement=
"INT",
180 key=HabitipySensorEntity.PERCEPTION,
181 translation_key=HabitipySensorEntity.PERCEPTION,
184 suggested_display_precision=0,
185 native_unit_of_measurement=
"PER",
188 key=HabitipySensorEntity.CONSTITUTION,
189 translation_key=HabitipySensorEntity.CONSTITUTION,
192 suggested_display_precision=0,
193 native_unit_of_measurement=
"CON",
201 "challenge":
"challenge",
203 "frequency":
"frequency",
208 "counter_up":
"counterUp",
209 "counter_down":
"counterDown",
210 "next_due":
"nextDue",
211 "yester_daily":
"yesterDaily",
212 "completed":
"completed",
213 "collapse_checklist":
"collapseChecklist",
218 "priority":
"priority",
219 "start_date":
"startDate",
220 "days_of_month":
"daysOfMonth",
221 "weeks_of_month":
"weeksOfMonth",
222 "created_at":
"createdAt",
228 TASK_SENSOR_DESCRIPTION: tuple[HabitipyTaskSensorEntityDescription, ...] = (
230 key=HabitipySensorEntity.HABITS,
231 translation_key=HabitipySensorEntity.HABITS,
232 native_unit_of_measurement=UNIT_TASKS,
233 value_fn=
lambda tasks: [r
for r
in tasks
if r.get(
"type") ==
"habit"],
236 key=HabitipySensorEntity.DAILIES,
237 translation_key=HabitipySensorEntity.DAILIES,
238 native_unit_of_measurement=UNIT_TASKS,
239 value_fn=
lambda tasks: [r
for r
in tasks
if r.get(
"type") ==
"daily"],
240 entity_registry_enabled_default=
False,
243 key=HabitipySensorEntity.TODOS,
244 translation_key=HabitipySensorEntity.TODOS,
245 native_unit_of_measurement=UNIT_TASKS,
246 value_fn=
lambda tasks: [
247 r
for r
in tasks
if r.get(
"type") ==
"todo" and not r.get(
"completed")
249 entity_registry_enabled_default=
False,
252 key=HabitipySensorEntity.REWARDS,
253 translation_key=HabitipySensorEntity.REWARDS,
254 native_unit_of_measurement=UNIT_TASKS,
255 value_fn=
lambda tasks: [r
for r
in tasks
if r.get(
"type") ==
"reward"],
262 config_entry: HabiticaConfigEntry,
263 async_add_entities: AddEntitiesCallback,
265 """Set up the habitica sensors."""
267 coordinator = config_entry.runtime_data
269 entities: list[SensorEntity] = [
270 HabitipySensor(coordinator, description)
for description
in SENSOR_DESCRIPTIONS
274 for description
in TASK_SENSOR_DESCRIPTION
280 """A generic Habitica sensor."""
282 entity_description: HabitipySensorEntityDescription
286 """Return the state of the device."""
289 self.coordinator.data.user, self.coordinator.content
294 """Return entity specific state attributes."""
296 return func(self.coordinator.data.user, self.coordinator.content)
301 """Return the entity picture to use in the frontend, if any."""
303 return f
"{ASSETS_URL}{entity_picture}"
308 """A Habitica task sensor."""
310 entity_description: HabitipyTaskSensorEntityDescription
314 """Return the state of the device."""
320 """Return the state attributes of all user tasks."""
325 self.coordinator.data.tasks
327 task_id = received_task[TASKS_MAP_ID]
329 for map_key, map_value
in TASKS_MAP.items():
330 if value := received_task.get(map_value):
331 task[map_key] = value
332 attrs[task_id] = task
336 """Raise issue when entity is registered and was not disabled."""
339 if entity_id := er.async_get(self.
hasshasshass).async_get_entity_id(
340 SENSOR_DOMAIN, DOMAIN, self.
unique_idunique_id
345 in (HabitipySensorEntity.TODOS, HabitipySensorEntity.DAILIES)
351 f
"deprecated_task_entity_{self.entity_description.key}",
352 breaks_in_ha_version=
"2025.2.0",
354 severity=IssueSeverity.WARNING,
355 translation_key=
"deprecated_task_entity",
356 translation_placeholders={
365 f
"deprecated_task_entity_{self.entity_description.key}",
str|None entity_picture(self)
StateType native_value(self)
dict[str, float|None]|None extra_state_attributes(self)
None async_added_to_hass(self)
Mapping[str, Any]|None extra_state_attributes(self)
StateType native_value(self)
str|UndefinedType|None name(self)
web.Response get(self, web.Request request, str config_key)
None async_setup_entry(HomeAssistant hass, HabiticaConfigEntry config_entry, AddEntitiesCallback async_add_entities)
list[str] entity_used_in(HomeAssistant hass, str entity_id)
dict[str, float] get_attribute_points(dict[str, Any] user, dict[str, Any] content, str attribute)
int get_attributes_total(dict[str, Any] user, dict[str, Any] content, str attribute)
None async_create_issue(HomeAssistant hass, str entry_id)
None async_delete_issue(HomeAssistant hass, str entry_id)