This commit is contained in:
Victor Alexandrovich Tsyrenschikov
2026-03-30 20:25:42 +05:00
parent 139f9f1bd2
commit 373ed28445
2449 changed files with 53602 additions and 0 deletions

View 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