hass.tibber_prices/README.md
Julian Pawlowski 383b495545
Feature/adaptive defaults (#22)
* feat(period-calc): adaptive defaults + remove volatility filter

Major improvements to period calculation with smarter defaults and
simplified configuration:

**Adaptive Defaults:**
- ENABLE_MIN_PERIODS: true (was false) - Always try to find periods
- MIN_PERIODS target: 2 periods/day (ensures coverage)
- BEST_PRICE_MAX_LEVEL: "cheap" (was "any") - Prefer genuinely cheap
- PEAK_PRICE_MIN_LEVEL: "expensive" (was "any") - Prefer genuinely expensive
- GAP_TOLERANCE: 1 (was 0) - Allow 1-level deviations in sequences
- MIN_DISTANCE_FROM_AVG: 5% (was 2%) - Ensure significance
- PEAK_PRICE_MIN_PERIOD_LENGTH: 30min (was 60min) - More responsive
- PEAK_PRICE_FLEX: -20% (was -15%) - Better peak detection

**Volatility Filter Removal:**
- Removed CONF_BEST_PRICE_MIN_VOLATILITY from const.py
- Removed CONF_PEAK_PRICE_MIN_VOLATILITY from const.py
- Removed volatility filter UI controls from config_flow.py
- Removed filter_periods_by_volatility() calls from coordinator.py
- Updated all 5 translations (de, en, nb, nl, sv)

**Period Calculation Logic:**
- Level filter now integrated into _build_periods() (applied during
  interval qualification, not as post-filter)
- Gap tolerance implemented via _check_level_with_gap_tolerance()
- Short periods (<1.5h) use strict filtering (no gap tolerance)
- Relaxation now passes level_filter + gap_count directly to
  PeriodConfig
- show_periods check skipped when relaxation enabled (relaxation
  tries "any" as fallback)

**Documentation:**
- Complete rewrite of docs/user/period-calculation.md:
  * Visual examples with timelines
  * Step-by-step explanation of 4-step process
  * Configuration scenarios (5 common use cases)
  * Troubleshooting section with specific fixes
  * Advanced topics (per-day independence, early stop, etc.)
- Updated README.md: "volatility" → "distance from average"

Impact: Periods now reliably appear on most days with meaningful
quality filters. Users get warned about expensive periods and notified
about cheap opportunities without manual tuning. Relaxation ensures
coverage while keeping filters as strict as possible.

Breaking change: Volatility filter removed (was never a critical
feature, often confused users). Existing configs continue to work
(removed keys are simply ignored).

* feat(periods): modularize period_utils and add statistical outlier filtering

Refactored monolithic period_utils.py (1800 lines) into focused modules
for better maintainability and added advanced outlier filtering with
smart impact tracking.

Modular structure:
- types.py: Type definitions and constants (89 lines)
- level_filtering.py: Level filtering with gap tolerance (121 lines)
- period_building.py: Period construction from intervals (238 lines)
- period_statistics.py: Statistics and summaries (318 lines)
- period_merging.py: Overlap resolution (382 lines)
- relaxation.py: Per-day relaxation strategy (547 lines)
- core.py: Main API orchestration (251 lines)
- outlier_filtering.py: Statistical spike detection (294 lines)
- __init__.py: Public API exports (62 lines)

New statistical outlier filtering:
- Linear regression for trend-based spike detection
- 2 standard deviation confidence intervals (95%)
- Symmetry checking to preserve legitimate price shifts
- Enhanced zigzag detection with relative volatility (catches clusters)
- Replaces simple average smoothing with trend-based predictions

Smart impact tracking:
- Tests if original price would have passed criteria
- Only counts smoothed intervals that actually changed period formation
- Tracks level gap tolerance usage separately
- Both attributes only appear when > 0 (clean UI)

New period attributes:
- period_interval_smoothed_count: Intervals kept via outlier smoothing
- period_interval_level_gap_count: Intervals kept via gap tolerance

Impact: Statistical outlier filtering prevents isolated price spikes from
breaking continuous periods while preserving data integrity. All statistics
use original prices. Smart tracking shows only meaningful interventions,
making it clear when tolerance mechanisms actually influenced results.

Backwards compatible: All public APIs re-exported from period_utils package.

* Update docs/user/period-calculation.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update custom_components/tibber_prices/const.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update custom_components/tibber_prices/coordinator.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update custom_components/tibber_prices/const.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* docs(periods): fix corrupted period-calculation.md and add outlier filtering documentation

Completely rewrote period-calculation.md after severe corruption (massive text
duplication throughout the file made it 2489 lines).

Changes:
- Fixed formatting: Removed all duplicate text and headers
- Reduced file size: 2594 lines down to 516 lines (clean, readable structure)
- Added section 5: "Statistical Outlier Filtering (NEW)" explaining:
  - Linear regression-based spike detection (95% confidence intervals)
  - Symmetry checking to preserve legitimate price shifts
  - Enhanced zigzag detection with relative volatility
  - Data integrity guarantees (original prices always used)
  - New period attributes: period_interval_smoothed_count
- Added troubleshooting: "Price spikes breaking periods" section
- Added technical details: Algorithm constants and implementation notes

Impact: Users can now understand how outlier filtering prevents isolated
price spikes from breaking continuous periods. Documentation is readable
again with no duplicate content.

* fix(const): improve clarity in comments regarding period lengths for price alerts

* docs(periods): improve formatting and clarity in period-calculation.md

* Initial plan

* refactor: convert flexibility_pct to ratio once at function entry

Co-authored-by: jpawlowski <75446+jpawlowski@users.noreply.github.com>

* Update custom_components/tibber_prices/const.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update custom_components/tibber_prices/period_utils/period_building.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update custom_components/tibber_prices/period_utils/relaxation.py

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Julian Pawlowski <jpawlowski@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2025-11-13 23:51:29 +01:00

355 lines
18 KiB
Markdown

# Tibber Price Information & Ratings
[![GitHub Release][releases-shield]][releases]
[![GitHub Activity][commits-shield]][commits]
[![License][license-shield]](LICENSE)
[![hacs][hacsbadge]][hacs]
[![Project Maintenance][maintenance-shield]][user_profile]
[![BuyMeCoffee][buymecoffeebadge]][buymecoffee]
A Home Assistant integration that provides advanced price information and ratings from Tibber. This integration fetches **quarter-hourly** electricity prices, enriches them with statistical analysis, and provides smart indicators to help you optimize your energy consumption and save money.
![Tibber Price Information & Ratings](images/logo.png)
## 📖 Documentation
- **[User Guide](docs/user/)** - Installation, configuration, and usage guides
- **[Period Calculation](docs/user/period-calculation.md)** - How Best/Peak Price periods are calculated
- **[Developer Guide](docs/development/)** - Contributing, architecture, and release process
- **[Changelog](https://github.com/jpawlowski/hass.tibber_prices/releases)** - Release history and notes
## ✨ Features
- **Quarter-Hourly Price Data**: Access detailed 15-minute interval pricing (192 data points across yesterday/today/tomorrow)
- **Current and Next Interval Prices**: Get real-time price data in both major currency (€, kr) and minor units (ct, øre)
- **Multi-Currency Support**: Automatic detection and formatting for EUR, NOK, SEK, DKK, USD, and GBP
- **Price Level Indicators**: Know when you're in a VERY_CHEAP, CHEAP, NORMAL, EXPENSIVE, or VERY_EXPENSIVE period
- **Statistical Sensors**: Track lowest, highest, and average prices for the day
- **Price Ratings**: Quarter-hourly ratings comparing current prices to 24-hour trailing averages
- **Smart Indicators**: Binary sensors to detect peak hours and best price hours for automations
- **Intelligent Caching**: Minimizes API calls while ensuring data freshness across Home Assistant restarts
- **Custom Services**: API endpoints for advanced integrations (ApexCharts support included)
- **Diagnostic Sensors**: Monitor data freshness and availability
- **Reliable API Usage**: Uses only official Tibber [`priceInfo`](https://developer.tibber.com/docs/reference#priceinfo) and [`priceInfoRange`](https://developer.tibber.com/docs/reference#subscription) endpoints - no legacy APIs. Price ratings and statistics are calculated locally for maximum reliability and future-proofing.
## 🚀 Quick Start
### Step 1: Install the Integration
**Prerequisites:** This integration requires [HACS](https://hacs.xyz/) (Home Assistant Community Store) to be installed.
Click the button below to open the integration directly in HACS:
[![Open your Home Assistant instance and open a repository inside the Home Assistant Community Store.](https://my.home-assistant.io/badges/hacs_repository.svg)](https://my.home-assistant.io/redirect/hacs_repository/?owner=jpawlowski&repository=hass.tibber_prices&category=integration)
Then:
1. Click "Download" to install the integration
2. **Restart Home Assistant** (required after installation)
> **Note:** The My Home Assistant redirect will first take you to a landing page. Click the button there to open your Home Assistant instance. If the repository is not yet in the HACS default store, HACS will ask if you want to add it as a custom repository.
### Step 2: Add and Configure the Integration
**Important:** You must have installed the integration first (see Step 1) and restarted Home Assistant!
#### Option 1: One-Click Setup (Quick)
Click the button below to open the configuration dialog:
[![Open your Home Assistant instance and start setting up a new integration.](https://my.home-assistant.io/badges/config_flow_start.svg)](https://my.home-assistant.io/redirect/config_flow_start/?domain=tibber_prices)
This will guide you through:
1. Enter your Tibber API token ([get one here](https://developer.tibber.com/settings/access-token))
2. Select your Tibber home
3. Configure price thresholds (optional)
#### Option 2: Manual Configuration
1. Go to **Settings****Devices & Services**
2. Click **"+ Add Integration"**
3. Search for "Tibber Price Information & Ratings"
4. Follow the configuration steps (same as Option 1)
### Step 3: Start Using!
- 30+ sensors are now available (key sensors enabled by default)
- Configure additional sensors in **Settings****Devices & Services****Tibber Price Information & Ratings****Entities**
- Use sensors in automations, dashboards, and scripts
📖 **[Full Installation Guide →](docs/user/installation.md)**
## 📊 Available Entities
The integration provides **30+ sensors** across different categories. Key sensors are enabled by default, while advanced sensors can be enabled as needed.
> **Rich Sensor Attributes**: All sensors include extensive attributes with timestamps, context data, and detailed explanations. Enable **Extended Descriptions** in the integration options to add `long_description` and `usage_tips` attributes to every sensor, providing in-context documentation directly in Home Assistant's UI.
### Core Price Sensors (Enabled by Default)
| Entity | Description |
| ----------------------------- | ------------------------------------------------- |
| Current Electricity Price | Current 15-minute interval price |
| Next Interval Price | Price for the next 15-minute interval |
| Current Hour Average Price | Average of current hour's 4 intervals |
| Next Hour Average Price | Average of next hour's 4 intervals |
| Current Price Level | API classification (VERY_CHEAP to VERY_EXPENSIVE) |
| Next Interval Price Level | Price level for next interval |
| Current Hour Price Level | Price level for current hour average |
| Next Hour Price Level | Price level for next hour average |
### Statistical Sensors (Enabled by Default)
| Entity | Description |
| ------------------------------ | -------------------------------------------- |
| Today's Lowest Price | Minimum price for today |
| Today's Highest Price | Maximum price for today |
| Today's Average Price | Mean price across today's intervals |
| Tomorrow's Lowest Price | Minimum price for tomorrow (when available) |
| Tomorrow's Highest Price | Maximum price for tomorrow (when available) |
| Tomorrow's Average Price | Mean price for tomorrow (when available) |
| Leading 24h Average Price | Average of next 24 hours from now |
| Leading 24h Minimum Price | Lowest price in next 24 hours |
| Leading 24h Maximum Price | Highest price in next 24 hours |
### Price Rating Sensors (Enabled by Default)
| Entity | Description |
| --------------------------- | ---------------------------------------------------------- |
| Current Price Rating | % difference from 24h trailing average (current interval) |
| Next Interval Price Rating | % difference from 24h trailing average (next interval) |
| Current Hour Price Rating | % difference for current hour average |
| Next Hour Price Rating | % difference for next hour average |
> **How ratings work**: Compares each interval to the average of the previous 96 intervals (24 hours). Positive values mean prices are above average, negative means below average.
### Binary Sensors (Enabled by Default)
| Entity | Description |
| -------------------------- | -------------------------------------------------------------- |
| Peak Price Period | ON when in a detected peak price period ([how it works](docs/user/period-calculation.md)) |
| Best Price Period | ON when in a detected best price period ([how it works](docs/user/period-calculation.md)) |
| Tibber API Connection | Connection status to Tibber API |
| Tomorrow's Data Available | Whether tomorrow's price data is available |
### Diagnostic Sensors (Enabled by Default)
| Entity | Description |
| ----------------- | ------------------------------------------ |
| Data Expiration | Timestamp when current data expires |
| Price Forecast | Formatted list of upcoming price intervals |
### Additional Sensors (Disabled by Default)
The following sensors are available but disabled by default. Enable them in `Settings > Devices & Services > Tibber Price Information & Ratings > Entities`:
- **Previous Interval Price** & **Previous Interval Price Level**: Historical data for the last 15-minute interval
- **Previous Interval Price Rating**: Rating for the previous interval
- **Trailing 24h Average Price**: Average of the past 24 hours from now
- **Trailing 24h Minimum/Maximum Price**: Min/max in the past 24 hours
> **Note**: All monetary sensors use minor currency units (ct/kWh, øre/kWh, ¢/kWh, p/kWh) automatically based on your Tibber account's currency. Supported: EUR, NOK, SEK, DKK, USD, GBP.
## Automation Examples
> **Note:** See the [full automation examples guide](docs/user/automation-examples.md) for more advanced recipes.
### Run Appliances During Cheap Hours
Use the `binary_sensor.tibber_best_price_period` to automatically start appliances during detected best price periods:
```yaml
automation:
- alias: "Run Dishwasher During Cheap Hours"
trigger:
- platform: state
entity_id: binary_sensor.tibber_best_price_period
to: "on"
condition:
- condition: time
after: "21:00:00"
before: "06:00:00"
action:
- service: switch.turn_on
target:
entity_id: switch.dishwasher
```
> **Learn more:** The [period calculation guide](docs/user/period-calculation.md) explains how Best/Peak Price periods are identified and how you can configure filters (flexibility, minimum distance from average, price level filters with gap tolerance).
### Notify on Extremely High Prices
Get notified when prices reach the VERY_EXPENSIVE level:
```yaml
automation:
- alias: "Notify on Very Expensive Electricity"
trigger:
- platform: state
entity_id: sensor.tibber_current_price_level
to: "VERY_EXPENSIVE"
action:
- service: notify.mobile_app
data:
title: "⚠️ High Electricity Prices"
message: "Current electricity price is in the VERY EXPENSIVE range. Consider reducing consumption."
```
### Temperature Control Based on Price Ratings
Adjust heating/cooling when current prices are significantly above the 24h average:
```yaml
automation:
- alias: "Reduce Heating During High Price Ratings"
trigger:
- platform: numeric_state
entity_id: sensor.tibber_current_price_rating
above: 20 # More than 20% above 24h average
action:
- service: climate.set_temperature
target:
entity_id: climate.living_room
data:
temperature: 19 # Lower target temperature
```
### Smart EV Charging Based on Tomorrow's Prices
Start charging when tomorrow's prices drop below today's average:
```yaml
automation:
- alias: "Smart EV Charging"
trigger:
- platform: state
entity_id: binary_sensor.tibber_best_price_interval
to: "on"
condition:
- condition: numeric_state
entity_id: sensor.tibber_current_price_rating
below: -15 # At least 15% below average
- condition: numeric_state
entity_id: sensor.ev_battery_level
below: 80
action:
- service: switch.turn_on
target:
entity_id: switch.ev_charger
```
## Troubleshooting
### No data appearing
1. Check your API token is valid at [developer.tibber.com](https://developer.tibber.com/settings/access-token)
2. Verify you have an active Tibber subscription
3. Check the Home Assistant logs for detailed error messages (`Settings > System > Logs`)
4. Restart the integration: `Settings > Devices & Services > Tibber Price Information & Ratings > ⋮ > Reload`
### Missing tomorrow's price data
- Tomorrow's price data typically becomes available between **13:00 and 15:00** each day (Nordic time)
- The integration automatically checks more frequently during this window
- Check `binary_sensor.tibber_tomorrows_data_available` to see if data is available
- If data is unavailable after 15:00, verify it's available in the Tibber app first
### Prices not updating at quarter-hour boundaries
- Entities automatically refresh at 00/15/30/45-minute marks without waiting for API polls
- Check `sensor.tibber_data_expiration` to verify data freshness
- The integration caches data intelligently and survives Home Assistant restarts
### Currency or units showing incorrectly
- Currency is automatically detected from your Tibber account
- The integration supports EUR, NOK, SEK, DKK, USD, and GBP with appropriate minor units
- Enable/disable major vs. minor unit sensors in `Settings > Devices & Services > Tibber Price Information & Ratings > Entities`
## Advanced Features
### Sensor Attributes
Every sensor includes rich attributes beyond just the state value. These attributes provide context, timestamps, and additional data useful for automations and templates.
**Standard attributes available on most sensors:**
- `timestamp` - ISO 8601 timestamp for the data point
- `description` - Brief explanation of what the sensor represents
- `level_id` and `level_value` - For price level sensors (e.g., `VERY_CHEAP` = -2)
**Extended descriptions** (enable in integration options):
- `long_description` - Detailed explanation of the sensor's purpose
- `usage_tips` - Practical suggestions for using the sensor in automations
**Example - Current Price sensor attributes:**
```yaml
timestamp: "2025-11-03T14:15:00+01:00"
description: "The current electricity price per kWh"
long_description: "Shows the current price per kWh from your Tibber subscription"
usage_tips: "Use this to track prices or to create automations that run when electricity is cheap"
```
**Example template using attributes:**
```yaml
template:
- sensor:
- name: "Price Status"
state: >
{% set price = states('sensor.tibber_current_electricity_price') | float %}
{% set timestamp = state_attr('sensor.tibber_current_electricity_price', 'timestamp') %}
Price at {{ timestamp }}: {{ price }} ct/kWh
```
📖 **[View all sensors and attributes →](docs/user/sensors.md)**
### Custom Services
The integration provides custom services for advanced use cases:
- `tibber_prices.get_price` - Fetch price data for specific days/times
- `tibber_prices.get_apexcharts_data` - Get formatted data for ApexCharts cards
- `tibber_prices.get_apexcharts_yaml` - Generate complete ApexCharts configurations
- `tibber_prices.refresh_user_data` - Manually refresh account information
📖 **[Service documentation and examples →](docs/user/services.md)**
### ApexCharts Integration
The integration includes built-in support for creating beautiful price visualization cards. Use the `get_apexcharts_yaml` service to generate card configurations automatically.
📖 **[ApexCharts examples →](docs/user/automation-examples.md#apexcharts-cards)**
## 🤝 Contributing
Contributions are welcome! Please read the [Contributing Guidelines](CONTRIBUTING.md) and [Developer Guide](docs/development/) before submitting pull requests.
### For Contributors
- **[Developer Setup](docs/development/setup.md)** - Get started with DevContainer
- **[Architecture Guide](docs/development/architecture.md)** - Understand the codebase
- **[Release Management](docs/development/release-management.md)** - Release process and versioning
## 🤖 Development Note
This integration is developed with extensive AI assistance (GitHub Copilot, Claude, and other AI tools). While AI enables rapid development and helps implement complex features, it's possible that some edge cases or subtle bugs may exist that haven't been discovered yet. If you encounter any issues, please [open an issue](https://github.com/jpawlowski/hass.tibber_prices/issues/new) - we'll work on fixing them (with AI help, of course! 😊).
The integration is actively maintained and benefits from AI's ability to quickly understand and implement Home Assistant patterns, maintain consistency across the codebase, and handle complex data transformations. Quality is ensured through automated linting (Ruff), Home Assistant's type checking, and real-world testing.
## 📄 License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
---
[releases]: https://github.com/jpawlowski/hass.tibber_prices/releases
[releases-shield]: https://img.shields.io/github/release/jpawlowski/hass.tibber_prices.svg?style=for-the-badge
[commits-shield]: https://img.shields.io/github/commit-activity/y/jpawlowski/hass.tibber_prices.svg?style=for-the-badge
[commits]: https://github.com/jpawlowski/hass.tibber_prices/commits/main
[hacs]: https://github.com/hacs/integration
[hacsbadge]: https://img.shields.io/badge/HACS-Custom-orange.svg?style=for-the-badge
[exampleimg]: https://raw.githubusercontent.com/jpawlowski/hass.tibber_prices/main/images/example.png
[license-shield]: https://img.shields.io/github/license/jpawlowski/hass.tibber_prices.svg?style=for-the-badge
[maintenance-shield]: https://img.shields.io/badge/maintainer-%40jpawlowski-blue.svg?style=for-the-badge
[user_profile]: https://github.com/jpawlowski
[buymecoffee]: https://www.buymeacoffee.com/jpawlowski
[buymecoffeebadge]: https://img.shields.io/badge/buy%20me%20a%20coffee-donate-yellow.svg?style=for-the-badge