python
This commit is contained in:
106
custom_components/yandex_smart_home/schema/capability_range.py
Normal file
106
custom_components/yandex_smart_home/schema/capability_range.py
Normal file
@@ -0,0 +1,106 @@
|
||||
"""Schema for range capability.
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/range.html
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import StrEnum
|
||||
from typing import Any, Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator, computed_field
|
||||
|
||||
from .base import APIModel
|
||||
|
||||
|
||||
class RangeCapabilityUnit(StrEnum):
|
||||
"""Unit used in a range capability."""
|
||||
|
||||
PERCENT = "unit.percent"
|
||||
TEMPERATURE_CELSIUS = "unit.temperature.celsius"
|
||||
|
||||
|
||||
class RangeCapabilityInstance(StrEnum):
|
||||
"""Instance of a range capability.
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/range-instance.html
|
||||
"""
|
||||
|
||||
BRIGHTNESS = "brightness"
|
||||
CHANNEL = "channel"
|
||||
HUMIDITY = "humidity"
|
||||
OPEN = "open"
|
||||
TEMPERATURE = "temperature"
|
||||
VOLUME = "volume"
|
||||
|
||||
|
||||
class RangeCapabilityRange(APIModel):
|
||||
"""Value range of a range capability."""
|
||||
|
||||
min: float
|
||||
max: float
|
||||
precision: float
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"[{self.min}, {self.max}]"
|
||||
|
||||
|
||||
class RangeCapabilityParameters(APIModel):
|
||||
"""Parameters of a range capability."""
|
||||
|
||||
instance: RangeCapabilityInstance
|
||||
unit: Optional[RangeCapabilityUnit] = Field(default=None, exclude=True) # исключаем из сериализации, если нужно
|
||||
random_access: bool
|
||||
range: Optional[RangeCapabilityRange] = Field(default=None)
|
||||
|
||||
@computed_field
|
||||
@property
|
||||
def computed_unit(self) -> RangeCapabilityUnit:
|
||||
"""Вычисляемый unit на основе instance."""
|
||||
match self.instance:
|
||||
case RangeCapabilityInstance.BRIGHTNESS:
|
||||
return RangeCapabilityUnit.PERCENT
|
||||
case RangeCapabilityInstance.HUMIDITY:
|
||||
return RangeCapabilityUnit.PERCENT
|
||||
case RangeCapabilityInstance.OPEN:
|
||||
return RangeCapabilityUnit.PERCENT
|
||||
case RangeCapabilityInstance.TEMPERATURE:
|
||||
return RangeCapabilityUnit.TEMPERATURE_CELSIUS
|
||||
case _:
|
||||
return self.unit or RangeCapabilityUnit.PERCENT # fallback
|
||||
|
||||
@model_validator(mode='after')
|
||||
def validate_range(self) -> Self:
|
||||
"""Force range boundaries for a capability instance."""
|
||||
r = self.range
|
||||
if r:
|
||||
match self.instance:
|
||||
case RangeCapabilityInstance.HUMIDITY | RangeCapabilityInstance.OPEN:
|
||||
r.min = max(0.0, r.min)
|
||||
r.max = min(100.0, r.max)
|
||||
case RangeCapabilityInstance.BRIGHTNESS:
|
||||
r.min = max(0.0, min(1.0, r.min))
|
||||
r.max = 100.0
|
||||
r.precision = 1.0
|
||||
else:
|
||||
if self.instance in (
|
||||
RangeCapabilityInstance.BRIGHTNESS,
|
||||
RangeCapabilityInstance.HUMIDITY,
|
||||
RangeCapabilityInstance.OPEN,
|
||||
RangeCapabilityInstance.TEMPERATURE,
|
||||
):
|
||||
raise ValueError(f"range field required for {self.instance}")
|
||||
|
||||
return self
|
||||
|
||||
|
||||
class RangeCapabilityInstanceActionState(APIModel):
|
||||
"""New value for a range capability."""
|
||||
|
||||
instance: RangeCapabilityInstance
|
||||
value: float
|
||||
relative: bool = False
|
||||
|
||||
@field_validator("relative", mode="before")
|
||||
@classmethod
|
||||
def set_relative(cls, v: Any) -> bool:
|
||||
"""Update relative value."""
|
||||
return False if v is None else v
|
||||
Reference in New Issue
Block a user