mirror of
https://github.com/home-assistant/core.git
synced 2026-04-17 23:53:49 +01:00
Fix Firefly iii sensors not updating (#165450)
Co-authored-by: Joostlek <joostlek@outlook.com>
This commit is contained in:
@@ -36,10 +36,10 @@ DEFAULT_SCAN_INTERVAL = timedelta(minutes=5)
|
||||
class FireflyCoordinatorData:
|
||||
"""Data structure for Firefly III coordinator data."""
|
||||
|
||||
accounts: list[Account]
|
||||
accounts: dict[str, Account]
|
||||
categories: list[Category]
|
||||
category_details: list[Category]
|
||||
budgets: list[Budget]
|
||||
category_details: dict[str, Category]
|
||||
budgets: dict[str, Budget]
|
||||
bills: list[Bill]
|
||||
primary_currency: Currency
|
||||
|
||||
@@ -142,10 +142,10 @@ class FireflyDataUpdateCoordinator(DataUpdateCoordinator[FireflyCoordinatorData]
|
||||
) from err
|
||||
|
||||
return FireflyCoordinatorData(
|
||||
accounts=accounts,
|
||||
accounts={account.id: account for account in accounts},
|
||||
categories=categories,
|
||||
category_details=category_details,
|
||||
budgets=budgets,
|
||||
category_details={category.id: category for category in category_details},
|
||||
budgets={budget.id: budget for budget in budgets},
|
||||
bills=bills,
|
||||
primary_currency=primary_currency,
|
||||
)
|
||||
|
||||
@@ -44,7 +44,7 @@ class FireflyAccountBaseEntity(FireflyBaseEntity):
|
||||
) -> None:
|
||||
"""Initialize a Firefly account entity."""
|
||||
super().__init__(coordinator)
|
||||
self._account = account
|
||||
self._account_id = account.id
|
||||
self._attr_device_info = DeviceInfo(
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
manufacturer=MANUFACTURER,
|
||||
@@ -58,6 +58,10 @@ class FireflyAccountBaseEntity(FireflyBaseEntity):
|
||||
f"{coordinator.config_entry.unique_id}_account_{account.id}_{key}"
|
||||
)
|
||||
|
||||
@property
|
||||
def _account(self) -> Account:
|
||||
return self.coordinator.data.accounts[self._account_id]
|
||||
|
||||
|
||||
class FireflyCategoryBaseEntity(FireflyBaseEntity):
|
||||
"""Base class for Firefly III category entity."""
|
||||
@@ -70,7 +74,7 @@ class FireflyCategoryBaseEntity(FireflyBaseEntity):
|
||||
) -> None:
|
||||
"""Initialize a Firefly category entity."""
|
||||
super().__init__(coordinator)
|
||||
self._category = category
|
||||
self._category_id = category.id
|
||||
self._attr_device_info = DeviceInfo(
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
manufacturer=MANUFACTURER,
|
||||
@@ -84,6 +88,10 @@ class FireflyCategoryBaseEntity(FireflyBaseEntity):
|
||||
f"{coordinator.config_entry.unique_id}_category_{category.id}_{key}"
|
||||
)
|
||||
|
||||
@property
|
||||
def _category(self) -> Category:
|
||||
return self.coordinator.data.category_details[self._category_id]
|
||||
|
||||
|
||||
class FireflyBudgetBaseEntity(FireflyBaseEntity):
|
||||
"""Base class for Firefly III budget entity."""
|
||||
@@ -96,7 +104,7 @@ class FireflyBudgetBaseEntity(FireflyBaseEntity):
|
||||
) -> None:
|
||||
"""Initialize a Firefly budget entity."""
|
||||
super().__init__(coordinator)
|
||||
self._budget = budget
|
||||
self._budget_id = budget.id
|
||||
self._attr_device_info = DeviceInfo(
|
||||
entry_type=DeviceEntryType.SERVICE,
|
||||
manufacturer=MANUFACTURER,
|
||||
@@ -109,3 +117,7 @@ class FireflyBudgetBaseEntity(FireflyBaseEntity):
|
||||
self._attr_unique_id = (
|
||||
f"{coordinator.config_entry.unique_id}_budget_{budget.id}_{key}"
|
||||
)
|
||||
|
||||
@property
|
||||
def _budget(self) -> Budget:
|
||||
return self.coordinator.data.budgets[self._budget_id]
|
||||
|
||||
@@ -51,7 +51,7 @@ async def async_setup_entry(
|
||||
coordinator = entry.runtime_data
|
||||
entities: list[SensorEntity] = []
|
||||
|
||||
for account in coordinator.data.accounts:
|
||||
for account in coordinator.data.accounts.values():
|
||||
entities.append(
|
||||
FireflyAccountBalanceSensor(coordinator, account, ACCOUNT_BALANCE)
|
||||
)
|
||||
@@ -61,14 +61,14 @@ async def async_setup_entry(
|
||||
entities.extend(
|
||||
[
|
||||
FireflyCategorySensor(coordinator, category, CATEGORY)
|
||||
for category in coordinator.data.category_details
|
||||
for category in coordinator.data.category_details.values()
|
||||
]
|
||||
)
|
||||
|
||||
entities.extend(
|
||||
[
|
||||
FireflyBudgetSensor(coordinator, budget, BUDGET)
|
||||
for budget in coordinator.data.budgets
|
||||
for budget in coordinator.data.budgets.values()
|
||||
]
|
||||
)
|
||||
|
||||
@@ -90,7 +90,6 @@ class FireflyAccountBalanceSensor(FireflyAccountBaseEntity, SensorEntity):
|
||||
) -> None:
|
||||
"""Initialize the account balance sensor."""
|
||||
super().__init__(coordinator, account, key)
|
||||
self._account = account
|
||||
self._attr_native_unit_of_measurement = (
|
||||
coordinator.data.primary_currency.attributes.code
|
||||
)
|
||||
@@ -108,16 +107,6 @@ class FireflyAccountRoleSensor(FireflyAccountBaseEntity, SensorEntity):
|
||||
_attr_entity_category = EntityCategory.DIAGNOSTIC
|
||||
_attr_entity_registry_enabled_default = True
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: FireflyDataUpdateCoordinator,
|
||||
account: Account,
|
||||
key: str,
|
||||
) -> None:
|
||||
"""Initialize the account role sensor."""
|
||||
super().__init__(coordinator, account, key)
|
||||
self._account = account
|
||||
|
||||
@property
|
||||
def native_value(self) -> StateType:
|
||||
"""Return account role."""
|
||||
@@ -173,7 +162,6 @@ class FireflyCategorySensor(FireflyCategoryBaseEntity, SensorEntity):
|
||||
) -> None:
|
||||
"""Initialize the category sensor."""
|
||||
super().__init__(coordinator, category, key)
|
||||
self._category = category
|
||||
self._attr_native_unit_of_measurement = (
|
||||
coordinator.data.primary_currency.attributes.code
|
||||
)
|
||||
@@ -205,7 +193,6 @@ class FireflyBudgetSensor(FireflyBudgetBaseEntity, SensorEntity):
|
||||
) -> None:
|
||||
"""Initialize the budget sensor."""
|
||||
super().__init__(coordinator, budget, key)
|
||||
self._budget = budget
|
||||
self._attr_native_unit_of_measurement = (
|
||||
coordinator.data.primary_currency.attributes.code
|
||||
)
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': 'mdi:hand-coin',
|
||||
'original_icon': 'mdi:cash-plus',
|
||||
'original_name': 'Account Type',
|
||||
'platform': 'firefly_iii',
|
||||
'previous_unique_id': None,
|
||||
@@ -200,14 +200,14 @@
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Credit Card Account Type',
|
||||
'icon': 'mdi:hand-coin',
|
||||
'icon': 'mdi:cash-plus',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.credit_card_account_type',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'liability',
|
||||
'state': 'revenue',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[sensor.lunch_earned_spent-entry]
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""Tests for the Firefly III sensor platform."""
|
||||
|
||||
from copy import deepcopy
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
@@ -8,9 +9,11 @@ from pyfirefly.exceptions import (
|
||||
FireflyConnectionError,
|
||||
FireflyTimeoutError,
|
||||
)
|
||||
from pyfirefly.models import Budget
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.firefly_iii.const import DOMAIN
|
||||
from homeassistant.components.firefly_iii.coordinator import DEFAULT_SCAN_INTERVAL
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import STATE_UNAVAILABLE, Platform
|
||||
@@ -20,7 +23,12 @@ from homeassistant.util import dt as dt_util
|
||||
|
||||
from . import setup_integration
|
||||
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
|
||||
from tests.common import (
|
||||
MockConfigEntry,
|
||||
async_fire_time_changed,
|
||||
async_load_json_array_fixture,
|
||||
snapshot_platform,
|
||||
)
|
||||
|
||||
|
||||
async def test_all_entities(
|
||||
@@ -69,3 +77,32 @@ async def test_refresh_exceptions(
|
||||
state = hass.states.get("sensor.credit_card_account_balance")
|
||||
assert state is not None
|
||||
assert state.state == STATE_UNAVAILABLE
|
||||
|
||||
|
||||
async def test_budget_sensor_updates_after_refresh(
|
||||
hass: HomeAssistant,
|
||||
mock_firefly_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
) -> None:
|
||||
"""Test budget sensor tracks refreshed coordinator budget objects."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
state = hass.states.get("sensor.bills_budget")
|
||||
assert state is not None
|
||||
assert state.state == "123.45"
|
||||
|
||||
updated_budget_data = await async_load_json_array_fixture(
|
||||
hass, "budgets.json", DOMAIN
|
||||
)
|
||||
updated_budget = deepcopy(updated_budget_data[0])
|
||||
updated_budget["attributes"]["spent"][0]["sum"] = "999.99"
|
||||
mock_firefly_client.get_budgets.return_value = [Budget.from_dict(updated_budget)]
|
||||
|
||||
freezer.tick(DEFAULT_SCAN_INTERVAL)
|
||||
async_fire_time_changed(hass, dt_util.utcnow())
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
|
||||
updated_state = hass.states.get("sensor.bills_budget")
|
||||
assert updated_state is not None
|
||||
assert updated_state.state == "999.99"
|
||||
|
||||
Reference in New Issue
Block a user