Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions custom_components/pumpsteer/sensor/sensor.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import logging
from datetime import datetime, timedelta
from typing import Any, Dict, List, Optional, Tuple
Expand Down Expand Up @@ -121,20 +121,20 @@

def compute_block_status(
update_time: datetime,
blocks: List["PriceBlock"],

Check failure on line 124 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.12)

Ruff (F821)

custom_components/pumpsteer/sensor/sensor.py:124:19: F821 Undefined name `PriceBlock`

Check failure on line 124 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.13)

Ruff (F821)

custom_components/pumpsteer/sensor/sensor.py:124:19: F821 Undefined name `PriceBlock`

Check failure on line 124 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.14)

Ruff (F821)

custom_components/pumpsteer/sensor/sensor.py:124:19: F821 Undefined name `PriceBlock`
) -> Tuple[
Optional[datetime],
Optional[datetime],
bool,
str,
int,
List[Tuple["PriceBlock", datetime, datetime]],

Check failure on line 131 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.12)

Ruff (F821)

custom_components/pumpsteer/sensor/sensor.py:131:17: F821 Undefined name `PriceBlock`

Check failure on line 131 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.13)

Ruff (F821)

custom_components/pumpsteer/sensor/sensor.py:131:17: F821 Undefined name `PriceBlock`

Check failure on line 131 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.14)

Ruff (F821)

custom_components/pumpsteer/sensor/sensor.py:131:17: F821 Undefined name `PriceBlock`
]:
"""Compute block timing and status details."""
if not blocks:
return None, None, False, "none", 0, []

block_windows: List[Tuple["PriceBlock", datetime, datetime]] = []

Check failure on line 137 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.12)

Ruff (F821)

custom_components/pumpsteer/sensor/sensor.py:137:32: F821 Undefined name `PriceBlock`

Check failure on line 137 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.13)

Ruff (F821)

custom_components/pumpsteer/sensor/sensor.py:137:32: F821 Undefined name `PriceBlock`

Check failure on line 137 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.14)

Ruff (F821)

custom_components/pumpsteer/sensor/sensor.py:137:32: F821 Undefined name `PriceBlock`
for block in blocks:
block_start = update_time + timedelta(minutes=block.start_offset_minutes)
block_end = update_time + timedelta(minutes=block.end_offset_minutes)
Expand Down Expand Up @@ -187,7 +187,7 @@

def compute_block_window(
update_time: datetime,
blocks: Optional["PriceBlock"] | List["PriceBlock"],

Check failure on line 190 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.12)

Ruff (F821)

custom_components/pumpsteer/sensor/sensor.py:190:44: F821 Undefined name `PriceBlock`

Check failure on line 190 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.12)

Ruff (F821)

custom_components/pumpsteer/sensor/sensor.py:190:23: F821 Undefined name `PriceBlock`

Check failure on line 190 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.13)

Ruff (F821)

custom_components/pumpsteer/sensor/sensor.py:190:44: F821 Undefined name `PriceBlock`

Check failure on line 190 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.13)

Ruff (F821)

custom_components/pumpsteer/sensor/sensor.py:190:23: F821 Undefined name `PriceBlock`

Check failure on line 190 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.14)

Ruff (F821)

custom_components/pumpsteer/sensor/sensor.py:190:44: F821 Undefined name `PriceBlock`

Check failure on line 190 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.14)

Ruff (F821)

custom_components/pumpsteer/sensor/sensor.py:190:23: F821 Undefined name `PriceBlock`
) -> Tuple[Optional[datetime], Optional[datetime], bool, str]:
"""Return the canonical block window and state for a block or list."""
if blocks is None:
Expand Down Expand Up @@ -742,10 +742,12 @@
brake_offset_c: float = 0.0,
brake_target_c: float = 0.0,
is_winter_brake: bool = False,
ramp_up_c_per_15min: float = 0.0,
ramp_down_c_per_15min: float = 0.0,
) -> Dict[str, Any]:
"""Build attribute dictionary for the sensor"""
max_price = max(prices) if prices else 1.0
min_price = min(prices) if prices else 0.0

Check failure on line 750 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.12)

Ruff (F841)

custom_components/pumpsteer/sensor/sensor.py:750:9: F841 Local variable `min_price` is assigned to but never used

Check failure on line 750 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.13)

Ruff (F841)

custom_components/pumpsteer/sensor/sensor.py:750:9: F841 Local variable `min_price` is assigned to but never used

Check failure on line 750 in custom_components/pumpsteer/sensor/sensor.py

View workflow job for this annotation

GitHub Actions / check (3.14)

Ruff (F841)

custom_components/pumpsteer/sensor/sensor.py:750:9: F841 Local variable `min_price` is assigned to but never used
braking_threshold_ratio = (
1.0 - (sensor_data["aggressiveness"] / 5.0) * AGGRESSIVENESS_SCALING_FACTOR
)
Expand Down Expand Up @@ -871,6 +873,8 @@
"brake_offset_c": round(brake_offset_c, 2),
"brake_target_c": round(brake_target_c, 2),
"is_winter_brake": is_winter_brake,
"ramp_up_c_per_15min": round(ramp_up_c_per_15min, 2),
"ramp_down_c_per_15min": round(ramp_down_c_per_15min, 2),
"data_quality": {
"prices_count": len(prices),
"categories_count": len(categories),
Expand Down Expand Up @@ -983,14 +987,22 @@
target_brake_offset_c = (
price_pressure * WINTER_BRAKE_TEMP_OFFSET if is_winter else 0.0
)
aggressiveness = sensor_data["aggressiveness"]
aggressiveness_clamped = max(1.0, min(aggressiveness, 5.0))
ramp_factor = aggressiveness_clamped / 3.0
ramp_up_c_per_15min = 3.0 * ramp_factor
ramp_down_c_per_15min = 2.0 * ramp_factor
dt_minutes = price_interval_minutes if price_interval_minutes > 0 else 60
step_up = ramp_up_c_per_15min * (dt_minutes / 15.0)
step_down = ramp_down_c_per_15min * (dt_minutes / 15.0)
previous_brake_offset = (
self._last_brake_offset if self._last_brake_offset is not None else 0.0
)
brake_offset_c, _ = apply_rate_limit(
target_brake_offset_c,
previous_brake_offset,
PRICE_BRAKE_MAX_DELTA_PER_STEP * WINTER_BRAKE_TEMP_OFFSET,
)
brake_offset_c = previous_brake_offset
if target_brake_offset_c > brake_offset_c:
brake_offset_c = min(brake_offset_c + step_up, target_brake_offset_c)
elif target_brake_offset_c < brake_offset_c:
brake_offset_c = max(brake_offset_c - step_down, target_brake_offset_c)
self._last_brake_offset = brake_offset_c
await self._persist_brake_offset(brake_offset_c)
control_outdoor_temperature = fake_temp + brake_offset_c
Expand Down Expand Up @@ -1033,6 +1045,8 @@
brake_offset_c=brake_offset_c,
brake_target_c=target_brake_offset_c,
is_winter_brake=is_winter_brake,
ramp_up_c_per_15min=ramp_up_c_per_15min,
ramp_down_c_per_15min=ramp_down_c_per_15min,
)
self._update_diagnostics(
prices,
Expand Down
Loading