Skip to content

Commit

Permalink
Add budgets sensors
Browse files Browse the repository at this point in the history
  • Loading branch information
soloam committed May 1, 2024
1 parent f61e323 commit cd166e7
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 13 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
- [x] Accounts
- [x] Bills in calendar
- [x] Import Piggy Banks
- [ ] Import Budgets
- [x] Import Budgets
- [ ] Services
- [ ] Add to HACS

Expand Down
2 changes: 1 addition & 1 deletion custom_components/fireflyiii_integration/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
),
FireflyiiiObjectType.BUDGETS: SensorEntityDescription(
key=FireflyiiiObjectType.BUDGETS,
name="Budget",
translation_key=FireflyiiiObjectType.BUDGETS,
icon="mdi:calculator",
device_class=SensorDeviceClass.MONETARY,
state_class=SensorStateClass.TOTAL,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
FireflyiiiAccount,
FireflyiiiBill,
FireflyiiiBillPayment,
FireflyiiiBudget,
FireflyiiiCategory,
FireflyiiiCurrency,
FireflyiiiObjectBaseList,
Expand Down Expand Up @@ -336,7 +337,7 @@ async def categories(self, ids=None, currency=None) -> FireflyiiiObjectBaseList:
spent_currency = sum(
float(s.get("sum", 0))
for s in spent_get
if s.get("currency_code", "") == get_currency
if s.get("currency_code", "") == str(get_currency)
)
except ValueError:
spent_currency = 0
Expand All @@ -345,7 +346,7 @@ async def categories(self, ids=None, currency=None) -> FireflyiiiObjectBaseList:
earned_currency = sum(
float(s.get("sum", 0))
for s in earned_get
if s.get("currency_code", "") == get_currency
if s.get("currency_code", "") == str(get_currency)
)
except ValueError:
earned_currency = 0
Expand Down Expand Up @@ -411,7 +412,7 @@ async def currencies(self, ids=None, enabled=None) -> FireflyiiiObjectBaseList:
return currency_list

async def piggy_banks(self, ids=None) -> FireflyiiiObjectBaseList:
"""Get FireflyIII currencies"""
"""Get FireflyIII Piggy Banks"""

piggy_bank_list = FireflyiiiObjectBaseList(
type=FireflyiiiObjectType.PIGGY_BANKS
Expand Down Expand Up @@ -462,6 +463,83 @@ async def piggy_banks(self, ids=None) -> FireflyiiiObjectBaseList:

return piggy_bank_list

async def budgets(self, ids=None, currency=None) -> FireflyiiiObjectBaseList:
"""Get FireflyIII Budgets"""

budgets_list = FireflyiiiObjectBaseList(type=FireflyiiiObjectType.BUDGETS)

date_range = {}
if (
self._timerange
and self._timerange.start_datetime
and self._timerange.end_datetime
):
date_range = {
"start": self._timerange.start_datetime.strftime("%Y-%m-%d"),
"end": self._timerange.end_datetime.strftime("%Y-%m-%d"),
}

budgets = await self._request_api("GET", "/budgets", date_range)
if not "data" in budgets:
return budgets_list

for budget in budgets["data"]:
budget_id = budget.get("id", 0)
if budget_id == 0:
continue

if ids and budget_id not in ids:
continue

attributes = budget.get("attributes")
if not attributes:
continue

budget_limits = await self._request_api(
"GET", f"/budgets/{budget_id}/limits", date_range
)
if not "data" in budget_limits or len(budget_limits["data"]) < 1:
budget_limits = None
else:
budget_limit = budget_limits["data"][0]

limit_attributes = budget_limit.get("attributes", {})

try:
start_limit = datetime.fromisoformat(limit_attributes.get("start"))
end_limit = datetime.fromisoformat(limit_attributes.get("end"))
except ValueError:
start_limit = None
end_limit = None

if currency:
get_currency = currency
else:
get_currency = await self.default_currency

try:
spent_currency = sum(
float(s.get("sum", 0))
for s in attributes["spent"]
if s.get("currency_code", "") == str(get_currency)
)
except ValueError:
spent_currency = 0

budget_obj = FireflyiiiBudget(
id=attributes.get("id", budget_id),
name=attributes.get("name", ""),
spent=spent_currency,
currency=get_currency,
limit=limit_attributes.get("amount", 0),
limit_start=start_limit,
limit_end=end_limit,
)

budgets_list.update(budget_obj)

return budgets_list

async def bills(
self, ids=None, timerange: Optional[DateTimeRange] = None
) -> FireflyiiiObjectBaseList:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,5 +223,8 @@ async def _async_update_data(self):
if self.user_data.get_piggy_banks:
data_list.update(self.api.piggy_banks())

if self.user_data.get_budgets:
data_list.update(self.api.budgets())

await data_list.gather()
return data_list
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ def currency(self) -> FireflyiiiCurrency:

@dataclass
class FireflyiiiPiggyBank(FireflyiiiObjectBaseId):
"""FireflyIII Preferences Data Agregation"""
"""FireflyIII Piggy Bank Data Agregation"""

_objtype: ClassVar[FireflyiiiObjectType] = FireflyiiiObjectType.PIGGY_BANKS

Expand All @@ -412,3 +412,17 @@ def __post_init__(self):
current_amount: float = 0
left_to_save: float = 0
currency: Optional[FireflyiiiCurrency] = None


@dataclass
class FireflyiiiBudget(FireflyiiiObjectBaseId):
"""FireflyIII Budget Data Agregation"""

_objtype: ClassVar[FireflyiiiObjectType] = FireflyiiiObjectType.BUDGETS

name: str
spent: float
currency: FireflyiiiCurrency
limit: float = 0
limit_start: Optional[datetime] = None
limit_end: Optional[datetime] = None
52 changes: 45 additions & 7 deletions custom_components/fireflyiii_integration/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

import logging
from datetime import timedelta
from datetime import datetime, timedelta
from typing import Optional, cast

from homeassistant import config_entries, core
Expand All @@ -20,6 +20,7 @@
)
from .integrations.fireflyiii_objects import (
FireflyiiiAccount,
FireflyiiiBudget,
FireflyiiiCategory,
FireflyiiiObjectType,
FireflyiiiPiggyBank,
Expand Down Expand Up @@ -74,9 +75,11 @@ async def async_setup_entry(
piggybank.append(obj)

budgets = []
if FireflyiiiObjectType.BUDGETS in coordinator.api_data:
for budget_id in coordinator.api_data.budgets:
obj = FireflyiiiBudgetSensorEntity(
coordinator, FIREFLYIII_SENSOR_DESCRIPTIONS[FireflyiiiObjectType.BUDGETS]
coordinator,
FIREFLYIII_SENSOR_DESCRIPTIONS[FireflyiiiObjectType.BUDGETS],
budget_id,
)

budgets.append(obj)
Expand Down Expand Up @@ -273,13 +276,48 @@ class FireflyiiiBudgetSensorEntity(FireflyiiiEntityBase, SensorEntity):

_type = FireflyiiiObjectType.BUDGETS

_attr_sources = ["limit", "limit_start", "limit_end"]

def __init__(
self,
coordinator,
entity_description: SensorEntityDescription = None,
data: Optional[dict] = None,
fireflyiii_id: Optional[int] = None,
):
self._data = data if data else {}
super().__init__(coordinator, entity_description, self._data.get("id", 0))
super().__init__(coordinator, entity_description, fireflyiii_id)

self._attr_translation_placeholders = {"budget_name": self.entity_data.name}

@property
def entity_data(self) -> FireflyiiiBudget:
"""Returns entity data - overide to Type Hints"""
return cast(FireflyiiiBudget, super().entity_data)

@property
def native_unit_of_measurement(self) -> str:
currency_code = self.entity_data.currency
return str(currency_code) if currency_code else ""

@property
def native_value(self) -> float:
"""Return the state of the sensor."""

return self.entity_data.spent

@property
def limit(self) -> float:
"""Return the budget limit"""

return self.entity_data.limit

@property
def limit_start(self) -> Optional[datetime]:
"""Return the budget limit start date"""

return self.entity_data.limit_start

@property
def limit_end(self) -> Optional[datetime]:
"""Return the budget limit end date"""

self._state = None
return self.entity_data.limit_end
23 changes: 23 additions & 0 deletions custom_components/fireflyiii_integration/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,29 @@
}
}
},
"budgets": {
"name": "{budget_name} Budget",
"state_attributes": {
"fireflyiii_id": {
"name": "FireflyIII id"
},
"fireflyiii_type": {
"name": "FireflyIII type",
"state": {
"budgets": "Budget"
}
},
"limit": {
"name": "Budget limit"
},
"limit_start": {
"name": "Budget limit start"
},
"limit_end": {
"name": "Budget limit end"
}
}
},
"piggy_banks": {
"name": "{piggy_bank_name} Piggy Bank",
"state_attributes": {
Expand Down

0 comments on commit cd166e7

Please sign in to comment.