Skip to content

Commit 9587c97

Browse files
committed
refactor: simplify sensors — remove budget aggregates, options flow, and streamline categories
- Remove 8 budget aggregate sensors: BudgetSummary, TotalBudgeted, TotalSpent, BudgetRemaining, BudgetHealth, CategoriesOverBudgetCount, CategoriesBudgeted, CategoriesUnbudgeted - Remove options flow (period/interval settings) and _fetch_budget_summary from coordinator — no longer needed - Strip const.py to just DOMAIN - Update CategoriesSensor attributes to include budgeted_categories and unbudgeted_categories lists - Simplify category sensor names to just the category title - Clean up dead code: remove _attr_device_info from binary sensor __init__ methods, remove unused imports (calendar, non_transfer_budget_packages from sensor.py, options constants) Budget data per category remains available via individual category sensor attributes (budgeted, actual, remaining, over_by, over_budget, percentage_used) for users to build custom templates and automations.
1 parent 972b84c commit 9587c97

File tree

7 files changed

+12
-667
lines changed

7 files changed

+12
-667
lines changed

custom_components/ha_pocketsmith/binary_sensor.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ def __init__(self, coordinator: PocketSmithCoordinator) -> None:
3838
"""Initialise the sensor."""
3939
super().__init__(coordinator)
4040
self._user_id = coordinator.data["user_id"]
41-
self._attr_device_info = _make_device_info(coordinator)
4241
self._attr_device_class = BinarySensorDeviceClass.PROBLEM
4342

4443
@property
@@ -104,7 +103,6 @@ def __init__(self, coordinator: PocketSmithCoordinator) -> None:
104103
"""Initialise the sensor."""
105104
super().__init__(coordinator)
106105
self._user_id = coordinator.data["user_id"]
107-
self._attr_device_info = _make_device_info(coordinator)
108106

109107
@property
110108
def device_info(self):
@@ -161,7 +159,6 @@ def __init__(self, coordinator: PocketSmithCoordinator) -> None:
161159
"""Initialise the sensor."""
162160
super().__init__(coordinator)
163161
self._user_id = coordinator.data["user_id"]
164-
self._attr_device_info = _make_device_info(coordinator)
165162
self._attr_device_class = BinarySensorDeviceClass.PROBLEM
166163

167164
@property

custom_components/ha_pocketsmith/config_flow.py

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,9 @@
55
import aiohttp
66
import voluptuous as vol
77
from homeassistant import config_entries
8-
from homeassistant.core import callback
98
from homeassistant.helpers.aiohttp_client import async_get_clientsession
109

11-
from .const import (
12-
DOMAIN,
13-
CONF_PERIOD,
14-
CONF_INTERVAL,
15-
PERIOD_OPTIONS,
16-
INTERVAL_OPTIONS,
17-
)
10+
from .const import DOMAIN
1811

1912
_LOGGER = logging.getLogger(__name__)
2013
_API_ME = "https://api.pocketsmith.com/v2/me"
@@ -42,12 +35,6 @@ class PocketSmithConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
4235

4336
VERSION = 1
4437

45-
@staticmethod
46-
@callback
47-
def async_get_options_flow(config_entry):
48-
"""Create the options flow."""
49-
return PocketSmithOptionsFlow()
50-
5138
async def async_step_user(self, user_input=None):
5239
"""Handle the initial setup step."""
5340
await self.async_set_unique_id(DOMAIN)
@@ -77,27 +64,3 @@ async def async_step_user(self, user_input=None):
7764
data_schema=vol.Schema({vol.Required("developer_key"): str}),
7865
errors=errors,
7966
)
80-
81-
82-
OPTIONS_SCHEMA = vol.Schema(
83-
{
84-
vol.Required(CONF_PERIOD): vol.In(PERIOD_OPTIONS),
85-
vol.Required(CONF_INTERVAL): vol.In(INTERVAL_OPTIONS),
86-
}
87-
)
88-
89-
90-
class PocketSmithOptionsFlow(config_entries.OptionsFlowWithReload):
91-
"""Handle PocketSmith options (period and interval)."""
92-
93-
async def async_step_init(self, user_input=None):
94-
"""Show the options form."""
95-
if user_input is not None:
96-
return self.async_create_entry(title="", data=user_input)
97-
98-
return self.async_show_form(
99-
step_id="init",
100-
data_schema=self.add_suggested_values_to_schema(
101-
OPTIONS_SCHEMA, self.config_entry.options
102-
),
103-
)
Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,2 @@
11
"""Constants for the PocketSmith integration."""
22
DOMAIN = "ha_pocketsmith"
3-
4-
DEFAULT_PERIOD = "months"
5-
DEFAULT_INTERVAL = 1
6-
DEFAULT_LOOKBACK_MONTHS = 12
7-
8-
CONF_PERIOD = "period"
9-
CONF_INTERVAL = "interval"
10-
11-
PERIOD_OPTIONS = ["weeks", "months", "years"]
12-
INTERVAL_OPTIONS = [1, 2, 3, 4]

custom_components/ha_pocketsmith/coordinator.py

Lines changed: 1 addition & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""DataUpdateCoordinator for PocketSmith."""
22
import asyncio
33
import logging
4-
import calendar
54
from datetime import date, datetime, timedelta, timezone
65

76
import aiohttp
@@ -10,7 +9,7 @@
109
from homeassistant.helpers.aiohttp_client import async_get_clientsession
1110
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
1211

13-
from .const import DOMAIN, CONF_PERIOD, CONF_INTERVAL, DEFAULT_PERIOD, DEFAULT_INTERVAL
12+
from .const import DOMAIN
1413

1514
_LOGGER = logging.getLogger(__name__)
1615

@@ -58,7 +57,6 @@ async def _async_update_data(self) -> dict:
5857
uncategorised_count = await self._fetch_uncategorised_count(session, user_id)
5958
categories = await self._fetch_categories(session, user_id)
6059
budget = await self._fetch_budget(session, user_id)
61-
budget_summary = await self._fetch_budget_summary(session, user_id)
6260
except aiohttp.ClientError as err:
6361
raise UpdateFailed(
6462
"Unable to reach the PocketSmith API. Check your network connection."
@@ -77,7 +75,6 @@ async def _async_update_data(self) -> dict:
7775
"uncategorised_count": uncategorised_count,
7876
"categories": categories,
7977
"budget": budget,
80-
"budget_summary": budget_summary,
8178
"enriched_categories": enriched_categories,
8279
"forecast_last_updated": datetime.now(timezone.utc),
8380
}
@@ -369,65 +366,6 @@ async def _fetch_budget(self, session: aiohttp.ClientSession, user_id: int) -> l
369366
_LOGGER.debug("Fetched budget for user %s", user_id)
370367
return budget
371368

372-
async def _fetch_budget_summary(self, session: aiohttp.ClientSession, user_id: int) -> list:
373-
"""Return budget summary for the given user for the current calendar month."""
374-
today = date.today()
375-
start_date = today.replace(day=1)
376-
end_date = today.replace(day=calendar.monthrange(today.year, today.month)[1])
377-
period = self._entry.options.get(CONF_PERIOD, DEFAULT_PERIOD)
378-
interval = self._entry.options.get(CONF_INTERVAL, DEFAULT_INTERVAL)
379-
url = (
380-
"%s/users/%s/budget_summary?period=%s&interval=%s&start_date=%s&end_date=%s&per_page=1000"
381-
% (_API_BASE, user_id, period, interval, start_date.isoformat(), end_date.isoformat())
382-
)
383-
384-
async with asyncio.timeout(_REQUEST_TIMEOUT):
385-
async with session.get(url, headers=self._headers) as response:
386-
if response.status == 400:
387-
try:
388-
error_body = (await response.json()).get("error", "unknown error")
389-
except Exception:
390-
error_body = "unknown error"
391-
raise UpdateFailed(
392-
"PocketSmith returned a bad request error: %s. This may indicate a bug in the integration." % error_body
393-
)
394-
if response.status == 401:
395-
raise UpdateFailed(
396-
"PocketSmith authentication failed — your developer key is invalid or has been revoked. "
397-
"Reconfigure the integration to fix this."
398-
)
399-
if response.status == 403:
400-
raise UpdateFailed(
401-
"PocketSmith access denied — your developer key lacks the required permissions "
402-
"to read your budget summary."
403-
)
404-
if response.status == 404:
405-
raise UpdateFailed(
406-
"PocketSmith could not find your budget summary data. This may be a temporary API issue."
407-
)
408-
if response.status == 405:
409-
raise UpdateFailed(
410-
"PocketSmith returned Method Not Allowed (HTTP 405). This is likely a bug in the integration — please report it."
411-
)
412-
if response.status == 429:
413-
raise UpdateFailed(
414-
"PocketSmith API rate limit exceeded. The integration will retry on the next update."
415-
)
416-
if response.status == 503:
417-
raise UpdateFailed(
418-
"PocketSmith is temporarily unavailable for maintenance (HTTP 503). The integration will retry on the next update."
419-
)
420-
if response.status >= 500:
421-
raise UpdateFailed(
422-
"PocketSmith is experiencing server issues (HTTP %s). "
423-
"Data will refresh when the service recovers." % response.status
424-
)
425-
response.raise_for_status()
426-
budget_summary = await response.json()
427-
428-
_LOGGER.debug("Fetched budget summary for user %s", user_id)
429-
return budget_summary
430-
431369
def _build_enriched_categories(self, categories: list, budget: list) -> list:
432370
"""Return a flat enriched list of all categories with budget data."""
433371

0 commit comments

Comments
 (0)