From b69be7e87adabf6a2a994c34d61c6f927e0dc0df Mon Sep 17 00:00:00 2001 From: Julian Pawlowski Date: Sat, 30 May 2026 14:46:40 +0000 Subject: [PATCH] docs(actions): document success flag and outage-vs-no-data contract Explain the top-level success flag and the price_data_unavailable reason for get_price, find_cheapest_*, and plan_charging, and clarify that an empty result with success=true (e.g. tomorrow's prices not yet published) is not an error. Note that day-ahead prices usually arrive around 13:00 but can be delayed into the afternoon or evening. Impact: Automation authors can reliably tell a temporary API outage apart from normally missing data. --- docs/user/docs/data-actions.md | 28 ++++++++++++++++++++++++++ docs/user/docs/plan-charging-action.md | 4 +++- docs/user/docs/scheduling-actions.md | 21 ++++++++++++++++++- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/docs/user/docs/data-actions.md b/docs/user/docs/data-actions.md index 3fe9054..69ab8fd 100644 --- a/docs/user/docs/data-actions.md +++ b/docs/user/docs/data-actions.md @@ -39,6 +39,7 @@ response_variable: price_data ```json { + "success": true, "home_id": "abc-123", "start_time": "2025-11-01T00:00:00+01:00", "end_time": "2025-11-02T00:00:00+01:00", @@ -63,6 +64,33 @@ response_variable: price_data **Note:** Times are automatically converted to your Tibber home's timezone. The interval pool caches previously fetched intervals, so repeated calls for the same range are fast. +### Checking the Result + +The response always has the expected shape — even when no data could be returned — so your automations never have to guard against missing fields. Use the `success` flag to tell apart two very different situations: + +| Situation | `success` | `price_info` | What it means | +|-----------|-----------|--------------|---------------| +| Data returned | `true` | populated | Prices are available for the range. | +| No prices for the range *yet* | `true` | `[]` (`interval_count: 0`) | **Not an error.** Tomorrow's prices are usually published by Tibber around 13:00 local time, but the underlying day-ahead auction can be delayed — occasionally the data only appears later in the afternoon or evening (and on rare auction failures, not at all for that day). Before that, a range covering tomorrow legitimately returns empty. Retry later. | +| Tibber API unavailable | `false` (`reason: "price_data_unavailable"`) | `[]` | A temporary API outage prevented the fetch on an uncached range. Existing sensors keep working from cache; retry later. | + +:::tip Distinguishing "no data yet" from "outage" +Check `success` first. `success: true` with an empty `price_info` means **the request worked, there simply are no prices for that range yet** (typically tomorrow before the day-ahead prices are published — usually around 13:00, but sometimes later in the afternoon or evening). `success: false` means **the API call itself failed** — treat it as a transient error and retry later. +::: + +```yaml +# Example: only act when prices are actually available +- if: "{{ price_data.success and price_data.interval_count > 0 }}" + then: + - service: notify.mobile_app + data: + message: "Got {{ price_data.interval_count }} price intervals." +- if: "{{ not price_data.success }}" + then: + # Tibber API outage — retry later, sensors keep running from cache + - delay: "00:30:00" +``` + --- ## tibber_prices.refresh_user_data diff --git a/docs/user/docs/plan-charging-action.md b/docs/user/docs/plan-charging-action.md index 94ad482..5e1a1cf 100644 --- a/docs/user/docs/plan-charging-action.md +++ b/docs/user/docs/plan-charging-action.md @@ -131,6 +131,7 @@ The response contains the following top-level keys: | Key | Description | |-----|-------------| +| `success` | `true` when the request itself worked (even if no schedule was produced); `false` only on a Tibber API outage (`reason: "price_data_unavailable"`). | | `intervals_found` | `true` when a schedule was produced. | | `battery` | Normalized SoC / capacity / efficiency / `achieved_soc_kwh` (what you actually reach with the returned schedule). | | `charging` | Mode, total duration, total energy, total cost, and the `schedule` block. | @@ -157,8 +158,9 @@ When no schedule is found, `reason` contains one of: | Code | Meaning | |------|---------| +| `price_data_unavailable` | The Tibber API was temporarily unavailable for an uncached range. This is the **only** case where `success` is `false` — treat it as a transient error and retry later. Your sensors keep running from cache. | | `already_at_target` | Current SoC is already at or above target — no charging needed. | -| `no_data_in_range` | The search range has no price data. | +| `no_data_in_range` | The search range has no price data. Often **not an error**: tomorrow's prices are usually published by Tibber around 13:00 local time, but the day-ahead auction can be delayed — sometimes the data only arrives later in the afternoon or evening. A range covering tomorrow returns this until then (with `success: true`). Retry later. | | `no_intervals_matching_level_filter` | `min_price_level` / `max_price_level` filtered everything out. | | `no_intervals_after_economic_filter` | `max_cost_per_kwh` or `reserve_for_discharge` filtered everything out. | | `energy_unreachable` | The energy needed cannot be charged within the available intervals + power limits. | diff --git a/docs/user/docs/scheduling-actions.md b/docs/user/docs/scheduling-actions.md index 605489a..e6cac69 100644 --- a/docs/user/docs/scheduling-actions.md +++ b/docs/user/docs/scheduling-actions.md @@ -383,6 +383,7 @@ response_variable: result ```json { + "success": true, "home_id": "abc-123", "search_start": "2026-04-11T14:00:00+02:00", "search_end": "2026-04-12T14:00:00+02:00", @@ -534,6 +535,7 @@ response_variable: result ```json { + "success": true, "home_id": "abc-123", "search_start": "2026-04-11T14:00:00+02:00", "search_end": "2026-04-12T14:00:00+02:00", @@ -679,6 +681,7 @@ response_variable: result ```json { + "success": true, "home_id": "abc-123", "search_start": "2026-04-11T22:00:00+02:00", "search_end": "2026-04-12T07:00:00+02:00", @@ -1047,7 +1050,8 @@ The `reason` field contains a stable machine-readable code you can use in automa | Reason Code | Meaning | |-------------|---------| -| `no_data_in_range` | No price data available for the search range | +| `price_data_unavailable` | The Tibber API was temporarily unavailable for an uncached range (see [Distinguishing an outage from "no data yet"](#distinguishing-an-outage-from-no-data-yet)) | +| `no_data_in_range` | No price data available for the search range (e.g., tomorrow's prices not published yet) | | `no_intervals_matching_level_filter` | Level filter excluded all intervals | | `insufficient_intervals_after_filter` | Not enough intervals left after filtering | | `insufficient_intervals_for_constraints` | Enough intervals, but constraints (min segment) can't be met | @@ -1060,3 +1064,18 @@ The `reason` field contains a stable machine-readable code you can use in automa | `relaxation_exhausted` | All relaxation steps tried, still no result (only when `allow_relaxation: true`) | Always check the failure fields in your automations before using the results. + +### Distinguishing an outage from "no data yet" + +Every response carries a top-level `success` flag so automations can react correctly **without inspecting the data fields**: + +| Situation | `success` | `reason` | What it means | +|-----------|-----------|----------|---------------| +| Result found | `true` | — | Use the schedule/window. | +| No match for your criteria | `true` | `no_data_in_range`, `no_intervals_matching_level_filter`, … | **Not an error.** The request worked; there is simply no result. A common case: tomorrow's prices are usually published by Tibber around 13:00 local time, but the day-ahead auction can be delayed — sometimes the data only arrives later in the afternoon or evening. A search covering tomorrow returns `no_data_in_range` until then. Retry later. | +| Tibber API unavailable | `false` | `price_data_unavailable` | A temporary API outage prevented the fetch on an uncached range. Existing sensors keep working from cache; retry later. | + +:::tip Key distinction +`success: true` means **the request itself worked** — even if no window was found (e.g., tomorrow's prices aren't out yet). `success: false` with `reason: "price_data_unavailable"` means **the API call failed** — treat it as a transient error and retry. These service calls never impair your sensors: a failed fetch for an uncached range leaves cached sensor data untouched. +::: +