Skip to content

Commit 0d85f54

Browse files
authored
Add sensors for inventory items to Habitica (#135331)
Add sensors for inventory items
1 parent b3af12c commit 0d85f54

File tree

7 files changed

+566
-5
lines changed

7 files changed

+566
-5
lines changed

homeassistant/components/habitica/icons.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,27 @@
138138
},
139139
"constitution": {
140140
"default": "mdi:run-fast"
141+
},
142+
"food_total": {
143+
"default": "mdi:candy",
144+
"state": {
145+
"0": "mdi:candy-off"
146+
}
147+
},
148+
"eggs_total": {
149+
"default": "mdi:egg",
150+
"state": {
151+
"0": "mdi:egg-off"
152+
}
153+
},
154+
"hatching_potions_total": {
155+
"default": "mdi:flask-round-bottom"
156+
},
157+
"saddle": {
158+
"default": "mdi:horse"
159+
},
160+
"quest_scrolls": {
161+
"default": "mdi:script-text-outline"
141162
}
142163
},
143164
"switch": {

homeassistant/components/habitica/sensor.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
from .const import ASSETS_URL
3030
from .entity import HabiticaBase
3131
from .types import HabiticaConfigEntry
32-
from .util import get_attribute_points, get_attributes_total
32+
from .util import get_attribute_points, get_attributes_total, inventory_list
3333

3434
_LOGGER = logging.getLogger(__name__)
3535

@@ -73,6 +73,11 @@ class HabiticaSensorEntity(StrEnum):
7373
INTELLIGENCE = "intelligence"
7474
CONSTITUTION = "constitution"
7575
PERCEPTION = "perception"
76+
EGGS_TOTAL = "eggs_total"
77+
HATCHING_POTIONS_TOTAL = "hatching_potions_total"
78+
FOOD_TOTAL = "food_total"
79+
SADDLE = "saddle"
80+
QUEST_SCROLLS = "quest_scrolls"
7681

7782

7883
SENSOR_DESCRIPTIONS: tuple[HabiticaSensorEntityDescription, ...] = (
@@ -179,6 +184,44 @@ class HabiticaSensorEntity(StrEnum):
179184
suggested_display_precision=0,
180185
native_unit_of_measurement="CON",
181186
),
187+
HabiticaSensorEntityDescription(
188+
key=HabiticaSensorEntity.EGGS_TOTAL,
189+
translation_key=HabiticaSensorEntity.EGGS_TOTAL,
190+
value_fn=lambda user, _: sum(n for n in user.items.eggs.values()),
191+
entity_picture="Pet_Egg_Egg.png",
192+
attributes_fn=lambda user, content: inventory_list(user, content, "eggs"),
193+
),
194+
HabiticaSensorEntityDescription(
195+
key=HabiticaSensorEntity.HATCHING_POTIONS_TOTAL,
196+
translation_key=HabiticaSensorEntity.HATCHING_POTIONS_TOTAL,
197+
value_fn=lambda user, _: sum(n for n in user.items.hatchingPotions.values()),
198+
entity_picture="Pet_HatchingPotion_RoyalPurple.png",
199+
attributes_fn=(
200+
lambda user, content: inventory_list(user, content, "hatchingPotions")
201+
),
202+
),
203+
HabiticaSensorEntityDescription(
204+
key=HabiticaSensorEntity.FOOD_TOTAL,
205+
translation_key=HabiticaSensorEntity.FOOD_TOTAL,
206+
value_fn=(
207+
lambda user, _: sum(n for k, n in user.items.food.items() if k != "Saddle")
208+
),
209+
entity_picture="Pet_Food_Strawberry.png",
210+
attributes_fn=lambda user, content: inventory_list(user, content, "food"),
211+
),
212+
HabiticaSensorEntityDescription(
213+
key=HabiticaSensorEntity.SADDLE,
214+
translation_key=HabiticaSensorEntity.SADDLE,
215+
value_fn=lambda user, _: user.items.food.get("Saddle", 0),
216+
entity_picture="Pet_Food_Saddle.png",
217+
),
218+
HabiticaSensorEntityDescription(
219+
key=HabiticaSensorEntity.QUEST_SCROLLS,
220+
translation_key=HabiticaSensorEntity.QUEST_SCROLLS,
221+
value_fn=(lambda user, _: sum(n for n in user.items.quests.values())),
222+
entity_picture="inventory_quest_scroll_dustbunnies.png",
223+
attributes_fn=lambda user, content: inventory_list(user, content, "quests"),
224+
),
182225
)
183226

184227

homeassistant/components/habitica/strings.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,26 @@
310310
"name": "[%key:component::habitica::entity::sensor::strength::state_attributes::buffs::name%]"
311311
}
312312
}
313+
},
314+
"eggs_total": {
315+
"name": "Eggs",
316+
"unit_of_measurement": "eggs"
317+
},
318+
"hatching_potions_total": {
319+
"name": "Hatching potions",
320+
"unit_of_measurement": "potions"
321+
},
322+
"food_total": {
323+
"name": "Pet food",
324+
"unit_of_measurement": "foods"
325+
},
326+
"saddle": {
327+
"name": "Saddles",
328+
"unit_of_measurement": "saddles"
329+
},
330+
"quest_scrolls": {
331+
"name": "Quest scrolls",
332+
"unit_of_measurement": "scrolls"
313333
}
314334
},
315335
"switch": {

homeassistant/components/habitica/util.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,14 @@ def get_attributes_total(user: UserData, content: ContentData, attribute: str) -
159159
return floor(
160160
sum(value for value in get_attribute_points(user, content, attribute).values())
161161
)
162+
163+
164+
def inventory_list(
165+
user: UserData, content: ContentData, item_type: str
166+
) -> dict[str, int]:
167+
"""List inventory items of given type."""
168+
return {
169+
getattr(content, item_type)[k].text: v
170+
for k, v in getattr(user.items, item_type, {}).items()
171+
if k != "Saddle"
172+
}

tests/components/habitica/fixtures/content.json

Lines changed: 195 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,109 @@
370370
"animalSetAchievements": {},
371371
"stableAchievements": {},
372372
"petSetCompleteAchievs": [],
373-
"quests": {},
373+
"quests": {
374+
"atom1": {
375+
"text": "Angriff des Banalen, Teil 1: Abwasch-Katastrophe!",
376+
"notes": "Du erreichst die Ufer des Waschbeckensees für eine wohlverdiente Auszeit ... Aber der See ist verschmutzt mit nicht abgespültem Geschirr! Wie ist das passiert? Wie auch immer, Du kannst den See jedenfalls nicht in diesem Zustand lassen. Es gibt nur eine Sache die Du tun kannst: Abspülen und den Ferienort retten! Dazu musst Du aber Seife für den Abwasch finden. Viel Seife ...",
377+
"completion": "Nach gründlichem Schrubben ist das Geschirr sicher am Ufer gestapelt! Du trittst zurück und begutachtest stolz Deiner Hände Arbeit.",
378+
"group": "questGroupAtom",
379+
"prerequisite": {
380+
"lvl": 15
381+
},
382+
"value": 4,
383+
"lvl": 15,
384+
"category": "unlockable",
385+
"collect": {
386+
"soapBars": {
387+
"text": "Seifenstücke",
388+
"count": 20
389+
}
390+
},
391+
"drop": {
392+
"items": [
393+
{
394+
"type": "quests",
395+
"key": "atom2",
396+
"text": "Das Monster vom KochLess (Schriftrolle)",
397+
"onlyOwner": true
398+
}
399+
],
400+
"gp": 7,
401+
"exp": 50
402+
},
403+
"key": "atom1"
404+
},
405+
"goldenknight1": {
406+
"text": "Die goldene Ritterin, Teil 1: Ein ernstes Gespräch",
407+
"notes": "Die goldene Ritterin ist Habiticanern mit ihrer Kritik ganz schön auf die Nerven gegangen. Nicht alle Tagesaufgaben erledigt? Eine negative Gewohnheit angeklickt? Sie nimmt dies zum Anlass Dich zu bedrängen, dass Du doch ihrem Beispiel folgen sollst. Sie ist das leuchtende Beispiel eines perfekten Habiticaners und Du bist nichts als ein Versager. Das ist ja mal gar nicht nett! Jeder macht Fehler. Man sollte deshalb nicht mit solcher Kritik drangsaliert werden. Vielleicht solltest Du einige Zeugenaussagen von verletzten Habiticanern zusammentragen und die Goldene Ritterin mal ordentlich zurechtweisen!",
408+
"completion": "Schau Dir nur all diese Zeugenaussagen an! Bestimmt wird das reichen, um die Goldene Ritterin zu überzeugen. Nun musst Du sie nur noch finden.",
409+
"group": "questGroupGoldenknight",
410+
"value": 4,
411+
"lvl": 40,
412+
"category": "unlockable",
413+
"collect": {
414+
"testimony": {
415+
"text": "Zeugenaussagen",
416+
"count": 60
417+
}
418+
},
419+
"drop": {
420+
"items": [
421+
{
422+
"type": "quests",
423+
"key": "goldenknight2",
424+
"text": "Die goldene Ritterin Teil 2: Die goldene Ritterin (Schriftrolle)",
425+
"onlyOwner": true
426+
}
427+
],
428+
"gp": 15,
429+
"exp": 120
430+
},
431+
"key": "goldenknight1"
432+
},
433+
"dustbunnies": {
434+
"text": "Die ungezähmten Staubmäuse",
435+
"notes": "Es ist schon etwas her, seit Du hier drinnen das letzte Mal Staub gewischt hast, aber Du sorgst dich nicht allzusehr - ein Wenig Staub hat noch nie jemandem geschadet, oder? Erst, als Du Deine Hand in eine der staubigsten Ecken steckst und einen Biss spürst, erinnerst du dich an @InspectorCaracals Warnung: Harmlosen Staub zu lange in Ruhe zu lassen, verwandelt ihn in boshafte Staubmäuse! Du solltest sie besser besiegen, bevor sie ganz Habitica mit feinen Schmutzpartikeln bedecken!",
436+
"group": "questGroupEarnable",
437+
"completion": "Die Staubmäuse verschwinden in einer Rauch-, äh… Staubwolke. Als sich der Staub legt, siehst du dich um. Du hast vergessen, wie hübsch es hier doch aussieht, wenn es sauber ist. Du erkennst einen kleinen Haufen Gold, wo der Staub vorher war. Huch, du hattest dich schon gefragt, wo er abgeblieben war!",
438+
"value": 1,
439+
"category": "unlockable",
440+
"boss": {
441+
"name": "Ungezähmte Staubmäuse",
442+
"hp": 100,
443+
"str": 0.5,
444+
"def": 1
445+
},
446+
"drop": {
447+
"gp": 8,
448+
"exp": 42
449+
},
450+
"key": "dustbunnies"
451+
},
452+
"basilist": {
453+
"text": "Der Basi-List",
454+
"notes": "Da ist ein Aufruhr auf dem Marktplatz – es sieht ganz so aus, als ob man lieber in die andere Richtung rennen sollte. Da Du aber ein mutiger Abenteurer bist, rennst Du stattdessen darauf zu und entdeckst einen Basi-List, der sich aus einem Haufen unerledigter Aufgaben geformt hat! Alle umstehenden Habiticaner sind aus Angst vor der Länge des Basi-Lists gelähmt und können nicht anfangen zu arbeiten. Von irgendwo in der Nähe hörst Du @Arcosine schreien: \"Schnell! Erledige Deine To-Dos und Tagesaufgaben, um dem Monster die Zähne zu entfernen, bevor sich jemand am Papier schneidet!\" Greife schnell an, Abenteurer, und hake etwas ab - aber Vorsicht! Wenn Du irgendwelche Tagesaufgaben nicht erledigst, wird der Basi-List Dich und Deine Party angreifen!",
455+
"group": "questGroupEarnable",
456+
"completion": "Der Basi-List ist in Papierschnitzel zerfallen, die sanft in Regenbogenfarben schimmern. \"Puh!\" sagt @Arcosine. \"Gut, dass ihr gerade hier wart!\" Du fühlst Dich erfahrener als vorher und sammelst ein paar verstreute Goldstücke zwischen den Papierstücken auf.",
457+
"goldValue": 100,
458+
"category": "unlockable",
459+
"unlockCondition": {
460+
"condition": "party invite",
461+
"text": "Lade Freunde ein"
462+
},
463+
"boss": {
464+
"name": "Der Basi-List",
465+
"hp": 100,
466+
"str": 0.5,
467+
"def": 1
468+
},
469+
"drop": {
470+
"gp": 8,
471+
"exp": 42
472+
},
473+
"key": "basilist"
474+
}
475+
},
374476
"questsByLevel": {},
375477
"userCanOwnQuestCategories": [],
376478
"itemList": {
@@ -450,11 +552,61 @@
450552
"special": {},
451553
"dropEggs": {},
452554
"questEggs": {},
453-
"eggs": {},
555+
"eggs": {
556+
"Wolf": {
557+
"text": "Wolfsjunges",
558+
"mountText": "Wolfs-Reittier",
559+
"adjective": "ein treues",
560+
"value": 3,
561+
"key": "Wolf",
562+
"notes": "Finde ein Schlüpfelixier, das Du über dieses Ei gießen kannst, damit ein ein treues Wolfsjunges schlüpfen kann."
563+
},
564+
"TigerCub": {
565+
"text": "Tigerjunges",
566+
"mountText": "Tiger-Reittier",
567+
"adjective": "ein wildes",
568+
"value": 3,
569+
"key": "TigerCub",
570+
"notes": "Finde ein Schlüpfelixier, das Du über dieses Ei gießen kannst, damit ein ein wildes Tigerjunges schlüpfen kann."
571+
},
572+
"PandaCub": {
573+
"text": "Pandajunges",
574+
"mountText": "Panda-Reittier",
575+
"adjective": "ein sanftes",
576+
"value": 3,
577+
"key": "PandaCub",
578+
"notes": "Finde ein Schlüpfelixier, das Du über dieses Ei gießen kannst, damit ein ein sanftes Pandajunges schlüpfen kann."
579+
}
580+
},
454581
"dropHatchingPotions": {},
455582
"premiumHatchingPotions": {},
456583
"wackyHatchingPotions": {},
457-
"hatchingPotions": {},
584+
"hatchingPotions": {
585+
"Base": {
586+
"value": 2,
587+
"key": "Base",
588+
"text": "Normales",
589+
"notes": "Gieße dies über ein Ei und es wird ein Normales Haustier daraus schlüpfen.",
590+
"premium": false,
591+
"limited": false
592+
},
593+
"White": {
594+
"value": 2,
595+
"key": "White",
596+
"text": "Weißes",
597+
"notes": "Gieße dies über ein Ei und es wird ein Weißes Haustier daraus schlüpfen.",
598+
"premium": false,
599+
"limited": false
600+
},
601+
"Desert": {
602+
"value": 2,
603+
"key": "Desert",
604+
"text": "Wüstenfarbenes",
605+
"notes": "Gieße dies über ein Ei und es wird ein Wüstenfarbenes Haustier daraus schlüpfen.",
606+
"premium": false,
607+
"limited": false
608+
}
609+
},
458610
"pets": {},
459611
"premiumPets": {},
460612
"questPets": {},
@@ -466,7 +618,46 @@
466618
"questMounts": {},
467619
"specialMounts": {},
468620
"mountInfo": {},
469-
"food": {}
621+
"food": {
622+
"Meat": {
623+
"text": "Fleisch",
624+
"textA": "Fleisch",
625+
"textThe": "das Fleisch",
626+
"target": "Base",
627+
"value": 1,
628+
"key": "Meat",
629+
"notes": "Verfüttere dies an ein Haustier und es wächst bald zu einem kräftigen Reittier heran.",
630+
"canDrop": true
631+
},
632+
"Milk": {
633+
"text": "Milch",
634+
"textA": "Milch",
635+
"textThe": "die Milch",
636+
"target": "White",
637+
"value": 1,
638+
"key": "Milk",
639+
"notes": "Verfüttere dies an ein Haustier und es wächst bald zu einem kräftigen Reittier heran.",
640+
"canDrop": true
641+
},
642+
"Potatoe": {
643+
"text": "Kartoffel",
644+
"textA": "eine Kartoffel",
645+
"textThe": "die Kartoffel",
646+
"target": "Desert",
647+
"value": 1,
648+
"key": "Potatoe",
649+
"notes": "Verfüttere dies an ein Haustier und es wächst bald zu einem kräftigen Reittier heran.",
650+
"canDrop": true
651+
},
652+
"Saddle": {
653+
"sellWarningNote": "Hey! Das ist ein sehr nützlicher Gegenstand! Weißt Du, wie Du den Sattel mit Deinen Haustieren nutzt?",
654+
"text": "Magischer Sattel",
655+
"value": 5,
656+
"notes": "Lässt eines Deiner Haustiere augenblicklich zum Reittier heranwachsen.",
657+
"canDrop": false,
658+
"key": "Saddle"
659+
}
660+
}
470661
},
471662
"appVersion": "5.29.2"
472663
}

tests/components/habitica/fixtures/user.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,28 @@
112112
"eyewear": "eyewear_armoire_plagueDoctorMask",
113113
"body": "body_special_aetherAmulet"
114114
}
115+
},
116+
"quests": {
117+
"atom1": 1,
118+
"goldenknight1": 0,
119+
"dustbunnies": 1,
120+
"basilist": 0
121+
},
122+
"food": {
123+
"Saddle": 2,
124+
"Meat": 0,
125+
"Milk": 1,
126+
"Potatoe": 2
127+
},
128+
"hatchingPotions": {
129+
"Base": 2,
130+
"White": 0,
131+
"Desert": 1
132+
},
133+
"eggs": {
134+
"Wolf": 1,
135+
"TigerCub": 0,
136+
"PandaCub": 2
115137
}
116138
},
117139
"balance": 10,

0 commit comments

Comments
 (0)