Use device supplied ranges in LaMetric (#135590)

This commit is contained in:
Joost Lekkerkerker 2025-01-14 14:02:17 +01:00 committed by Franck Nijhof
parent c6cde13615
commit 0bd03346e8
No known key found for this signature in database
GPG Key ID: D62583BA8AB11CA3
3 changed files with 100 additions and 6 deletions

View File

@ -6,7 +6,7 @@ from collections.abc import Awaitable, Callable
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any from typing import Any
from demetriek import Device, LaMetricDevice from demetriek import Device, LaMetricDevice, Range
from homeassistant.components.number import NumberEntity, NumberEntityDescription from homeassistant.components.number import NumberEntity, NumberEntityDescription
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
@ -25,6 +25,7 @@ class LaMetricNumberEntityDescription(NumberEntityDescription):
"""Class describing LaMetric number entities.""" """Class describing LaMetric number entities."""
value_fn: Callable[[Device], int | None] value_fn: Callable[[Device], int | None]
range_fn: Callable[[Device], Range | None]
has_fn: Callable[[Device], bool] = lambda device: True has_fn: Callable[[Device], bool] = lambda device: True
set_value_fn: Callable[[LaMetricDevice, float], Awaitable[Any]] set_value_fn: Callable[[LaMetricDevice, float], Awaitable[Any]]
@ -35,8 +36,7 @@ NUMBERS = [
translation_key="brightness", translation_key="brightness",
entity_category=EntityCategory.CONFIG, entity_category=EntityCategory.CONFIG,
native_step=1, native_step=1,
native_min_value=0, range_fn=lambda device: device.display.brightness_limit,
native_max_value=100,
native_unit_of_measurement=PERCENTAGE, native_unit_of_measurement=PERCENTAGE,
value_fn=lambda device: device.display.brightness, value_fn=lambda device: device.display.brightness,
set_value_fn=lambda device, bri: device.display(brightness=int(bri)), set_value_fn=lambda device, bri: device.display(brightness=int(bri)),
@ -46,8 +46,7 @@ NUMBERS = [
translation_key="volume", translation_key="volume",
entity_category=EntityCategory.CONFIG, entity_category=EntityCategory.CONFIG,
native_step=1, native_step=1,
native_min_value=0, range_fn=lambda device: device.audio.volume_range if device.audio else None,
native_max_value=100,
native_unit_of_measurement=PERCENTAGE, native_unit_of_measurement=PERCENTAGE,
has_fn=lambda device: bool(device.audio and device.audio.available), has_fn=lambda device: bool(device.audio and device.audio.available),
value_fn=lambda device: device.audio.volume if device.audio else 0, value_fn=lambda device: device.audio.volume if device.audio else 0,
@ -92,6 +91,20 @@ class LaMetricNumberEntity(LaMetricEntity, NumberEntity):
"""Return the number value.""" """Return the number value."""
return self.entity_description.value_fn(self.coordinator.data) return self.entity_description.value_fn(self.coordinator.data)
@property
def native_min_value(self) -> int:
"""Return the min range."""
if limits := self.entity_description.range_fn(self.coordinator.data):
return limits.range_min
return 0
@property
def native_max_value(self) -> int:
"""Return the max range."""
if limits := self.entity_description.range_fn(self.coordinator.data):
return limits.range_max
return 100
@lametric_exception_handler @lametric_exception_handler
async def async_set_native_value(self, value: float) -> None: async def async_set_native_value(self, value: float) -> None:
"""Change to new number value.""" """Change to new number value."""

View File

@ -0,0 +1,68 @@
{
"audio": {
"available": true,
"volume": 53,
"volume_limit": {
"max": 100,
"min": 0
},
"volume_range": {
"max": 100,
"min": 0
}
},
"bluetooth": {
"active": false,
"address": "40:F4:C9:AA:AA:AA",
"available": true,
"discoverable": true,
"mac": "40:F4:C9:AA:AA:AA",
"name": "LM8367",
"pairable": false
},
"display": {
"brightness": 75,
"brightness_limit": {
"max": 76,
"min": 2
},
"brightness_mode": "manual",
"brightness_range": {
"max": 100,
"min": 0
},
"height": 8,
"on": true,
"screensaver": {
"enabled": true,
"modes": {
"time_based": {
"enabled": false
},
"when_dark": {
"enabled": true
}
},
"widget": "1_com.lametric.clock"
},
"type": "mixed",
"width": 37
},
"id": "67790",
"mode": "manual",
"model": "sa8",
"name": "TIME",
"os_version": "3.1.3",
"serial_number": "SA840700836700W00BAA",
"wifi": {
"active": true,
"mac": "40:F4:C9:AA:AA:AA",
"available": true,
"encryption": "WPA",
"ssid": "My wifi",
"ip": "10.0.0.99",
"mode": "dhcp",
"netmask": "255.255.255.0",
"rssi": 78
}
}

View File

@ -42,7 +42,7 @@ async def test_brightness(
assert state.attributes.get(ATTR_DEVICE_CLASS) is None assert state.attributes.get(ATTR_DEVICE_CLASS) is None
assert state.attributes.get(ATTR_FRIENDLY_NAME) == "Frenck's LaMetric Brightness" assert state.attributes.get(ATTR_FRIENDLY_NAME) == "Frenck's LaMetric Brightness"
assert state.attributes.get(ATTR_MAX) == 100 assert state.attributes.get(ATTR_MAX) == 100
assert state.attributes.get(ATTR_MIN) == 0 assert state.attributes.get(ATTR_MIN) == 2
assert state.attributes.get(ATTR_STEP) == 1 assert state.attributes.get(ATTR_STEP) == 1
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE
assert state.state == "100" assert state.state == "100"
@ -183,3 +183,16 @@ async def test_number_connection_error(
state = hass.states.get("number.frenck_s_lametric_volume") state = hass.states.get("number.frenck_s_lametric_volume")
assert state assert state
assert state.state == STATE_UNAVAILABLE assert state.state == STATE_UNAVAILABLE
@pytest.mark.parametrize("device_fixture", ["computer_powered"])
async def test_computer_powered_devices(
hass: HomeAssistant,
mock_lametric: MagicMock,
) -> None:
"""Test Brightness is properly limited for computer powered devices."""
state = hass.states.get("number.time_brightness")
assert state
assert state.state == "75"
assert state.attributes[ATTR_MIN] == 2
assert state.attributes[ATTR_MAX] == 76