diff --git a/custom_components/tibber_prices/services.yaml b/custom_components/tibber_prices/services.yaml index b62736d..e25fa9e 100644 --- a/custom_components/tibber_prices/services.yaml +++ b/custom_components/tibber_prices/services.yaml @@ -219,6 +219,16 @@ get_chartdata: default: false selector: boolean: + include_energy: + required: false + default: false + selector: + boolean: + include_tax: + required: false + default: false + selector: + boolean: start_time_field: required: false example: time @@ -246,6 +256,14 @@ get_chartdata: required: false selector: text: + energy_field: + required: false + selector: + text: + tax_field: + required: false + selector: + text: arrays_of_arrays: collapsed: true fields: diff --git a/custom_components/tibber_prices/services/get_chartdata.py b/custom_components/tibber_prices/services/get_chartdata.py index 463d8be..29426ea 100644 --- a/custom_components/tibber_prices/services/get_chartdata.py +++ b/custom_components/tibber_prices/services/get_chartdata.py @@ -280,6 +280,8 @@ CHARTDATA_SERVICE_SCHEMA: Final = vol.Schema( vol.Optional("include_level", default=False): bool, vol.Optional("include_rating_level", default=False): bool, vol.Optional("include_average", default=False): bool, + vol.Optional("include_energy", default=False): bool, + vol.Optional("include_tax", default=False): bool, vol.Optional("level_filter"): vol.All( vol.Coerce(list), normalize_level_filter, @@ -310,6 +312,8 @@ CHARTDATA_SERVICE_SCHEMA: Final = vol.Schema( vol.Optional("level_field", default="level"): str, vol.Optional("rating_level_field", default="rating_level"): str, vol.Optional("average_field", default="average"): str, + vol.Optional("energy_field", default="energy_price"): str, + vol.Optional("tax_field", default="tax"): str, vol.Optional("data_key", default="data"): str, vol.Optional("metadata", default="include"): vol.In(["include", "only", "none"]), } @@ -368,6 +372,8 @@ async def handle_chartdata(call: ServiceCall) -> dict[str, Any]: # noqa: PLR091 level_field = call.data.get("level_field", "level") rating_level_field = call.data.get("rating_level_field", "rating_level") average_field = call.data.get("average_field", "average") + energy_field = call.data.get("energy_field", "energy_price") + tax_field = call.data.get("tax_field", "tax") data_key = call.data.get("data_key", "data") resolution = call.data.get("resolution", "interval") output_format = call.data.get("output_format", "array_of_objects") @@ -377,6 +383,8 @@ async def handle_chartdata(call: ServiceCall) -> dict[str, Any]: # noqa: PLR091 include_level = call.data.get("include_level", False) include_rating_level = call.data.get("include_rating_level", False) include_average = call.data.get("include_average", False) + include_energy = call.data.get("include_energy", False) + include_tax = call.data.get("include_tax", False) insert_nulls = call.data.get("insert_nulls", "none") connect_segments = call.data.get("connect_segments", False) add_trailing_null = call.data.get("add_trailing_null", False) @@ -432,6 +440,10 @@ async def handle_chartdata(call: ServiceCall) -> dict[str, Any]: # noqa: PLR091 include_rating_level = True if average_field in array_fields_template: include_average = True + if energy_field in array_fields_template: + include_energy = True + if tax_field in array_fields_template: + include_tax = True # Get thresholds from config for rating aggregation threshold_low = coordinator.config_entry.options.get( @@ -470,6 +482,25 @@ async def handle_chartdata(call: ServiceCall) -> dict[str, Any]: # noqa: PLR091 # Get price data for all requested days chart_data = [] + def _add_energy_tax_fields(data_point: dict, interval: dict, price: float | None) -> None: + """Add energy and tax fields to a data point if requested and price is not None.""" + if price is None: + return + if include_energy and "energy" in interval: + energy_val = interval["energy"] + if energy_val is not None: + energy_val = round(float(energy_val) * 100, 2) if subunit_currency else round(float(energy_val), 4) + if round_decimals is not None: + energy_val = round(energy_val, round_decimals) + data_point[energy_field] = energy_val + if include_tax and "tax" in interval: + tax_val = interval["tax"] + if tax_val is not None: + tax_val = round(float(tax_val) * 100, 2) if subunit_currency else round(float(tax_val), 4) + if round_decimals is not None: + tax_val = round(tax_val, round_decimals) + data_point[tax_field] = tax_val + # Build set of timestamps that match period_filter if specified period_timestamps = None if period_filter: @@ -610,6 +641,9 @@ async def handle_chartdata(call: ServiceCall) -> dict[str, Any]: # noqa: PLR091 if include_average and day_key and day_key in day_averages: data_point[average_field] = day_averages[day_key] + # Add energy/tax if requested + _add_energy_tax_fields(data_point, interval, price) + chart_data.append(data_point) elif insert_nulls == "segments" and (level_filter or rating_level_filter): @@ -667,6 +701,8 @@ async def handle_chartdata(call: ServiceCall) -> dict[str, Any]: # noqa: PLR091 if include_average and day_key and day_key in day_averages: data_point[average_field] = day_averages[day_key] + _add_energy_tax_fields(data_point, interval, converted_price) + chart_data.append(data_point) # AFTER the real point: Add END-BRIDGE to draw vertical line DOWN to previous price @@ -806,6 +842,9 @@ async def handle_chartdata(call: ServiceCall) -> dict[str, Any]: # noqa: PLR091 day_key = _get_day_key_for_interval(last_start_time) if include_average and day_key and day_key in day_averages: last_data_point[average_field] = day_averages[day_key] + + _add_energy_tax_fields(last_data_point, last_interval, converted_last_price) + chart_data.append(last_data_point) # Extend to end of selected time range (midnight after last day) @@ -882,6 +921,8 @@ async def handle_chartdata(call: ServiceCall) -> dict[str, Any]: # noqa: PLR091 if include_average and day_key and day_key in day_averages: data_point[average_field] = day_averages[day_key] + _add_energy_tax_fields(data_point, interval, price) + chart_data.append(data_point) # Remove trailing null values ONLY for insert_nulls='segments' mode. diff --git a/custom_components/tibber_prices/translations/de.json b/custom_components/tibber_prices/translations/de.json index 05fe8ca..e6b97a6 100644 --- a/custom_components/tibber_prices/translations/de.json +++ b/custom_components/tibber_prices/translations/de.json @@ -1174,6 +1174,14 @@ "name": "Durchschnitt einschließen", "description": "Den Tagesdurchschnittspreis in jedem Datenpunkt zum Vergleich einschließen." }, + "include_energy": { + "name": "Energiepreis einschließen", + "description": "Den reinen Energie-/Spotpreis (ohne Steuern und Gebühren) in jedem Datenpunkt einschließen. Dies ist das 'energy'-Feld aus der Tibber-API, nützlich für Einspeisungs-/Salderungsberechnungen." + }, + "include_tax": { + "name": "Steueranteil einschließen", + "description": "Den Steueranteil des Preises in jedem Datenpunkt einschließen. Dies ist das 'tax'-Feld aus der Tibber-API, das Gebühren, Steuern und Netzentgelte darstellt." + }, "level_filter": { "name": "Preisniveau-Filter", "description": "Intervalle filtern, um nur bestimmte Tibber-Preisniveaus einzuschließen (sehr günstig/günstig/normal/teuer/sehr teuer). Falls nicht angegeben, werden alle Niveaus eingeschlossen." @@ -1222,6 +1230,14 @@ "name": "Durchschnitts-Feldname", "description": "Benutzerdefinierter Name für das Durchschnitts-Feld in der Ausgabe. Standard ist 'average', falls nicht angegeben. Wird nur verwendet, wenn include_average aktiviert ist." }, + "energy_field": { + "name": "Energiepreis-Feldname", + "description": "Benutzerdefinierter Name für das Energiepreis-Feld in der Ausgabe. Standard ist 'energy_price', falls nicht angegeben. Wird nur verwendet, wenn include_energy aktiviert ist." + }, + "tax_field": { + "name": "Steuer-Feldname", + "description": "Benutzerdefinierter Name für das Steuer-Feld in der Ausgabe. Standard ist 'tax', falls nicht angegeben. Wird nur verwendet, wenn include_tax aktiviert ist." + }, "metadata": { "name": "Metadaten", "description": "Steuerung der Metadaten-Einbindung in der Antwort. 'include' (Standard): Gibt Chart-Daten und Metadaten mit Preisstatistiken, Währungsinformationen, Y-Achsen-Vorschlägen und Zeitbereich zurück. 'only': Gibt nur Metadaten zurück ohne Chart-Daten zu verarbeiten (schnell, nützlich für dynamische Y-Achsen-Konfiguration). 'none': Gibt nur Chart-Daten ohne Metadaten zurück." diff --git a/custom_components/tibber_prices/translations/en.json b/custom_components/tibber_prices/translations/en.json index 974cc00..e8bd895 100644 --- a/custom_components/tibber_prices/translations/en.json +++ b/custom_components/tibber_prices/translations/en.json @@ -1178,6 +1178,14 @@ "name": "Include Average", "description": "Include the daily average price in each data point for comparison." }, + "include_energy": { + "name": "Include Energy Price", + "description": "Include the raw energy/spot price (excluding taxes and fees) in each data point. This is the 'energy' field from the Tibber API, useful for feed-in/net metering calculations." + }, + "include_tax": { + "name": "Include Tax", + "description": "Include the tax component of the price in each data point. This is the 'tax' field from the Tibber API, representing fees, taxes, and grid charges." + }, "level_filter": { "name": "Level Filter", "description": "Filter intervals to include only specific Tibber price levels (very cheap/cheap/normal/expensive/very expensive). If not specified, all levels are included." @@ -1226,6 +1234,14 @@ "name": "Average Field Name", "description": "Custom name for the average field in the output. Defaults to 'average' if not specified. Only used when include_average is enabled." }, + "energy_field": { + "name": "Energy Field Name", + "description": "Custom name for the energy price field in the output. Defaults to 'energy_price' if not specified. Only used when include_energy is enabled." + }, + "tax_field": { + "name": "Tax Field Name", + "description": "Custom name for the tax field in the output. Defaults to 'tax' if not specified. Only used when include_tax is enabled." + }, "metadata": { "name": "Metadata", "description": "Control metadata inclusion in the response. 'include' (default): Returns both chart data and metadata with price statistics, currency info, Y-axis suggestions, and time range. 'only': Returns only metadata without processing chart data (fast, useful for dynamic Y-axis configuration). 'none': Returns only chart data without metadata." diff --git a/custom_components/tibber_prices/translations/nb.json b/custom_components/tibber_prices/translations/nb.json index e9d4eeb..10f283a 100644 --- a/custom_components/tibber_prices/translations/nb.json +++ b/custom_components/tibber_prices/translations/nb.json @@ -1174,6 +1174,14 @@ "name": "Inkluder gjennomsnitt", "description": "Inkluder daglig gjennomsnittspris i hvert datapunkt for sammenligning." }, + "include_energy": { + "name": "Inkluder energipris", + "description": "Inkluder rå energi-/spotpris (ekskludert skatter og avgifter) i hvert datapunkt. Dette er 'energy'-feltet fra Tibber-APIet, nyttig for innmatings-/nettomålingsberegninger." + }, + "include_tax": { + "name": "Inkluder skatt", + "description": "Inkluder skatteandelen av prisen i hvert datapunkt. Dette er 'tax'-feltet fra Tibber-APIet, som representerer avgifter, skatter og nettleie." + }, "level_filter": { "name": "Prisnivåfilter", "description": "Filtrer intervaller for å bare inkludere spesifikke Tibber-prisnivåer (veldig billig/billig/normal/dyr/veldig dyr). Hvis ikke angitt, inkluderes alle nivåer." @@ -1222,6 +1230,14 @@ "name": "Gjennomsnittsfelt-navn", "description": "Tilpasset navn for gjennomsnittsfeltet i utdata. Standard er 'average'. Brukes bare når include_average er aktivert." }, + "energy_field": { + "name": "Energiprisfelt-navn", + "description": "Tilpasset navn for energiprisfeltet i utdata. Standard er 'energy_price'. Brukes bare når include_energy er aktivert." + }, + "tax_field": { + "name": "Skattefelt-navn", + "description": "Tilpasset navn for skattefeltet i utdata. Standard er 'tax'. Brukes bare når include_tax er aktivert." + }, "metadata": { "name": "Metadata", "description": "Kontroller metadata-inkludering i svaret. 'include' (standard): Returnerer både diagramdata og metadata med prisstatistikk, valutainformasjon, Y-akse forslag og tidsperiode. 'only': Returnerer bare metadata uten å behandle diagramdata (raskt, nyttig for dynamisk Y-akse konfigurasjon). 'none': Returnerer bare diagramdata uten metadata." diff --git a/custom_components/tibber_prices/translations/nl.json b/custom_components/tibber_prices/translations/nl.json index 495c5aa..5c0338a 100644 --- a/custom_components/tibber_prices/translations/nl.json +++ b/custom_components/tibber_prices/translations/nl.json @@ -1174,6 +1174,14 @@ "name": "Gemiddelde opnemen", "description": "Dagelijkse gemiddelde prijs opnemen in elk gegevenspunt ter vergelijking." }, + "include_energy": { + "name": "Energieprijs opnemen", + "description": "De kale energie-/spotprijs (exclusief belastingen en heffingen) opnemen in elk gegevenspunt. Dit is het 'energy'-veld uit de Tibber-API, handig voor teruglever-/salderingsberekeningen." + }, + "include_tax": { + "name": "Belasting opnemen", + "description": "Het belastingdeel van de prijs opnemen in elk gegevenspunt. Dit is het 'tax'-veld uit de Tibber-API, dat heffingen, belastingen en netwerkkosten vertegenwoordigt." + }, "level_filter": { "name": "Prijsniveaufilter", "description": "Intervallen filteren om alleen specifieke Tibber-prijsniveaus op te nemen (zeer goedkoop/goedkoop/normaal/duur/zeer duur). Indien niet opgegeven, worden alle niveaus opgenomen." @@ -1222,6 +1230,14 @@ "name": "Gemiddelde veld-naam", "description": "Aangepaste naam voor het gemiddelde veld in de uitvoer. Standaard is 'average'. Alleen gebruikt wanneer include_average is ingeschakeld." }, + "energy_field": { + "name": "Energieprijs veld-naam", + "description": "Aangepaste naam voor het energieprijsveld in de uitvoer. Standaard is 'energy_price'. Alleen gebruikt wanneer include_energy is ingeschakeld." + }, + "tax_field": { + "name": "Belasting veld-naam", + "description": "Aangepaste naam voor het belastingveld in de uitvoer. Standaard is 'tax'. Alleen gebruikt wanneer include_tax is ingeschakeld." + }, "metadata": { "name": "Metadata", "description": "Beheer metadata-opname in het antwoord. 'include' (standaard): Retourneert zowel grafiekdata als metadata met prijsstatistieken, valuta-info, Y-as suggesties en tijdsbereik. 'only': Retourneert alleen metadata zonder grafiekdata te verwerken (snel, handig voor dynamische Y-as configuratie). 'none': Retourneert alleen grafiekdata zonder metadata." diff --git a/custom_components/tibber_prices/translations/sv.json b/custom_components/tibber_prices/translations/sv.json index 30d61f5..55247b2 100644 --- a/custom_components/tibber_prices/translations/sv.json +++ b/custom_components/tibber_prices/translations/sv.json @@ -1178,6 +1178,14 @@ "name": "Inkludera medelvärde", "description": "Inkludera dagligt medelpris i varje datapunkt för jämförelse." }, + "include_energy": { + "name": "Inkludera energipris", + "description": "Inkludera rått energi-/spotpris (exklusive skatter och avgifter) i varje datapunkt. Detta är 'energy'-fältet från Tibber-API:et, användbart för inmatnings-/nettomätningsberäkningar." + }, + "include_tax": { + "name": "Inkludera skatt", + "description": "Inkludera skattedelen av priset i varje datapunkt. Detta är 'tax'-fältet från Tibber-API:et, som representerar avgifter, skatter och nätavgifter." + }, "level_filter": { "name": "Nivåfilter", "description": "Filtrera intervaller för att endast inkludera specifika Tibber-prisnivåer (mycket billigt/billigt/normalt/dyrt/mycket dyrt). Om inget anges inkluderas alla nivåer." @@ -1226,6 +1234,14 @@ "name": "Medelvärdesfältnamn", "description": "Anpassat namn för medelvärdesfältet i utdatan. Standard är 'average' om inget anges. Används endast när include_average är aktiverad." }, + "energy_field": { + "name": "Energiprisfältnamn", + "description": "Anpassat namn för energiprisfältet i utdatan. Standard är 'energy_price' om inget anges. Används endast när include_energy är aktiverad." + }, + "tax_field": { + "name": "Skattefältnamn", + "description": "Anpassat namn för skattefältet i utdatan. Standard är 'tax' om inget anges. Används endast när include_tax är aktiverad." + }, "metadata": { "name": "Metadata", "description": "Kontrollera inkludering av metadata i svaret. 'include' (standard): Returnerar både diagramdata och metadata med prisstatistik, valutainfo, Y-axelförslag och tidsintervall. 'only': Returnerar endast metadata utan att bearbeta diagramdata (snabbt, användbart för dynamisk Y-axelkonfiguration). 'none': Returnerar endast diagramdata utan metadata."