diff --git a/docs/user/docs/community-examples.md b/docs/user/docs/community-examples.md index e2e5b17..db22eaf 100644 --- a/docs/user/docs/community-examples.md +++ b/docs/user/docs/community-examples.md @@ -12,7 +12,16 @@ This page collects **real-world examples** contributed by the community — temp ## Country-Specific Price Calculations -The Tibber API provides the raw spot price (`energy_price` attribute) and tax/fee component (`tax` attribute) on every price sensor. Since the exact composition of `tax` varies by country, you can use these attributes to build **your own** country-specific calculations with Home Assistant templates. +The Tibber API provides the raw spot price (`energy_price` attribute) and tax/fee component (`tax` attribute) on every price sensor. Their unit follows your integration's **Currency Display Mode**: + +- Subunit mode: `ct/kWh` (default for EUR, including NL) +- Base mode: `€/kWh` + +Since the exact composition of `tax` varies by country, you can use these attributes to build **your own** country-specific calculations with Home Assistant templates. + +:::tip Keep templates unit-safe +For long-term stable templates, normalize values to `€/kWh` inside your template (recommended below). If you use Subunit mode, you can alternatively use the dedicated **Current Electricity Price (Energy Dashboard)** sensor (`current_interval_price_base`), which provides base-currency values for Energy Dashboard use cases. In Base mode, this extra sensor is not exposed because `current_interval_price` already provides base-currency values. +::: :::tip Why templates instead of built-in calculations? Tax rates and energy fees change regularly (often annually). Using `input_number` helpers in Home Assistant keeps your calculations up-to-date with a simple UI adjustment — no integration update needed. @@ -34,11 +43,11 @@ In the Netherlands, the electricity price paid to consumers includes: | Component | Dutch Name | Typical Value (2025) | |-----------|-----------|---------------------| -| Spot price | Inkoopprijs | Variable (= `energy_price` attribute) | +| Spot price | Inkoopprijs | Variable (`energy_price` attribute; unit depends on display mode) | | Energy tax | Energiebelasting | ~0.0916 €/kWh (excl. VAT) | -| VAT | BTW | 21% | | Purchase fee | Inkoopvergoeding | ~0.0205 €/kWh | -| Sales fee | Verkoopvergoeding | ~0.0205 €/kWh | +| Sales fee | Verkoopvergoeding | ~-0.0205 €/kWh | +| VAT | BTW | 21% | :::warning Rates change annually The values above are examples. Check [Rijksoverheid.nl](https://www.rijksoverheid.nl/onderwerpen/belastingplan/energiebelasting) for current energy tax rates and your energy contract for purchase/sales fees. @@ -57,9 +66,13 @@ Create `input_number` helpers in Home Assistant for each fee component. This way | Helper | Entity ID | Min | Max | Step | Unit | Example Value | |--------|-----------|-----|-----|------|------|---------------| | Energiebelasting | `input_number.energiebelasting` | 0 | 1 | 0.0001 | €/kWh | 0.0916 | -| BTW percentage | `input_number.btw_percentage` | 0 | 100 | 0.01 | % | 21 | | Inkoopvergoeding | `input_number.inkoopvergoeding` | 0 | 1 | 0.0001 | €/kWh | 0.0205 | -| Verkoopvergoeding | `input_number.verkoopvergoeding` | 0 | 1 | 0.0001 | €/kWh | 0.0205 | +| Verkoopvergoeding | `input_number.verkoopvergoeding` | -1 | 1 | 0.0001 | €/kWh | -0.0205 | +| BTW percentage | `input_number.btw_percentage` | 0 | 100 | 0.01 | % | 21 | + +:::note Signed fee input +`input_number.verkoopvergoeding` is a signed value in this example, so negative values are allowed. Enter all fee components excluding VAT. +:::
Show YAML: Input Number Helpers @@ -75,13 +88,6 @@ input_number: step: 0.0001 unit_of_measurement: "€/kWh" icon: mdi:lightning-bolt - btw_percentage: - name: BTW Percentage - min: 0 - max: 100 - step: 0.01 - unit_of_measurement: "%" - icon: mdi:percent inkoopvergoeding: name: Inkoopvergoeding min: 0 @@ -91,11 +97,18 @@ input_number: icon: mdi:cash-minus verkoopvergoeding: name: Verkoopvergoeding - min: 0 + min: -1 max: 1 step: 0.0001 unit_of_measurement: "€/kWh" icon: mdi:cash-plus + btw_percentage: + name: BTW Percentage + min: 0 + max: 100 + step: 0.01 + unit_of_measurement: "%" + icon: mdi:percent ```
@@ -112,19 +125,26 @@ template: - sensor: # Feed-in compensation WITH saldering (current rules, until 2027) # With saldering, you effectively earn the full consumer price - # minus the purchase fee, plus the sales fee. + # plus purchase and sales fee components (use negative verkoopvergoeding + # to offset inkoopvergoeding when your contract defines it that way). - name: "Solar Feed-In Price (with Saldering)" unique_id: solar_feed_in_saldering unit_of_measurement: "€/kWh" device_class: monetary state: > - {% set energy = state_attr('sensor._current_electricity_price', 'energy_price') %} + {# Option A: current display-mode sensor (default) #} + {# Option B: in Subunit mode, switch to current_interval_price_base for base-currency workflows #} + {% set price_entity = 'sensor._current_electricity_price' %} + {% set energy_raw = state_attr(price_entity, 'energy_price') %} + {% set price_unit = state_attr(price_entity, 'unit_of_measurement') %} + {% set unit_factor = 100 if price_unit == 'ct/kWh' else 1 %} {% set eb = states('input_number.energiebelasting') | float %} - {% set btw = states('input_number.btw_percentage') | float / 100 %} {% set inkoop = states('input_number.inkoopvergoeding') | float %} {% set verkoop = states('input_number.verkoopvergoeding') | float %} - {% if energy is not none %} - {{ ((energy + eb) * (1 + btw) - inkoop + verkoop) | round(4) }} + {% set btw = states('input_number.btw_percentage') | float / 100 %} + {% if energy_raw is not none %} + {% set energy = (energy_raw | float) / unit_factor %} + {{ ((energy + eb + inkoop + verkoop) * (1 + btw)) | round(4) }} {% else %} unavailable {% endif %} @@ -132,17 +152,24 @@ template: # Feed-in compensation WITHOUT saldering (after 2027) # Without saldering, you only earn the raw spot price - # minus the purchase fee, plus the sales fee. + # plus purchase and sales fee components. - name: "Solar Feed-In Price (without Saldering)" unique_id: solar_feed_in_no_saldering unit_of_measurement: "€/kWh" device_class: monetary state: > - {% set energy = state_attr('sensor._current_electricity_price', 'energy_price') %} + {# Option A: current display-mode sensor (default) #} + {# Option B: in Subunit mode, switch to current_interval_price_base for base-currency workflows #} + {% set price_entity = 'sensor._current_electricity_price' %} + {% set energy_raw = state_attr(price_entity, 'energy_price') %} + {% set price_unit = state_attr(price_entity, 'unit_of_measurement') %} + {% set unit_factor = 100 if price_unit == 'ct/kWh' else 1 %} {% set inkoop = states('input_number.inkoopvergoeding') | float %} {% set verkoop = states('input_number.verkoopvergoeding') | float %} - {% if energy is not none %} - {{ (energy - inkoop + verkoop) | round(4) }} + {% set btw = states('input_number.btw_percentage') | float / 100 %} + {% if energy_raw is not none %} + {% set energy = (energy_raw | float) / unit_factor %} + {{ ((energy + inkoop + verkoop) * (1 + btw)) | round(4) }} {% else %} unavailable {% endif %} @@ -187,6 +214,10 @@ automation: To understand the financial impact of the saldering phase-out, you can create a dashboard comparing both scenarios side by side: +:::note Unit label reminder +The label `ct/kWh` below is a manual display label. If your integration uses Base currency mode, update this label to `€/kWh` so it matches your active display mode. +::: +
Show YAML: Preparing for the End of Saldering @@ -199,7 +230,7 @@ entities: - type: attribute entity: sensor._current_electricity_price attribute: energy_price - name: "Spot Price (energy)" + name: "Spot Price (energy, ct/kWh)" icon: mdi:transmission-tower - entity: sensor.solar_feed_in_price_with_saldering name: "Feed-In with Saldering" @@ -213,43 +244,135 @@ entities: --- -## 🇩🇪 Germany: Price Composition +## 🇩🇪 Germany: Feed-In Compensation ### Background -In Germany, the electricity price includes numerous components bundled into `tax`: +In Germany, private households usually get a **fixed feed-in compensation** (Einspeisevergütung) for exported PV energy, while consumption uses the dynamic end-user price from your tariff. -| Component | German Name | Description | -|-----------|-----------|-------------| -| Spot price | Börsenstrompreis | Variable (= `energy_price` attribute) | -| Grid fees | Netzentgelte | Varies by grid operator | -| Electricity tax | Stromsteuer | Fixed per kWh | -| Concession fee | Konzessionsabgabe | Varies by municipality | -| Surcharges | Umlagen (§19, Offshore, KWKG) | Various regulatory surcharges | -| VAT | Mehrwertsteuer | 19% | +That means the practical question is often: -### Template: Spot Price Share +- consume/store energy locally now, or +- export now at your fixed feed-in rate -A simple template sensor showing what percentage of your total price is the actual energy cost: +### Step 1: Create Input Number Helper for Feed-In Compensation + +Create one helper for your current contractual feed-in rate in `€/kWh`. + +**Settings → Devices & Services → Helpers → Create Helper → Number** + +| Helper | Entity ID | Min | Max | Step | Unit | Example Value | +|--------|-----------|-----|-----|------|------|---------------| +| Einspeisevergütung | `input_number.einspeiseverguetung` | 0 | 1 | 0.0001 | €/kWh | 0.0778 | + +:::note Keep this value up to date +Use the exact value from your contract or network operator statement. Typical values differ by commissioning date and plant setup (partial vs full feed-in). +:::
-Show YAML: Spot Price Share +Show YAML: Input Number Helper + +```yaml +input_number: + einspeiseverguetung: + name: Einspeisevergütung + min: 0 + max: 1 + step: 0.0001 + unit_of_measurement: "€/kWh" + icon: mdi:transmission-tower-export +``` + +
+ +### Step 2: Template Sensors for Feed-In Decision Support + +These sensors normalize your current price to `€/kWh`, compare it with your fixed feed-in compensation, and expose a clean binary signal for automations. + +:::note Display-mode safe +`current_electricity_price` can be in `ct/kWh` or `€/kWh` depending on display mode. The template below normalizes automatically to `€/kWh`. +::: + +
+Show YAML: Feed-In Decision Sensors ```yaml template: - sensor: - - name: "Spot Price Share" - unique_id: spot_price_share - unit_of_measurement: "%" + - name: "Current Electricity Price (EUR normalized)" + unique_id: current_electricity_price_eur_normalized + unit_of_measurement: "€/kWh" + device_class: monetary state: > - {% set energy = state_attr('sensor._current_electricity_price', 'energy_price') %} - {% set total = states('sensor._current_electricity_price') | float %} - {% if energy is not none and total > 0 %} - {{ ((energy / total) * 100) | round(1) }} + {% set price_entity = 'sensor._current_electricity_price' %} + {% set total_raw = states(price_entity) | float(none) %} + {% set price_unit = state_attr(price_entity, 'unit_of_measurement') %} + {% set unit_factor = 100 if price_unit == 'ct/kWh' else 1 %} + {% if total_raw is not none %} + {{ (total_raw / unit_factor) | round(4) }} {% else %} unavailable {% endif %} - icon: mdi:chart-pie + icon: mdi:currency-eur + + - name: "Self-Consumption Advantage" + unique_id: self_consumption_advantage + unit_of_measurement: "€/kWh" + device_class: monetary + state: > + {% set import_price = states('sensor.current_electricity_price_eur_normalized') | float(none) %} + {% set feed_in = states('input_number.einspeiseverguetung') | float(none) %} + {% if import_price is not none and feed_in is not none %} + {{ (import_price - feed_in) | round(4) }} + {% else %} + unavailable + {% endif %} + icon: mdi:scale-balance + + - binary_sensor: + - name: "Prefer Self-Consumption" + unique_id: prefer_self_consumption + state: > + {% set advantage = states('sensor.self_consumption_advantage') | float(none) %} + {{ advantage is not none and advantage > 0 }} + icon: mdi:home-lightning-bolt +``` + +
+ +### Step 3: Use in Automations + +Use the binary sensor to switch behavior between export-oriented and self-consumption-oriented operation. + +
+Show YAML: Example Automation (Battery Charging Strategy) + +```yaml +automation: + - alias: "Battery: Prefer self-consumption when import price is higher than feed-in" + trigger: + - platform: state + entity_id: binary_sensor.prefer_self_consumption + action: + - choose: + - conditions: + - condition: state + entity_id: binary_sensor.prefer_self_consumption + state: "on" + sequence: + # Example: keep energy locally (charge battery / reduce export) + - service: switch.turn_on + target: + entity_id: switch.battery_charging + - conditions: + - condition: state + entity_id: binary_sensor.prefer_self_consumption + state: "off" + sequence: + # Example: allow more export to grid + - service: switch.turn_off + target: + entity_id: switch.battery_charging ```
@@ -258,7 +381,7 @@ template: ## 🇳🇴 Norway / 🇸🇪 Sweden: Grid & Tax Components -Norway and Sweden have their own fee structures, but the same pattern applies — use `input_number` helpers for the fixed/semi-fixed components and `energy_price` for the spot price. +Norway and Sweden have their own fee structures, but the same pattern applies — use `input_number` helpers for the fixed/semi-fixed components and `energy_price` for the spot price (unit depends on your display mode). **Contributions welcome!** If you have working template examples for Norway or Sweden, please share them in a [GitHub Discussion](https://github.com/jpawlowski/hass.tibber_prices/discussions).