Fix Shelly Air lamp life sensor (#140799)

This commit is contained in:
Shay Levy 2025-03-17 17:33:11 +02:00 committed by GitHub
parent 18bd8b561a
commit 9b57a831f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 41 additions and 2 deletions

View File

@ -39,7 +39,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.entity_registry import RegistryEntry
from homeassistant.helpers.typing import StateType
from .const import CONF_SLEEP_PERIOD, ROLE_TO_DEVICE_CLASS_MAP, SHAIR_MAX_WORK_HOURS
from .const import CONF_SLEEP_PERIOD, ROLE_TO_DEVICE_CLASS_MAP
from .coordinator import ShellyBlockCoordinator, ShellyConfigEntry, ShellyRpcCoordinator
from .entity import (
BlockEntityDescription,
@ -58,6 +58,7 @@ from .utils import (
async_remove_orphaned_entities,
get_device_entry_gen,
get_device_uptime,
get_shelly_air_lamp_life,
get_virtual_component_ids,
is_rpc_wifi_stations_disabled,
)
@ -355,7 +356,7 @@ SENSORS: dict[tuple[str, str], BlockSensorDescription] = {
name="Lamp life",
native_unit_of_measurement=PERCENTAGE,
translation_key="lamp_life",
value=lambda value: 100 - (value / 3600 / SHAIR_MAX_WORK_HOURS),
value=get_shelly_air_lamp_life,
suggested_display_precision=1,
extra_state_attributes=lambda block: {
"Operational hours": round(cast(int, block.totalWorkTime) / 3600, 1)

View File

@ -59,6 +59,7 @@ from .const import (
GEN2_RELEASE_URL,
LOGGER,
RPC_INPUTS_EVENTS_TYPES,
SHAIR_MAX_WORK_HOURS,
SHBTN_INPUTS_EVENTS_TYPES,
SHBTN_MODELS,
SHELLY_EMIT_EVENT_PATTERN,
@ -655,3 +656,11 @@ def is_rpc_exclude_from_relay(
return True
return is_rpc_channel_type_light(settings, ch)
def get_shelly_air_lamp_life(lamp_seconds: int) -> float:
"""Return Shelly Air lamp life in percentage."""
lamp_hours = lamp_seconds / 3600
if lamp_hours >= SHAIR_MAX_WORK_HOURS:
return 0.0
return 100 * (1 - lamp_hours / SHAIR_MAX_WORK_HOURS)

View File

@ -102,12 +102,14 @@ MOCK_BLOCKS = [
"power": 53.4,
"energy": 1234567.89,
"output": True,
"totalWorkTime": 3600,
},
channel="0",
type="relay",
overpower=0,
power=53.4,
energy=1234567.89,
totalWorkTime=3600,
description="relay_0",
set_state=AsyncMock(side_effect=lambda turn: {"ison": turn == "on"}),
),

View File

@ -374,6 +374,33 @@ async def test_block_sensor_unknown_value(
assert hass.states.get(entity_id).state == STATE_UNKNOWN
@pytest.mark.parametrize(
("lamp_life_seconds", "percentage"),
[
(0 * 3600, "100.0"), # 0 hours, 100% remaining
(16 * 3600, "99.8222222222222"),
(4500 * 3600, "50.0"), # 4500 hours, 50% remaining
(9000 * 3600, "0.0"), # 9000 hours, 0% remaining
(10000 * 3600, "0.0"), # > 9000 hours, 0% remaining
],
)
async def test_block_shelly_air_lamp_life(
hass: HomeAssistant,
mock_block_device: Mock,
monkeypatch: pytest.MonkeyPatch,
lamp_life_seconds: int,
percentage: float,
) -> None:
"""Test block Shelly Air lamp life percentage sensor."""
entity_id = f"{SENSOR_DOMAIN}.{'test_name_channel_1_lamp_life'}"
monkeypatch.setattr(
mock_block_device.blocks[RELAY_BLOCK_ID], "totalWorkTime", lamp_life_seconds
)
await init_integration(hass, 1)
assert hass.states.get(entity_id).state == percentage
async def test_rpc_sensor(
hass: HomeAssistant, mock_rpc_device: Mock, monkeypatch: pytest.MonkeyPatch
) -> None: