mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-05-28 18:43:40 +00:00
Accepts battery parameters (capacity, current/target SoC, max power) and returns a cost-minimized charging schedule with per-interval power, SoC progression, and total cost — no manual duration calculation needed. Supports fixed, continuous (min_charge_power_w), and stepped (charge_power_steps_w) charging modes, deadline-aware two-pass planning (must_reach_soc + must_reach_by / must_reach_by_event), and round-trip economics (expected_discharge_price, reserve_for_discharge, max_cost_per_kwh) for arbitrage use cases. Includes min_charge_duration and max_cycles_per_day constraints. Groups deadline fields (must_reach_soc_*, must_reach_by, must_reach_by_event) into a dedicated section so a deadline use case can be configured in one place. Battery section lists capacity before the percent SoC fields that depend on it. Response exposes stable reason codes (already_at_target, energy_unreachable, energy_unreachable_by_ deadline, no_intervals_after_economic_filter, …) documented in the service description and user docs.
162 lines
5.3 KiB
Python
162 lines
5.3 KiB
Python
"""
|
|
Service handlers for Tibber Prices integration.
|
|
|
|
This package provides service endpoints for external integrations and data export:
|
|
- Chart data export (get_chartdata)
|
|
- ApexCharts YAML generation (get_apexcharts_yaml)
|
|
- User data refresh (refresh_user_data)
|
|
- Debug: Clear tomorrow data (debug_clear_tomorrow) - DevContainer only
|
|
|
|
Architecture:
|
|
- helpers.py: Common utilities (get_entry_and_data)
|
|
- formatters.py: Data transformation and formatting functions
|
|
- chartdata.py: Main data export service handler
|
|
- apexcharts.py: ApexCharts card YAML generator
|
|
- refresh_user_data.py: User data refresh handler
|
|
- debug_clear_tomorrow.py: Debug tool for testing tomorrow refresh (dev only)
|
|
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from typing import TYPE_CHECKING
|
|
|
|
from custom_components.tibber_prices.const import DOMAIN
|
|
from homeassistant.core import SupportsResponse, callback
|
|
|
|
from .find_cheapest_block import (
|
|
FIND_CHEAPEST_BLOCK_SERVICE_NAME,
|
|
FIND_CHEAPEST_BLOCK_SERVICE_SCHEMA,
|
|
handle_find_cheapest_block,
|
|
)
|
|
from .find_cheapest_hours import (
|
|
FIND_CHEAPEST_HOURS_SERVICE_NAME,
|
|
FIND_CHEAPEST_HOURS_SERVICE_SCHEMA,
|
|
handle_find_cheapest_hours,
|
|
)
|
|
from .find_cheapest_schedule import (
|
|
FIND_CHEAPEST_SCHEDULE_SERVICE_NAME,
|
|
FIND_CHEAPEST_SCHEDULE_SERVICE_SCHEMA,
|
|
handle_find_cheapest_schedule,
|
|
)
|
|
from .find_most_expensive_block import (
|
|
FIND_MOST_EXPENSIVE_BLOCK_SERVICE_NAME,
|
|
FIND_MOST_EXPENSIVE_BLOCK_SERVICE_SCHEMA,
|
|
handle_find_most_expensive_block,
|
|
)
|
|
from .find_most_expensive_hours import (
|
|
FIND_MOST_EXPENSIVE_HOURS_SERVICE_NAME,
|
|
FIND_MOST_EXPENSIVE_HOURS_SERVICE_SCHEMA,
|
|
handle_find_most_expensive_hours,
|
|
)
|
|
from .get_apexcharts_yaml import APEXCHARTS_SERVICE_SCHEMA, APEXCHARTS_YAML_SERVICE_NAME, handle_apexcharts_yaml
|
|
from .get_chartdata import CHARTDATA_SERVICE_NAME, CHARTDATA_SERVICE_SCHEMA, handle_chartdata
|
|
from .get_price import GET_PRICE_SERVICE_NAME, GET_PRICE_SERVICE_SCHEMA, handle_get_price
|
|
from .plan_charging import PLAN_CHARGING_SERVICE_NAME, PLAN_CHARGING_SERVICE_SCHEMA, handle_plan_charging
|
|
from .refresh_user_data import (
|
|
REFRESH_USER_DATA_SERVICE_NAME,
|
|
REFRESH_USER_DATA_SERVICE_SCHEMA,
|
|
handle_refresh_user_data,
|
|
)
|
|
|
|
if TYPE_CHECKING:
|
|
from homeassistant.core import HomeAssistant
|
|
|
|
__all__ = [
|
|
"async_setup_services",
|
|
]
|
|
|
|
# Check if running in development mode (DevContainer)
|
|
_IS_DEV_MODE = os.environ.get("TIBBER_PRICES_DEV") == "1"
|
|
|
|
|
|
@callback
|
|
def async_setup_services(hass: HomeAssistant) -> None:
|
|
"""Set up services for Tibber Prices integration."""
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
APEXCHARTS_YAML_SERVICE_NAME,
|
|
handle_apexcharts_yaml,
|
|
schema=APEXCHARTS_SERVICE_SCHEMA,
|
|
supports_response=SupportsResponse.ONLY,
|
|
)
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
CHARTDATA_SERVICE_NAME,
|
|
handle_chartdata,
|
|
schema=CHARTDATA_SERVICE_SCHEMA,
|
|
supports_response=SupportsResponse.ONLY,
|
|
)
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
GET_PRICE_SERVICE_NAME,
|
|
handle_get_price,
|
|
schema=GET_PRICE_SERVICE_SCHEMA,
|
|
supports_response=SupportsResponse.ONLY,
|
|
)
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
FIND_CHEAPEST_BLOCK_SERVICE_NAME,
|
|
handle_find_cheapest_block,
|
|
schema=FIND_CHEAPEST_BLOCK_SERVICE_SCHEMA,
|
|
supports_response=SupportsResponse.ONLY,
|
|
)
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
FIND_CHEAPEST_HOURS_SERVICE_NAME,
|
|
handle_find_cheapest_hours,
|
|
schema=FIND_CHEAPEST_HOURS_SERVICE_SCHEMA,
|
|
supports_response=SupportsResponse.ONLY,
|
|
)
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
FIND_CHEAPEST_SCHEDULE_SERVICE_NAME,
|
|
handle_find_cheapest_schedule,
|
|
schema=FIND_CHEAPEST_SCHEDULE_SERVICE_SCHEMA,
|
|
supports_response=SupportsResponse.ONLY,
|
|
)
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
FIND_MOST_EXPENSIVE_BLOCK_SERVICE_NAME,
|
|
handle_find_most_expensive_block,
|
|
schema=FIND_MOST_EXPENSIVE_BLOCK_SERVICE_SCHEMA,
|
|
supports_response=SupportsResponse.ONLY,
|
|
)
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
FIND_MOST_EXPENSIVE_HOURS_SERVICE_NAME,
|
|
handle_find_most_expensive_hours,
|
|
schema=FIND_MOST_EXPENSIVE_HOURS_SERVICE_SCHEMA,
|
|
supports_response=SupportsResponse.ONLY,
|
|
)
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
PLAN_CHARGING_SERVICE_NAME,
|
|
handle_plan_charging,
|
|
schema=PLAN_CHARGING_SERVICE_SCHEMA,
|
|
supports_response=SupportsResponse.ONLY,
|
|
)
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
REFRESH_USER_DATA_SERVICE_NAME,
|
|
handle_refresh_user_data,
|
|
schema=REFRESH_USER_DATA_SERVICE_SCHEMA,
|
|
supports_response=SupportsResponse.ONLY,
|
|
)
|
|
|
|
# Debug services - only available in DevContainer (TIBBER_PRICES_DEV=1)
|
|
if _IS_DEV_MODE:
|
|
from .debug_clear_tomorrow import ( # noqa: PLC0415 - Conditional import for dev-only service
|
|
DEBUG_CLEAR_TOMORROW_SERVICE_NAME,
|
|
DEBUG_CLEAR_TOMORROW_SERVICE_SCHEMA,
|
|
handle_debug_clear_tomorrow,
|
|
)
|
|
|
|
hass.services.async_register(
|
|
DOMAIN,
|
|
DEBUG_CLEAR_TOMORROW_SERVICE_NAME,
|
|
handle_debug_clear_tomorrow,
|
|
schema=DEBUG_CLEAR_TOMORROW_SERVICE_SCHEMA,
|
|
supports_response=SupportsResponse.ONLY,
|
|
)
|