From 4dcf2f04c54379432c558fda70379b0673fb68bc Mon Sep 17 00:00:00 2001 From: Kaden Napper Date: Sun, 27 Sep 2026 17:53:51 +1000 Subject: [PATCH] Fix currency presentation and update resilience --- README.md | 4 ++-- custom_components/up_banking/api.py | 4 ++-- custom_components/up_banking/coordinator.py | 5 ++++- custom_components/up_banking/models.py | 2 +- tests/test_models.py | 14 ++++++++++++-- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 35b77e6..bce4f75 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## What it provides -- One AUD balance sensor for each account selected during setup, including Savers and 2Up (joint) accounts. +- One $ balance sensor for each account selected during setup, including Savers and 2Up (joint) accounts. - Stable entity identity based on Up's account ID, so changing an account name does not create a new entity. - The `up_banking_transaction` Home Assistant event for new activity. Its compact data includes `transaction_id`, `event_type` (`created`, `settled`, or `deleted`), `status` (`held`, `settled`, or `deleted`), `account_id`, `amount`, `currency`, `description`, and `created_at`. - A five-minute coordinated poll. It reads changed activity since the last successful poll, so a Home Assistant restart or brief outage catches up. It retains at most 500 small de-duplication records in HA storage and does **not** put transaction history on entities or into Recorder attributes. @@ -36,7 +36,7 @@ automation: data: message: >- {{ trigger.event.data.description }}: - {{ trigger.event.data.amount }} {{ trigger.event.data.currency }} + {{ trigger.event.data.currency }}{{ trigger.event.data.amount }} ``` Amounts use Up's signed decimal representation: an outgoing purchase is normally negative. diff --git a/custom_components/up_banking/api.py b/custom_components/up_banking/api.py index 9283a80..85a0c29 100644 --- a/custom_components/up_banking/api.py +++ b/custom_components/up_banking/api.py @@ -44,7 +44,7 @@ class UpApi: if response.status >= 400: raise UpApiError(f"Up API request failed ({response.status})") return (await response.json())["data"] - except aiohttp.ClientError as err: + except (aiohttp.ClientError, TimeoutError) as err: raise UpApiError("Unable to reach the Up API") from err async def _list( @@ -70,5 +70,5 @@ class UpApi: if response.status >= 400: raise UpApiError(f"Up API request failed ({response.status})") return await response.json() - except aiohttp.ClientError as err: + except (aiohttp.ClientError, TimeoutError) as err: raise UpApiError("Unable to reach the Up API") from err diff --git a/custom_components/up_banking/coordinator.py b/custom_components/up_banking/coordinator.py index af1446a..bf8817e 100644 --- a/custom_components/up_banking/coordinator.py +++ b/custom_components/up_banking/coordinator.py @@ -59,7 +59,10 @@ class UpCoordinator(DataUpdateCoordinator[dict[str, dict[str, Any]]]): for tx_id, saved in list(self._seen.items()): if saved["status"] != "HELD": continue - current = await self.api.transaction(tx_id) + try: + current = await self.api.transaction(tx_id) + except UpApiError as err: + raise UpdateFailed(str(err)) from err if current is None: # A held item that no longer exists was deleted by Up. payload = dict(saved["event"]) diff --git a/custom_components/up_banking/models.py b/custom_components/up_banking/models.py index 30f29a2..67fac93 100644 --- a/custom_components/up_banking/models.py +++ b/custom_components/up_banking/models.py @@ -21,7 +21,7 @@ def transaction_event(transaction: dict[str, Any], event_type: str) -> dict[str, "status": attrs["status"].lower(), "account_id": account.get("id"), "amount": money["value"], - "currency": money["currencyCode"], + "currency": "$", "description": attrs.get("description", ""), "created_at": attrs.get("createdAt"), "raw_text": attrs.get("rawText"), diff --git a/tests/test_models.py b/tests/test_models.py index 779a2ec..7b02914 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,5 +1,15 @@ """Tests for event payloads: no Home Assistant runtime is required.""" -from custom_components.up_banking.models import account_label, transaction_event +from importlib.util import module_from_spec, spec_from_file_location +from pathlib import Path + + +_MODELS_PATH = Path(__file__).parents[1] / "custom_components" / "up_banking" / "models.py" +_spec = spec_from_file_location("up_banking_models", _MODELS_PATH) +assert _spec and _spec.loader +_models = module_from_spec(_spec) +_spec.loader.exec_module(_models) +account_label = _models.account_label +transaction_event = _models.transaction_event def test_account_label_includes_saver_and_ownership(): @@ -13,4 +23,4 @@ def test_transaction_event_is_small_and_automation_ready(): "attributes": {"status": "HELD", "amount": {"value": "-12.34", "currencyCode": "AUD"}, "description": "Coffee", "createdAt": "2026-01-01T00:00:00Z", "rawText": "Cafe"}, "relationships": {"account": {"data": {"id": "account-1"}}}, } - assert transaction_event(transaction, "created") == {"transaction_id": "tx-1", "event_type": "created", "status": "held", "account_id": "account-1", "amount": "-12.34", "currency": "AUD", "description": "Coffee", "created_at": "2026-01-01T00:00:00Z", "raw_text": "Cafe"} + assert transaction_event(transaction, "created") == {"transaction_id": "tx-1", "event_type": "created", "status": "held", "account_id": "account-1", "amount": "-12.34", "currency": "$", "description": "Coffee", "created_at": "2026-01-01T00:00:00Z", "raw_text": "Cafe"}