1
0
mirror of https://github.com/home-assistant/core.git synced 2026-04-02 08:26:41 +01:00
Files
core/tests/components/tibber/test_sensor.py
Daniel Hjelseth Høyer 35a99dd4a4 Fix Tibber update token (#164295)
Signed-off-by: Daniel Hjelseth Høyer <github@dahoiv.net>
2026-03-17 15:11:51 +01:00

257 lines
10 KiB
Python

"""Tests for the Tibber Data API sensors and coordinator."""
from __future__ import annotations
from unittest.mock import AsyncMock, MagicMock
import pytest
from homeassistant.components.recorder import Recorder
from homeassistant.components.tibber.const import DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.entity_component import async_update_entity
from homeassistant.util import dt as dt_util
from .conftest import create_tibber_device
from tests.common import MockConfigEntry
def _create_home(*, current_price: float | None = 1.25) -> MagicMock:
"""Create a mocked Tibber home with an active subscription."""
home = MagicMock()
home.home_id = "home-id"
home.name = "Home"
home.currency = "NOK"
home.price_unit = "NOK/kWh"
home.has_active_subscription = True
home.has_real_time_consumption = False
home.last_data_timestamp = None
home.update_info = AsyncMock(return_value=None)
home.update_info_and_price_info = AsyncMock(return_value=None)
home.current_price_data = MagicMock(
return_value=(current_price, dt_util.utcnow(), 0.4)
)
home.current_attributes = MagicMock(
return_value={
"max_price": 1.8,
"avg_price": 1.2,
"min_price": 0.8,
"off_peak_1": 0.9,
"peak": 1.7,
"off_peak_2": 1.0,
}
)
home.month_cost = 111.1
home.peak_hour = 2.5
home.peak_hour_time = dt_util.utcnow()
home.month_cons = 222.2
home.hourly_consumption_data = []
home.hourly_production_data = []
home.info = {
"viewer": {
"home": {
"appNickname": "Home",
"address": {"address1": "Street 1"},
"meteringPointData": {
"gridCompany": "GridCo",
"estimatedAnnualConsumption": 12000,
},
}
}
}
return home
async def test_price_sensor_state_unit_and_attributes(
recorder_mock: Recorder,
hass: HomeAssistant,
config_entry: MockConfigEntry,
tibber_mock: MagicMock,
setup_credentials: None,
entity_registry: er.EntityRegistry,
) -> None:
"""Test price sensor state and attributes."""
home = _create_home(current_price=1.25)
tibber_mock.get_homes.return_value = [home]
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
entity_id = entity_registry.async_get_entity_id("sensor", DOMAIN, home.home_id)
assert entity_id is not None
await async_update_entity(hass, entity_id)
await hass.async_block_till_done()
state = hass.states.get(entity_id)
assert state is not None
assert float(state.state) == 1.25
assert state.attributes["unit_of_measurement"] == "NOK/kWh"
assert state.attributes["app_nickname"] == "Home"
assert state.attributes["grid_company"] == "GridCo"
assert state.attributes["estimated_annual_consumption"] == 12000
assert state.attributes["intraday_price_ranking"] == 0.4
assert state.attributes["max_price"] == 1.8
assert state.attributes["avg_price"] == 1.2
assert state.attributes["min_price"] == 0.8
assert state.attributes["off_peak_1"] == 0.9
assert state.attributes["peak"] == 1.7
assert state.attributes["off_peak_2"] == 1.0
async def test_data_api_sensors_are_created(
recorder_mock: Recorder,
hass: HomeAssistant,
config_entry: MockConfigEntry,
data_api_client_mock: AsyncMock,
setup_credentials: None,
entity_registry: er.EntityRegistry,
) -> None:
"""Ensure Data API sensors are created and expose values from the coordinator."""
data_api_client_mock.get_all_devices = AsyncMock(
return_value={"device-id": create_tibber_device(state_of_charge=72.0)}
)
data_api_client_mock.update_devices = AsyncMock(
return_value={"device-id": create_tibber_device(state_of_charge=83.0)}
)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
data_api_client_mock.get_all_devices.assert_awaited_once()
data_api_client_mock.update_devices.assert_awaited_once()
unique_id = "external-id_storage.stateOfCharge"
entity_id = entity_registry.async_get_entity_id("sensor", DOMAIN, unique_id)
assert entity_id is not None
state = hass.states.get(entity_id)
assert state is not None
assert float(state.state) == 83.0
@pytest.mark.parametrize(
("sensor_id", "expected_value", "description"),
[
("storage.ratedCapacity", 10000.0, "Storage rated capacity"),
("storage.ratedPower", 5000.0, "Storage rated power"),
("storage.availableEnergy", 7500.0, "Storage available energy"),
("powerFlow.battery.power", 2500.0, "Battery power flow"),
("powerFlow.grid.power", 1500.0, "Grid power flow"),
("powerFlow.load.power", 4000.0, "Load power flow"),
("powerFlow.toGrid", 25.5, "Power flow to grid percentage"),
("powerFlow.toLoad", 60.0, "Power flow to load percentage"),
("powerFlow.fromGrid", 15.0, "Power flow from grid percentage"),
("powerFlow.fromLoad", 10.0, "Power flow from load percentage"),
("energyFlow.hour.battery.charged", 2000.0, "Hourly battery charged"),
("energyFlow.hour.battery.discharged", 1500.0, "Hourly battery discharged"),
("energyFlow.hour.grid.imported", 1000.0, "Hourly grid imported"),
("energyFlow.hour.grid.exported", 800.0, "Hourly grid exported"),
("energyFlow.hour.load.consumed", 3000.0, "Hourly load consumed"),
("energyFlow.hour.load.generated", 200.0, "Hourly load generated"),
("energyFlow.month.battery.charged", 50000.0, "Monthly battery charged"),
("energyFlow.month.battery.discharged", 40000.0, "Monthly battery discharged"),
("energyFlow.month.grid.imported", 25000.0, "Monthly grid imported"),
("energyFlow.month.grid.exported", 20000.0, "Monthly grid exported"),
("energyFlow.month.load.consumed", 60000.0, "Monthly load consumed"),
("energyFlow.month.load.generated", 5000.0, "Monthly load generated"),
("range.remaining", 250.5, "Remaining range"),
("charging.current.max", 32.0, "Max charging current"),
("charging.current.offlineFallback", 16.0, "Offline fallback charging current"),
("temp.setpoint", 22.5, "Temperature setpoint"),
("temp.current", 21.0, "Current temperature"),
("temp.comfort", 20.5, "Comfort temperature"),
("grid.phaseCount", 3.0, "Grid phase count"),
],
)
async def test_new_data_api_sensor_values(
recorder_mock: Recorder,
hass: HomeAssistant,
config_entry: MockConfigEntry,
data_api_client_mock: AsyncMock,
setup_credentials: None,
entity_registry: er.EntityRegistry,
sensor_id: str,
expected_value: float,
description: str,
) -> None:
"""Test individual new Data API sensor values."""
device = create_tibber_device(sensor_values={sensor_id: expected_value})
data_api_client_mock.get_all_devices = AsyncMock(return_value={"device-id": device})
data_api_client_mock.update_devices = AsyncMock(return_value={"device-id": device})
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
unique_id = f"external-id_{sensor_id}"
entity_id = entity_registry.async_get_entity_id("sensor", DOMAIN, unique_id)
assert entity_id is not None, f"Entity not found for {description}"
state = hass.states.get(entity_id)
assert state is not None, f"State not found for {description}"
assert float(state.state) == expected_value, (
f"Expected {expected_value} for {description}, got {state.state}"
)
async def test_new_data_api_sensors_with_disabled_by_default(
recorder_mock: Recorder,
hass: HomeAssistant,
config_entry: MockConfigEntry,
data_api_client_mock: AsyncMock,
setup_credentials: None,
entity_registry: er.EntityRegistry,
) -> None:
"""Test that sensors with entity_registry_enabled_default=False are disabled by default."""
sensor_values = {
"cellular.rssi": -75.0,
"energyFlow.hour.battery.source.grid": 500.0,
"energyFlow.hour.battery.source.load": 300.0,
"energyFlow.hour.load.source.battery": 700.0,
"energyFlow.hour.load.source.grid": 500.0,
"energyFlow.month.battery.source.grid": 10000.0,
"energyFlow.month.battery.source.battery": 5000.0,
"energyFlow.month.battery.source.load": 8000.0,
"energyFlow.month.grid.source.battery": 3000.0,
"energyFlow.month.grid.source.grid": 1000.0,
"energyFlow.month.grid.source.load": 2000.0,
"energyFlow.month.load.source.battery": 15000.0,
"energyFlow.month.load.source.grid": 10000.0,
}
device = create_tibber_device(sensor_values=sensor_values)
data_api_client_mock.get_all_devices = AsyncMock(return_value={"device-id": device})
data_api_client_mock.update_devices = AsyncMock(return_value={"device-id": device})
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
disabled_sensors = [
"cellular.rssi",
"energyFlow.hour.battery.source.grid",
"energyFlow.hour.battery.source.load",
"energyFlow.hour.load.source.battery",
"energyFlow.hour.load.source.grid",
"energyFlow.month.battery.source.grid",
"energyFlow.month.battery.source.battery",
"energyFlow.month.battery.source.load",
"energyFlow.month.grid.source.battery",
"energyFlow.month.grid.source.grid",
"energyFlow.month.grid.source.load",
"energyFlow.month.load.source.battery",
"energyFlow.month.load.source.grid",
]
for sensor_id in disabled_sensors:
unique_id = f"external-id_{sensor_id}"
entity_id = entity_registry.async_get_entity_id("sensor", DOMAIN, unique_id)
assert entity_id is not None, f"Entity not found for sensor {sensor_id}"
entity_entry = entity_registry.async_get(entity_id)
assert entity_entry is not None
assert entity_entry.disabled, (
f"Sensor {sensor_id} should be disabled by default"
)