Skip to content

Commit 61823dc

Browse files
Merge branch 'main' into annable/update-version
2 parents 0e23cf6 + e338fcd commit 61823dc

File tree

15 files changed

+502
-113
lines changed

15 files changed

+502
-113
lines changed

.cursor/commands/coverage.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../.github/prompts/coverage.prompt.md

.cursor/commands/lint.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../.github/prompts/lint.prompt.md

.cursor/commands/update-docs.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../.github/prompts/update-docs.prompt.md

.github/workflows/ci.yml

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ jobs:
3030
REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }}
3131
steps:
3232
- name: Checkout the repository
33-
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
33+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
3434

35-
- uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
35+
- uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
3636

3737
- name: Install python dependencies
3838
run: uv sync --locked --all-extras --dev
@@ -60,9 +60,9 @@ jobs:
6060
REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }}
6161
steps:
6262
- name: Checkout the repository
63-
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
63+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
6464

65-
- uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
65+
- uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
6666

6767
- name: Install python dependencies
6868
run: uv sync --locked --all-extras --dev
@@ -90,9 +90,9 @@ jobs:
9090
REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }}
9191
steps:
9292
- name: Checkout the repository
93-
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
93+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
9494

95-
- uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
95+
- uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
9696

9797
- name: Install python dependencies
9898
run: uv sync --locked --all-extras --dev
@@ -137,9 +137,9 @@ jobs:
137137
REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }}
138138
steps:
139139
- name: Checkout the repository
140-
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
140+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
141141

142-
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
142+
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
143143

144144
- name: Setup reviewdog
145145
if: github.event_name == 'pull_request'
@@ -168,9 +168,9 @@ jobs:
168168
REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }}
169169
steps:
170170
- name: Checkout the repository
171-
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
171+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
172172

173-
- uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
173+
- uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
174174

175175
- name: Install python dependencies
176176
run: uv sync --locked --all-extras --dev
@@ -203,12 +203,12 @@ jobs:
203203
runs-on: ubuntu-latest
204204
steps:
205205
- name: Checkout the repository
206-
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
206+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
207207
with:
208208
fetch-depth: 0
209209

210210
- name: Install uv
211-
uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
211+
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
212212

213213
- name: Install the project
214214
run: uv sync --locked --all-extras --dev
@@ -241,20 +241,20 @@ jobs:
241241
runs-on: ubuntu-latest
242242
steps:
243243
- name: Checkout the repository
244-
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
244+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
245245

246246
- name: Run hassfest validation
247-
uses: home-assistant/actions/hassfest@87c064c607f3c5cc673a24258d0c98d23033bfc3 # master
247+
uses: home-assistant/actions/hassfest@55b4a5d23e09d627c2773c2ef82afa98904d65b4 # master
248248

249249
version-check:
250250
name: Version consistency
251251
runs-on: ubuntu-latest
252252
steps:
253253
- name: Checkout the repository
254-
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
254+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
255255

256256
- name: Install uv
257-
uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
257+
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
258258

259259
- name: Check HAFO version consistency
260260
run: |
@@ -286,12 +286,12 @@ jobs:
286286
runs-on: ubuntu-latest
287287
steps:
288288
- name: Checkout repository
289-
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
289+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
290290
with:
291291
fetch-depth: 0
292292

293293
- name: Install uv
294-
uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
294+
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
295295

296296
- name: Install dependencies
297297
run: uv sync

.github/workflows/copilot-setup-steps.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ jobs:
2626
# If you do not check out your code, Copilot will do this for you.
2727
steps:
2828
- name: Checkout code
29-
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
29+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
3030

31-
- uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
32-
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
31+
- uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
32+
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
3333

3434
- name: Install python dependencies
3535
run: uv sync --locked --all-extras --dev

.github/workflows/docs.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,12 @@ jobs:
2626
runs-on: ubuntu-latest
2727
steps:
2828
- name: Checkout repository
29-
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
29+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
3030
with:
3131
fetch-depth: 0
3232

3333
- name: Install uv
34-
uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
34+
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
3535
with:
3636
version: "latest"
3737

.github/workflows/release.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ jobs:
1313
runs-on: ubuntu-latest
1414
steps:
1515
- name: Checkout the repository
16-
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
16+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
1717

1818
- name: Install uv
19-
uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6
19+
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
2020

2121
- name: Extract and validate version from release tag
2222
run: |
@@ -60,15 +60,15 @@ jobs:
6060
runs-on: ubuntu-latest
6161
steps:
6262
- name: Checkout the repository
63-
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
63+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
6464

6565
- name: Create release package
6666
run: |
6767
cd custom_components
6868
zip -r ../hafo.zip hafo
6969
7070
- name: Upload release assets
71-
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2
71+
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0
7272
with:
7373
files: |
7474
hafo.zip

.vscode/settings.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"[python]": {
3+
"editor.defaultFormatter": "charliermarsh.ruff"
4+
},
5+
"editor.detectIndentation": true,
6+
"editor.formatOnSave": true,
7+
"editor.insertSpaces": true,
8+
"files.associations": {
9+
"*.yaml": "home-assistant"
10+
},
11+
"files.eol": "\n",
12+
"files.insertFinalNewline": true,
13+
"files.trimFinalNewlines": true,
14+
"files.trimTrailingWhitespace": true,
15+
"python.testing.pytestArgs": ["tests"],
16+
"python.testing.pytestEnabled": true,
17+
"python.testing.unittestEnabled": false
18+
}

custom_components/hafo/forecasters/historical_shift.py

Lines changed: 25 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,17 @@
88
from dataclasses import dataclass
99
from datetime import datetime, timedelta
1010
import logging
11-
from typing import TYPE_CHECKING, Any
11+
from typing import Any
1212

13+
from homeassistant.components.recorder.statistics import StatisticsRow, statistics_during_period
1314
from homeassistant.config_entries import ConfigEntry
1415
from homeassistant.core import HomeAssistant
15-
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
16+
from homeassistant.helpers.recorder import get_instance
17+
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
1618
from homeassistant.util import dt as dt_util
1719

1820
from custom_components.hafo.const import CONF_HISTORY_DAYS, CONF_SOURCE_ENTITY, DEFAULT_HISTORY_DAYS, DOMAIN
1921

20-
if TYPE_CHECKING:
21-
from homeassistant.components.recorder.statistics import StatisticsRow
22-
2322
_LOGGER = logging.getLogger(__name__)
2423

2524

@@ -62,42 +61,19 @@ async def get_statistics_for_sensor(
6261
Returns:
6362
List of statistics rows with 'start' and 'mean' fields.
6463
65-
Raises:
66-
ValueError: If the recorder is not available or not set up.
67-
6864
"""
69-
if "recorder" not in hass.config.components:
70-
msg = "Recorder component not loaded"
71-
raise ValueError(msg)
72-
73-
try:
74-
# Recorder is an optional after_dependency, so we import inline after checking it's loaded
75-
from homeassistant.components.recorder.statistics import statistics_during_period # noqa: PLC0415
76-
from homeassistant.helpers.recorder import DATA_INSTANCE # noqa: PLC0415
77-
78-
if DATA_INSTANCE not in hass.data:
79-
msg = "Recorder not initialized"
80-
raise ValueError(msg)
81-
except ImportError:
82-
msg = "Recorder component not available"
83-
raise ValueError(msg) from None
84-
85-
try:
86-
statistics: dict[str, list[StatisticsRow]] = await hass.async_add_executor_job(
87-
lambda: statistics_during_period(
88-
hass,
89-
start_time,
90-
end_time,
91-
{entity_id},
92-
"hour",
93-
None,
94-
{"mean"},
95-
)
65+
recorder = get_instance(hass)
66+
statistics: dict[str, list[StatisticsRow]] = await recorder.async_add_executor_job(
67+
lambda: statistics_during_period(
68+
hass,
69+
start_time,
70+
end_time,
71+
{entity_id},
72+
"hour",
73+
None,
74+
{"mean"},
9675
)
97-
except Exception as e:
98-
msg = f"Failed to fetch statistics: {e}"
99-
raise ValueError(msg) from e
100-
76+
)
10177
return statistics.get(entity_id, [])
10278

10379

@@ -198,33 +174,22 @@ def entry(self) -> ConfigEntry:
198174
"""Return the config entry."""
199175
return self._entry
200176

201-
async def _async_update_data(self) -> ForecastResult | None:
177+
async def _async_update_data(self) -> ForecastResult:
202178
"""Fetch and update forecast data.
203179
204180
Returns:
205-
ForecastResult with the latest forecast, or None if unavailable.
206-
207-
Raises:
208-
UpdateFailed: If the forecast cannot be generated.
181+
ForecastResult with the latest forecast.
209182
210183
"""
211-
try:
212-
result = await self._generate_forecast()
184+
result = await self._generate_forecast()
213185

214-
_LOGGER.debug(
215-
"Generated forecast for %s with %d points",
216-
self._source_entity,
217-
len(result.forecast),
218-
)
219-
220-
return result
186+
_LOGGER.debug(
187+
"Generated forecast for %s with %d points",
188+
self._source_entity,
189+
len(result.forecast),
190+
)
221191

222-
except ValueError as err:
223-
_LOGGER.warning("Failed to generate forecast: %s", err)
224-
return None
225-
except Exception as err:
226-
msg = f"Error generating forecast: {err}"
227-
raise UpdateFailed(msg) from err
192+
return result
228193

229194
async def _generate_forecast(self) -> ForecastResult:
230195
"""Generate a forecast by shifting historical data forward.
@@ -241,11 +206,7 @@ async def _generate_forecast(self) -> ForecastResult:
241206
end_time = now
242207

243208
# Fetch historical statistics
244-
try:
245-
statistics = await get_statistics_for_sensor(self.hass, self._source_entity, start_time, end_time)
246-
except ValueError:
247-
_LOGGER.warning("Failed to get statistics for %s", self._source_entity)
248-
raise
209+
statistics = await get_statistics_for_sensor(self.hass, self._source_entity, start_time, end_time)
249210

250211
if not statistics:
251212
msg = f"No historical data available for {self._source_entity}"

custom_components/hafo/manifest.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
{
22
"domain": "hafo",
33
"name": "HAFO Forecast",
4-
"after_dependencies": ["recorder"],
54
"codeowners": ["@TrentHouliston"],
65
"config_flow": true,
7-
"dependencies": [],
6+
"dependencies": ["recorder"],
87
"documentation": "https://github.com/hass-energy/hafo",
98
"integration_type": "helper",
109
"iot_class": "calculated",

0 commit comments

Comments
 (0)