Initialize docker stack repo
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
"""Yandex Smart Home API schemas."""
|
||||
|
||||
# ruff: noqa
|
||||
from .callback import *
|
||||
from .capability import *
|
||||
from .capability_color import *
|
||||
from .capability_mode import *
|
||||
from .capability_onoff import *
|
||||
from .capability_range import *
|
||||
from .capability_toggle import *
|
||||
from .capability_video import *
|
||||
from .device import *
|
||||
from .property import *
|
||||
from .property_event import *
|
||||
from .property_float import *
|
||||
from .response import *
|
||||
@@ -0,0 +1,22 @@
|
||||
"""Base class for API response schemas."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
from pydantic.v1 import BaseModel
|
||||
from pydantic.v1.generics import GenericModel
|
||||
|
||||
|
||||
class APIModel(BaseModel):
|
||||
"""Base API response model."""
|
||||
|
||||
def as_json(self) -> str:
|
||||
"""Generate a JSON representation of the model."""
|
||||
return super().json(exclude_none=True, ensure_ascii=False)
|
||||
|
||||
def as_dict(self) -> dict[str, Any]:
|
||||
"""Generate a dictionary representation of the model."""
|
||||
return super().dict(exclude_none=True)
|
||||
|
||||
|
||||
class GenericAPIModel(GenericModel, APIModel):
|
||||
"""Base generic API response model."""
|
||||
@@ -0,0 +1,57 @@
|
||||
"""Schema for event notification service.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/reference-alerts/resources-alerts.html
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
import time
|
||||
|
||||
from pydantic.v1 import Field
|
||||
|
||||
from .base import APIModel
|
||||
from .device import DeviceState
|
||||
|
||||
|
||||
class CallbackStatesRequestPayload(APIModel):
|
||||
"""Payload of request body for notification about device state change."""
|
||||
|
||||
user_id: str
|
||||
devices: list[DeviceState]
|
||||
|
||||
|
||||
class CallbackStatesRequest(APIModel):
|
||||
"""Request body for notification about device state change."""
|
||||
|
||||
ts: float = Field(default_factory=lambda: time.time())
|
||||
payload: CallbackStatesRequestPayload
|
||||
|
||||
|
||||
class CallbackDiscoveryRequestPayload(APIModel):
|
||||
"""Payload of request body for notification about change of devices' parameters."""
|
||||
|
||||
user_id: str
|
||||
|
||||
|
||||
class CallbackDiscoveryRequest(APIModel):
|
||||
"""Request body for notification about change of devices' parameters."""
|
||||
|
||||
ts: float = Field(default_factory=lambda: time.time())
|
||||
payload: CallbackDiscoveryRequestPayload
|
||||
|
||||
|
||||
class CallbackResponseStatus(StrEnum):
|
||||
"""Status of a callback request."""
|
||||
|
||||
OK = "ok"
|
||||
ERROR = "error"
|
||||
|
||||
|
||||
class CallbackResponse(APIModel):
|
||||
"""Response on a callback request."""
|
||||
|
||||
status: CallbackResponseStatus
|
||||
error_code: str | None
|
||||
error_message: str | None
|
||||
|
||||
|
||||
CallbackRequest = CallbackDiscoveryRequest | CallbackStatesRequest
|
||||
@@ -0,0 +1,160 @@
|
||||
"""Schema for device capabilities."""
|
||||
|
||||
from enum import StrEnum
|
||||
from typing import Annotated, Any, Literal, TypeVar, Union
|
||||
|
||||
from pydantic.v1 import Field
|
||||
|
||||
from .base import APIModel
|
||||
from .capability_color import (
|
||||
ColorSettingCapabilityInstance,
|
||||
ColorSettingCapabilityInstanceActionState,
|
||||
ColorSettingCapabilityParameters,
|
||||
RGBInstanceActionState,
|
||||
SceneInstanceActionState,
|
||||
TemperatureKInstanceActionState,
|
||||
)
|
||||
from .capability_mode import ModeCapabilityInstance, ModeCapabilityInstanceActionState, ModeCapabilityParameters
|
||||
from .capability_onoff import OnOffCapabilityInstance, OnOffCapabilityInstanceActionState, OnOffCapabilityParameters
|
||||
from .capability_range import RangeCapabilityInstance, RangeCapabilityInstanceActionState, RangeCapabilityParameters
|
||||
from .capability_toggle import ToggleCapabilityInstance, ToggleCapabilityInstanceActionState, ToggleCapabilityParameters
|
||||
from .capability_video import (
|
||||
GetStreamInstanceActionResultValue,
|
||||
GetStreamInstanceActionState,
|
||||
VideoStreamCapabilityInstance,
|
||||
VideoStreamCapabilityParameters,
|
||||
)
|
||||
|
||||
|
||||
class CapabilityType(StrEnum):
|
||||
"""Capability type."""
|
||||
|
||||
ON_OFF = "devices.capabilities.on_off"
|
||||
COLOR_SETTING = "devices.capabilities.color_setting"
|
||||
MODE = "devices.capabilities.mode"
|
||||
RANGE = "devices.capabilities.range"
|
||||
TOGGLE = "devices.capabilities.toggle"
|
||||
VIDEO_STREAM = "devices.capabilities.video_stream"
|
||||
|
||||
@property
|
||||
def short(self) -> str:
|
||||
"""Return short version of the capability type."""
|
||||
return str(self).replace("devices.capabilities.", "")
|
||||
|
||||
|
||||
CapabilityParameters = (
|
||||
OnOffCapabilityParameters
|
||||
| ColorSettingCapabilityParameters
|
||||
| ModeCapabilityParameters
|
||||
| RangeCapabilityParameters
|
||||
| ToggleCapabilityParameters
|
||||
| VideoStreamCapabilityParameters
|
||||
)
|
||||
"""Parameters of a capability for a device list request."""
|
||||
|
||||
CapabilityInstance = (
|
||||
OnOffCapabilityInstance
|
||||
| ColorSettingCapabilityInstance
|
||||
| ModeCapabilityInstance
|
||||
| RangeCapabilityInstance
|
||||
| ToggleCapabilityInstance
|
||||
| VideoStreamCapabilityInstance
|
||||
)
|
||||
"""All capability instances."""
|
||||
|
||||
|
||||
class CapabilityDescription(APIModel):
|
||||
"""Description of a capability for a device list request."""
|
||||
|
||||
type: CapabilityType
|
||||
retrievable: bool
|
||||
reportable: bool
|
||||
parameters: CapabilityParameters | None
|
||||
|
||||
|
||||
class CapabilityInstanceStateValue(APIModel):
|
||||
"""Capability instance value."""
|
||||
|
||||
instance: CapabilityInstance
|
||||
value: Any
|
||||
|
||||
|
||||
class CapabilityInstanceState(APIModel):
|
||||
"""Capability state for state query and callback requests."""
|
||||
|
||||
type: CapabilityType
|
||||
state: CapabilityInstanceStateValue
|
||||
|
||||
|
||||
class OnOffCapabilityInstanceAction(APIModel):
|
||||
"""New capability state for a state change request of on_off capability."""
|
||||
|
||||
type: Literal[CapabilityType.ON_OFF] = CapabilityType.ON_OFF
|
||||
state: OnOffCapabilityInstanceActionState
|
||||
|
||||
|
||||
class ColorSettingCapabilityInstanceAction(APIModel):
|
||||
"""New capability state for a state change request of color_setting capability."""
|
||||
|
||||
type: Literal[CapabilityType.COLOR_SETTING] = CapabilityType.COLOR_SETTING
|
||||
state: ColorSettingCapabilityInstanceActionState
|
||||
|
||||
|
||||
class ModeCapabilityInstanceAction(APIModel):
|
||||
"""New capability state for a state change request of mode capability."""
|
||||
|
||||
type: Literal[CapabilityType.MODE] = CapabilityType.MODE
|
||||
state: ModeCapabilityInstanceActionState
|
||||
|
||||
|
||||
class RangeCapabilityInstanceAction(APIModel):
|
||||
"""New capability state for a state change request of range capability."""
|
||||
|
||||
type: Literal[CapabilityType.RANGE] = CapabilityType.RANGE
|
||||
state: RangeCapabilityInstanceActionState
|
||||
|
||||
|
||||
class ToggleCapabilityInstanceAction(APIModel):
|
||||
"""New capability state for a state change request of toggle capability."""
|
||||
|
||||
type: Literal[CapabilityType.TOGGLE] = CapabilityType.TOGGLE
|
||||
state: ToggleCapabilityInstanceActionState
|
||||
|
||||
|
||||
class VideoStreamCapabilityInstanceAction(APIModel):
|
||||
"""New capability state for a state change request of video_stream capability."""
|
||||
|
||||
type: Literal[CapabilityType.VIDEO_STREAM] = CapabilityType.VIDEO_STREAM
|
||||
state: GetStreamInstanceActionState
|
||||
|
||||
|
||||
CapabilityInstanceAction = Annotated[
|
||||
Union[
|
||||
OnOffCapabilityInstanceAction,
|
||||
ColorSettingCapabilityInstanceAction,
|
||||
ModeCapabilityInstanceAction,
|
||||
RangeCapabilityInstanceAction,
|
||||
ToggleCapabilityInstanceAction,
|
||||
VideoStreamCapabilityInstanceAction,
|
||||
],
|
||||
Field(discriminator="type"),
|
||||
]
|
||||
"""New capability state including type for a state change request."""
|
||||
|
||||
CapabilityInstanceActionState = TypeVar(
|
||||
"CapabilityInstanceActionState",
|
||||
OnOffCapabilityInstanceActionState,
|
||||
ColorSettingCapabilityInstanceActionState,
|
||||
RGBInstanceActionState,
|
||||
TemperatureKInstanceActionState,
|
||||
SceneInstanceActionState,
|
||||
ModeCapabilityInstanceActionState,
|
||||
RangeCapabilityInstanceActionState,
|
||||
ToggleCapabilityInstanceActionState,
|
||||
GetStreamInstanceActionState,
|
||||
contravariant=True,
|
||||
)
|
||||
"""New capability state for a state change request."""
|
||||
|
||||
CapabilityInstanceActionResultValue = GetStreamInstanceActionResultValue | None
|
||||
"""Result of a capability state change."""
|
||||
@@ -0,0 +1,111 @@
|
||||
"""Schema for color_setting capability.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/color_setting.html
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
from typing import Annotated, Any, Literal, Self, Union
|
||||
|
||||
from pydantic.v1 import Field, root_validator
|
||||
|
||||
from .base import APIModel
|
||||
|
||||
|
||||
class ColorSettingCapabilityInstance(StrEnum):
|
||||
"""Instance of a color_setting capability."""
|
||||
|
||||
BASE = "base"
|
||||
RGB = "rgb"
|
||||
HSV = "hsv"
|
||||
TEMPERATURE_K = "temperature_k"
|
||||
SCENE = "scene"
|
||||
|
||||
|
||||
class ColorScene(StrEnum):
|
||||
"""Color scene."""
|
||||
|
||||
ALARM = "alarm"
|
||||
ALICE = "alice"
|
||||
CANDLE = "candle"
|
||||
DINNER = "dinner"
|
||||
FANTASY = "fantasy"
|
||||
GARLAND = "garland"
|
||||
JUNGLE = "jungle"
|
||||
MOVIE = "movie"
|
||||
NEON = "neon"
|
||||
NIGHT = "night"
|
||||
OCEAN = "ocean"
|
||||
PARTY = "party"
|
||||
READING = "reading"
|
||||
REST = "rest"
|
||||
ROMANCE = "romance"
|
||||
SIREN = "siren"
|
||||
SUNRISE = "sunrise"
|
||||
SUNSET = "sunset"
|
||||
|
||||
|
||||
class CapabilityParameterColorModel(StrEnum):
|
||||
"""Color model."""
|
||||
|
||||
RGB = "rgb"
|
||||
HSV = "hsv"
|
||||
|
||||
|
||||
class CapabilityParameterTemperatureK(APIModel):
|
||||
"""Color temperature range."""
|
||||
|
||||
min: int
|
||||
max: int
|
||||
|
||||
|
||||
class CapabilityParameterColorScene(APIModel):
|
||||
"""Parameter of a scene instance."""
|
||||
|
||||
scenes: list[dict[Literal["id"], ColorScene]]
|
||||
|
||||
@classmethod
|
||||
def from_list(cls, scenes: list[ColorScene]) -> Self:
|
||||
return cls(scenes=[{"id": s} for s in scenes])
|
||||
|
||||
|
||||
class ColorSettingCapabilityParameters(APIModel):
|
||||
"""Parameters of a color_setting capability."""
|
||||
|
||||
color_model: CapabilityParameterColorModel | None = None
|
||||
temperature_k: CapabilityParameterTemperatureK | None = None
|
||||
color_scene: CapabilityParameterColorScene | None = None
|
||||
|
||||
@root_validator
|
||||
def any_of(cls, values: dict[str, Any]) -> dict[str, Any]:
|
||||
if not any(values.values()):
|
||||
raise ValueError("one of color_model, temperature_k or color_scene must have a value")
|
||||
|
||||
return values
|
||||
|
||||
|
||||
class RGBInstanceActionState(APIModel):
|
||||
"""New value for a rgb instance."""
|
||||
|
||||
instance: Literal[ColorSettingCapabilityInstance.RGB] = ColorSettingCapabilityInstance.RGB
|
||||
value: int
|
||||
|
||||
|
||||
class TemperatureKInstanceActionState(APIModel):
|
||||
"""New value for a temperature_k instance."""
|
||||
|
||||
instance: Literal[ColorSettingCapabilityInstance.TEMPERATURE_K] = ColorSettingCapabilityInstance.TEMPERATURE_K
|
||||
value: int
|
||||
|
||||
|
||||
class SceneInstanceActionState(APIModel):
|
||||
"""New value for a scene instance."""
|
||||
|
||||
instance: Literal[ColorSettingCapabilityInstance.SCENE] = ColorSettingCapabilityInstance.SCENE
|
||||
value: ColorScene
|
||||
|
||||
|
||||
ColorSettingCapabilityInstanceActionState = Annotated[
|
||||
Union[RGBInstanceActionState, TemperatureKInstanceActionState, SceneInstanceActionState],
|
||||
Field(discriminator="instance"),
|
||||
]
|
||||
"""New value for an instance of color_setting capability."""
|
||||
@@ -0,0 +1,133 @@
|
||||
"""Schema for mode capability.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/mode.html
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
from typing import Literal, Self
|
||||
|
||||
from .base import APIModel
|
||||
|
||||
|
||||
class ModeCapabilityInstance(StrEnum):
|
||||
"""Instance of a mode capability.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/mode-instance.html
|
||||
"""
|
||||
|
||||
CLEANUP_MODE = "cleanup_mode"
|
||||
COFFEE_MODE = "coffee_mode"
|
||||
DISHWASHING = "dishwashing"
|
||||
FAN_SPEED = "fan_speed"
|
||||
HEAT = "heat"
|
||||
INPUT_SOURCE = "input_source"
|
||||
PROGRAM = "program"
|
||||
SWING = "swing"
|
||||
TEA_MODE = "tea_mode"
|
||||
THERMOSTAT = "thermostat"
|
||||
VENTILATION_MODE = "ventilation_mode"
|
||||
WORK_SPEED = "work_speed"
|
||||
|
||||
|
||||
class ModeCapabilityMode(StrEnum):
|
||||
"""Mode value of a mode capability.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/mode-instance-modes.html
|
||||
"""
|
||||
|
||||
WET_CLEANING = "wet_cleaning"
|
||||
DRY_CLEANING = "dry_cleaning"
|
||||
MIXED_CLEANING = "mixed_cleaning"
|
||||
AUTO = "auto"
|
||||
ECO = "eco"
|
||||
SMART = "smart"
|
||||
TURBO = "turbo"
|
||||
COOL = "cool"
|
||||
DRY = "dry"
|
||||
FAN_ONLY = "fan_only"
|
||||
HEAT = "heat"
|
||||
PREHEAT = "preheat"
|
||||
HIGH = "high"
|
||||
LOW = "low"
|
||||
MEDIUM = "medium"
|
||||
MAX = "max"
|
||||
MIN = "min"
|
||||
FAST = "fast"
|
||||
SLOW = "slow"
|
||||
EXPRESS = "express"
|
||||
NORMAL = "normal"
|
||||
QUIET = "quiet"
|
||||
HORIZONTAL = "horizontal"
|
||||
STATIONARY = "stationary"
|
||||
VERTICAL = "vertical"
|
||||
SUPPLY_AIR = "supply_air"
|
||||
EXTRACTION_AIR = "extraction_air"
|
||||
ONE = "one"
|
||||
TWO = "two"
|
||||
THREE = "three"
|
||||
FOUR = "four"
|
||||
FIVE = "five"
|
||||
SIX = "six"
|
||||
SEVEN = "seven"
|
||||
EIGHT = "eight"
|
||||
NINE = "nine"
|
||||
TEN = "ten"
|
||||
AMERICANO = "americano"
|
||||
CAPPUCCINO = "cappuccino"
|
||||
DOUBLE = "double"
|
||||
ESPRESSO = "espresso"
|
||||
DOUBLE_ESPRESSO = "double_espresso"
|
||||
LATTE = "latte"
|
||||
BLACK_TEA = "black_tea"
|
||||
FLOWER_TEA = "flower_tea"
|
||||
GREEN_TEA = "green_tea"
|
||||
HERBAL_TEA = "herbal_tea"
|
||||
OOLONG_TEA = "oolong_tea"
|
||||
PUERH_TEA = "puerh_tea"
|
||||
RED_TEA = "red_tea"
|
||||
WHITE_TEA = "white_tea"
|
||||
GLASS = "glass"
|
||||
INTENSIVE = "intensive"
|
||||
PRE_RINSE = "pre_rinse"
|
||||
ASPIC = "aspic"
|
||||
BABY_FOOD = "baby_food"
|
||||
BAKING = "baking"
|
||||
BREAD = "bread"
|
||||
BOILING = "boiling"
|
||||
CEREALS = "cereals"
|
||||
CHEESECAKE = "cheesecake"
|
||||
DEEP_FRYER = "deep_fryer"
|
||||
DESSERT = "dessert"
|
||||
FOWL = "fowl"
|
||||
FRYING = "frying"
|
||||
MACARONI = "macaroni"
|
||||
MILK_PORRIDGE = "milk_porridge"
|
||||
MULTICOOKER = "multicooker"
|
||||
PASTA = "pasta"
|
||||
PILAF = "pilaf"
|
||||
PIZZA = "pizza"
|
||||
SAUCE = "sauce"
|
||||
SLOW_COOK = "slow_cook"
|
||||
SOUP = "soup"
|
||||
STEAM = "steam"
|
||||
STEWING = "stewing"
|
||||
VACUUM = "vacuum"
|
||||
YOGURT = "yogurt"
|
||||
|
||||
|
||||
class ModeCapabilityParameters(APIModel):
|
||||
"""Parameters of a mode capability."""
|
||||
|
||||
instance: ModeCapabilityInstance
|
||||
modes: list[dict[Literal["value"], ModeCapabilityMode]]
|
||||
|
||||
@classmethod
|
||||
def from_list(cls, instance: ModeCapabilityInstance, modes: list[ModeCapabilityMode]) -> Self:
|
||||
return cls(instance=instance, modes=[{"value": m} for m in modes])
|
||||
|
||||
|
||||
class ModeCapabilityInstanceActionState(APIModel):
|
||||
"""New value for a mode capability."""
|
||||
|
||||
instance: ModeCapabilityInstance
|
||||
value: ModeCapabilityMode
|
||||
@@ -0,0 +1,27 @@
|
||||
"""Schema for on_off capability.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/on_off.html
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
|
||||
from .base import APIModel
|
||||
|
||||
|
||||
class OnOffCapabilityInstance(StrEnum):
|
||||
"""Instance of an on_off capability."""
|
||||
|
||||
ON = "on"
|
||||
|
||||
|
||||
class OnOffCapabilityParameters(APIModel):
|
||||
"""Parameters of a on_off capability."""
|
||||
|
||||
split: bool
|
||||
|
||||
|
||||
class OnOffCapabilityInstanceActionState(APIModel):
|
||||
"""New value for an on_off capability."""
|
||||
|
||||
instance: OnOffCapabilityInstance
|
||||
value: bool
|
||||
@@ -0,0 +1,99 @@
|
||||
"""Schema for range capability.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/range.html
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
from typing import Any
|
||||
|
||||
from pydantic.v1 import root_validator, validator
|
||||
|
||||
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: RangeCapabilityUnit | None = None
|
||||
random_access: bool
|
||||
range: RangeCapabilityRange | None = None
|
||||
|
||||
@root_validator
|
||||
def compute_unit(cls, values: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Return value unit for a capability instance."""
|
||||
match values.get("instance"):
|
||||
case RangeCapabilityInstance.BRIGHTNESS:
|
||||
values["unit"] = RangeCapabilityUnit.PERCENT
|
||||
case RangeCapabilityInstance.HUMIDITY:
|
||||
values["unit"] = RangeCapabilityUnit.PERCENT
|
||||
case RangeCapabilityInstance.OPEN:
|
||||
values["unit"] = RangeCapabilityUnit.PERCENT
|
||||
case RangeCapabilityInstance.TEMPERATURE:
|
||||
values["unit"] = RangeCapabilityUnit.TEMPERATURE_CELSIUS
|
||||
|
||||
return values
|
||||
|
||||
@root_validator
|
||||
def validate_range(cls, values: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Force range boundaries for a capability instance."""
|
||||
|
||||
r: RangeCapabilityRange | None
|
||||
if r := values.get("range"):
|
||||
match values.get("instance"):
|
||||
case RangeCapabilityInstance.HUMIDITY | RangeCapabilityInstance.OPEN:
|
||||
r.min, r.max = max([0.0, r.min]), min([100.0, r.max])
|
||||
case RangeCapabilityInstance.BRIGHTNESS:
|
||||
r.min = max(min(r.min, 1.0), 0.0)
|
||||
r.max = 100.0
|
||||
r.precision = 1.0
|
||||
|
||||
return values
|
||||
|
||||
|
||||
class RangeCapabilityInstanceActionState(APIModel):
|
||||
"""New value for a range capability."""
|
||||
|
||||
instance: RangeCapabilityInstance
|
||||
value: float
|
||||
relative: bool = False
|
||||
|
||||
@validator("relative", pre=True, always=True)
|
||||
def set_relative(cls, v: Any) -> Any:
|
||||
"""Update relative value."""
|
||||
if v is None: # VK
|
||||
return False
|
||||
|
||||
return v
|
||||
@@ -0,0 +1,36 @@
|
||||
"""Schema for toggle capability.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/toggle.html
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
|
||||
from .base import APIModel
|
||||
|
||||
|
||||
class ToggleCapabilityInstance(StrEnum):
|
||||
"""Instance of a toggle capability.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/toggle-instance.html
|
||||
"""
|
||||
|
||||
BACKLIGHT = "backlight"
|
||||
CONTROLS_LOCKED = "controls_locked"
|
||||
IONIZATION = "ionization"
|
||||
KEEP_WARM = "keep_warm"
|
||||
MUTE = "mute"
|
||||
OSCILLATION = "oscillation"
|
||||
PAUSE = "pause"
|
||||
|
||||
|
||||
class ToggleCapabilityParameters(APIModel):
|
||||
"""Parameters of a toggle capability."""
|
||||
|
||||
instance: ToggleCapabilityInstance
|
||||
|
||||
|
||||
class ToggleCapabilityInstanceActionState(APIModel):
|
||||
"""New value for a toggle capability."""
|
||||
|
||||
instance: ToggleCapabilityInstance
|
||||
value: bool
|
||||
@@ -0,0 +1,43 @@
|
||||
"""Schema for video_stream capability.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/video_stream.html
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
from typing import Literal
|
||||
|
||||
from .base import APIModel
|
||||
|
||||
StreamProtocols = list[Literal["hls"]]
|
||||
|
||||
|
||||
class VideoStreamCapabilityInstance(StrEnum):
|
||||
"""Instance of a video_stream capability."""
|
||||
|
||||
GET_STREAM = "get_stream"
|
||||
|
||||
|
||||
class VideoStreamCapabilityParameters(APIModel):
|
||||
"""Parameters of a video_stream capability."""
|
||||
|
||||
protocols: StreamProtocols
|
||||
|
||||
|
||||
class GetStreamInstanceActionStateValue(APIModel):
|
||||
"""New state value for a get_stream instance."""
|
||||
|
||||
protocols: StreamProtocols
|
||||
|
||||
|
||||
class GetStreamInstanceActionState(APIModel):
|
||||
"""New value for a get_stream instance."""
|
||||
|
||||
instance: Literal[VideoStreamCapabilityInstance.GET_STREAM]
|
||||
value: GetStreamInstanceActionStateValue
|
||||
|
||||
|
||||
class GetStreamInstanceActionResultValue(APIModel):
|
||||
"""New value after a get_stream instance state changed."""
|
||||
|
||||
stream_url: str
|
||||
protocol: Literal["hls"]
|
||||
@@ -0,0 +1,197 @@
|
||||
"""Schema for an user device.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/reference/get-devices.html
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/reference/post-devices-query.html
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/reference/post-action.html
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
from typing import Any, Literal
|
||||
|
||||
from .base import APIModel
|
||||
from .capability import (
|
||||
CapabilityDescription,
|
||||
CapabilityInstance,
|
||||
CapabilityInstanceAction,
|
||||
CapabilityInstanceActionResultValue,
|
||||
CapabilityInstanceState,
|
||||
CapabilityType,
|
||||
)
|
||||
from .property import PropertyDescription, PropertyInstanceState
|
||||
from .response import ResponseCode, ResponsePayload
|
||||
|
||||
|
||||
class DeviceType(StrEnum):
|
||||
"""User device type.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/device-types.html
|
||||
"""
|
||||
|
||||
LIGHT = "devices.types.light"
|
||||
LIGHT_STRIP = "devices.types.light.strip"
|
||||
LIGHT_CEILING = "devices.types.light.ceiling"
|
||||
LIGHT_LAMP = "devices.types.light.lamp"
|
||||
LIGHT_GARLAND = "devices.types.light.garland"
|
||||
SOCKET = "devices.types.socket"
|
||||
SWITCH = "devices.types.switch"
|
||||
SWITCH_RELAY = "devices.types.switch.relay"
|
||||
THERMOSTAT = "devices.types.thermostat"
|
||||
THERMOSTAT_AC = "devices.types.thermostat.ac"
|
||||
MEDIA_DEVICE = "devices.types.media_device"
|
||||
MEDIA_DEVICE_TV = "devices.types.media_device.tv"
|
||||
MEDIA_DEVICE_TV_BOX = "devices.types.media_device.tv_box"
|
||||
MEDIA_DEVICE_RECIEVER = "devices.types.media_device.receiver"
|
||||
CAMERA = "devices.types.camera"
|
||||
COOKING = "devices.types.cooking"
|
||||
COFFEE_MAKER = "devices.types.cooking.coffee_maker"
|
||||
KETTLE = "devices.types.cooking.kettle"
|
||||
MULTICOOKER = "devices.types.cooking.multicooker"
|
||||
OPENABLE = "devices.types.openable"
|
||||
OPENABLE_CURTAIN = "devices.types.openable.curtain"
|
||||
OPENABLE_VALVE = "devices.types.openable.valve"
|
||||
HUMIDIFIER = "devices.types.humidifier"
|
||||
PURIFIER = "devices.types.purifier"
|
||||
VACUUM_CLEANER = "devices.types.vacuum_cleaner"
|
||||
WASHING_MACHINE = "devices.types.washing_machine"
|
||||
DISHWASHER = "devices.types.dishwasher"
|
||||
IRON = "devices.types.iron"
|
||||
SENSOR = "devices.types.sensor"
|
||||
SENSOR_MOTION = "devices.types.sensor.motion"
|
||||
SENSOR_VIBRATION = "devices.types.sensor.vibration"
|
||||
SENSOR_ILLUMINATION = "devices.types.sensor.illumination"
|
||||
SENSOR_OPEN = "devices.types.sensor.open"
|
||||
SENSOR_CLIMATE = "devices.types.sensor.climate"
|
||||
SENSOR_WATER_LEAK = "devices.types.sensor.water_leak"
|
||||
SENSOR_BUTTON = "devices.types.sensor.button"
|
||||
SENSOR_GAS = "devices.types.sensor.gas"
|
||||
SENSOR_SMOKE = "devices.types.sensor.smoke"
|
||||
SMART_METER = "devices.types.smart_meter"
|
||||
SMART_METER_COLD_WATER = "devices.types.smart_meter.cold_water"
|
||||
SMART_METER_ELECTRICITY = "devices.types.smart_meter.electricity"
|
||||
SMART_METER_GAS = "devices.types.smart_meter.gas"
|
||||
SMART_METER_HEAT = "devices.types.smart_meter.heat"
|
||||
SMART_METER_HOT_WATER = "devices.types.smart_meter.hot_water"
|
||||
PET_DRINKING_FOUNTAIN = "devices.types.pet_drinking_fountain"
|
||||
PET_FEEDER = "devices.types.pet_feeder"
|
||||
VENTILATION = "devices.types.ventilation"
|
||||
VENTILATION_FAN = "devices.types.ventilation.fan"
|
||||
OTHER = "devices.types.other"
|
||||
|
||||
|
||||
class DeviceInfo(APIModel):
|
||||
"""Extended device info."""
|
||||
|
||||
manufacturer: str | None = None
|
||||
model: str | None = None
|
||||
hw_version: str | None = None
|
||||
sw_version: str | None = None
|
||||
|
||||
|
||||
class DeviceDescription(APIModel):
|
||||
"""Device description for a device list request."""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
description: str | None = None
|
||||
room: str | None = None
|
||||
type: DeviceType
|
||||
capabilities: list[CapabilityDescription] | None = None
|
||||
properties: list[PropertyDescription] | None = None
|
||||
device_info: DeviceInfo | None = None
|
||||
|
||||
|
||||
class DeviceState(APIModel):
|
||||
"""Device state for a state query request."""
|
||||
|
||||
id: str
|
||||
capabilities: list[CapabilityInstanceState] | None = None
|
||||
properties: list[PropertyInstanceState] | None = None
|
||||
error_code: ResponseCode | None = None
|
||||
error_message: str | None = None
|
||||
|
||||
|
||||
class DeviceList(ResponsePayload):
|
||||
"""Response payload for a device list request."""
|
||||
|
||||
user_id: str
|
||||
devices: list[DeviceDescription]
|
||||
|
||||
|
||||
class DeviceStates(ResponsePayload):
|
||||
"""Response payload for a state query request."""
|
||||
|
||||
devices: list[DeviceState]
|
||||
|
||||
|
||||
class StatesRequestDevice(APIModel):
|
||||
"""Device for a state query request."""
|
||||
|
||||
id: str
|
||||
custom_data: dict[str, Any] | None = None
|
||||
|
||||
|
||||
class StatesRequest(APIModel):
|
||||
"""Request body for a state query request."""
|
||||
|
||||
devices: list[StatesRequestDevice]
|
||||
|
||||
|
||||
class ActionRequestDevice(APIModel):
|
||||
"""Device for a state change request."""
|
||||
|
||||
id: str
|
||||
capabilities: list[CapabilityInstanceAction]
|
||||
|
||||
|
||||
class ActionRequestPayload(APIModel):
|
||||
"""Request payload for state change request."""
|
||||
|
||||
devices: list[ActionRequestDevice]
|
||||
|
||||
|
||||
class ActionRequest(APIModel):
|
||||
"""Request body for a state change request."""
|
||||
|
||||
payload: ActionRequestPayload
|
||||
|
||||
|
||||
class SuccessActionResult(APIModel):
|
||||
"""Success device action result."""
|
||||
|
||||
status: Literal["DONE"] = "DONE"
|
||||
|
||||
|
||||
class FailedActionResult(APIModel):
|
||||
"""Failed device action result."""
|
||||
|
||||
status: Literal["ERROR"] = "ERROR"
|
||||
error_code: ResponseCode
|
||||
|
||||
|
||||
class ActionResultCapabilityState(APIModel):
|
||||
"""Result of capability instance state change."""
|
||||
|
||||
instance: CapabilityInstance
|
||||
value: CapabilityInstanceActionResultValue | None = None
|
||||
action_result: SuccessActionResult | FailedActionResult
|
||||
|
||||
|
||||
class ActionResultCapability(APIModel):
|
||||
"""Result of capability state change."""
|
||||
|
||||
type: CapabilityType
|
||||
state: ActionResultCapabilityState
|
||||
|
||||
|
||||
class ActionResultDevice(APIModel):
|
||||
"""Device for a state change response."""
|
||||
|
||||
id: str
|
||||
capabilities: list[ActionResultCapability] | None = None
|
||||
action_result: FailedActionResult | SuccessActionResult | None = None
|
||||
|
||||
|
||||
class ActionResult(ResponsePayload):
|
||||
"""Response for a device state change."""
|
||||
|
||||
devices: list[ActionResultDevice]
|
||||
@@ -0,0 +1,65 @@
|
||||
"""Schema for device property.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/properties-types.html
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
from typing import Any, Literal
|
||||
|
||||
from .base import APIModel
|
||||
from .property_event import EventPropertyInstance, EventPropertyParameters
|
||||
from .property_float import FloatPropertyInstance, FloatPropertyParameters
|
||||
|
||||
|
||||
class PropertyType(StrEnum):
|
||||
"""Property type."""
|
||||
|
||||
FLOAT = "devices.properties.float"
|
||||
EVENT = "devices.properties.event"
|
||||
|
||||
@property
|
||||
def short(self) -> str:
|
||||
"""Return short version of the property type."""
|
||||
return str(self).replace("devices.properties.", "")
|
||||
|
||||
|
||||
class FloatPropertyDescription(APIModel):
|
||||
"""Description of a float property for a device list request."""
|
||||
|
||||
type: Literal[PropertyType.FLOAT] = PropertyType.FLOAT
|
||||
retrievable: bool
|
||||
reportable: bool
|
||||
parameters: FloatPropertyParameters
|
||||
|
||||
|
||||
class EventPropertyDescription(APIModel):
|
||||
"""Description of an event property for a device list request."""
|
||||
|
||||
type: Literal[PropertyType.EVENT] = PropertyType.EVENT
|
||||
retrievable: bool
|
||||
reportable: bool
|
||||
parameters: EventPropertyParameters[Any]
|
||||
|
||||
|
||||
PropertyDescription = FloatPropertyDescription | EventPropertyDescription
|
||||
"""Description of a property for a device list request."""
|
||||
|
||||
PropertyParameters = FloatPropertyParameters | EventPropertyParameters[Any]
|
||||
"""Parameters of a property for a device list request."""
|
||||
|
||||
PropertyInstance = FloatPropertyInstance | EventPropertyInstance
|
||||
"""All property instances."""
|
||||
|
||||
|
||||
class PropertyInstanceStateValue(APIModel):
|
||||
"""Property instance value."""
|
||||
|
||||
instance: PropertyInstance
|
||||
value: Any
|
||||
|
||||
|
||||
class PropertyInstanceState(APIModel):
|
||||
"""Property state for state query and callback requests."""
|
||||
|
||||
type: PropertyType
|
||||
state: PropertyInstanceStateValue
|
||||
@@ -0,0 +1,192 @@
|
||||
"""Schema for event property.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/event.html
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
from typing import Any, Generic, Literal, TypeVar
|
||||
|
||||
from pydantic.v1 import validator
|
||||
|
||||
from .base import GenericAPIModel
|
||||
|
||||
|
||||
class EventPropertyInstance(StrEnum):
|
||||
"""Instance of an event property.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/event-instance.html
|
||||
"""
|
||||
|
||||
VIBRATION = "vibration"
|
||||
OPEN = "open"
|
||||
BUTTON = "button"
|
||||
MOTION = "motion"
|
||||
SMOKE = "smoke"
|
||||
GAS = "gas"
|
||||
BATTERY_LEVEL = "battery_level"
|
||||
FOOD_LEVEL = "food_level"
|
||||
WATER_LEVEL = "water_level"
|
||||
WATER_LEAK = "water_leak"
|
||||
|
||||
|
||||
class EventInstanceEvent(StrEnum):
|
||||
"""Base class for an instance event."""
|
||||
|
||||
...
|
||||
|
||||
|
||||
class VibrationInstanceEvent(EventInstanceEvent):
|
||||
"""Event of a vibration instance."""
|
||||
|
||||
TILT = "tilt"
|
||||
FALL = "fall"
|
||||
VIBRATION = "vibration"
|
||||
|
||||
|
||||
class OpenInstanceEvent(EventInstanceEvent):
|
||||
"""Event of a open instance."""
|
||||
|
||||
OPENED = "opened"
|
||||
CLOSED = "closed"
|
||||
|
||||
|
||||
class ButtonInstanceEvent(EventInstanceEvent):
|
||||
"""Event of a button instance."""
|
||||
|
||||
CLICK = "click"
|
||||
DOUBLE_CLICK = "double_click"
|
||||
LONG_PRESS = "long_press"
|
||||
|
||||
|
||||
class MotionInstanceEvent(EventInstanceEvent):
|
||||
"""Event of a motion instance."""
|
||||
|
||||
DETECTED = "detected"
|
||||
NOT_DETECTED = "not_detected"
|
||||
|
||||
|
||||
class SmokeInstanceEvent(EventInstanceEvent):
|
||||
"""Event of a smoke instance."""
|
||||
|
||||
DETECTED = "detected"
|
||||
NOT_DETECTED = "not_detected"
|
||||
HIGH = "high"
|
||||
|
||||
|
||||
class GasInstanceEvent(EventInstanceEvent):
|
||||
"""Event of a gas instance."""
|
||||
|
||||
DETECTED = "detected"
|
||||
NOT_DETECTED = "not_detected"
|
||||
HIGH = "high"
|
||||
|
||||
|
||||
class BatteryLevelInstanceEvent(EventInstanceEvent):
|
||||
"""Event of a battery_level instance."""
|
||||
|
||||
LOW = "low"
|
||||
NORMAL = "normal"
|
||||
HIGH = "high"
|
||||
|
||||
|
||||
class FoodLevelInstanceEvent(EventInstanceEvent):
|
||||
"""Event of a food_level instance."""
|
||||
|
||||
EMPTY = "empty"
|
||||
LOW = "low"
|
||||
NORMAL = "normal"
|
||||
|
||||
|
||||
class WaterLevelInstanceEvent(EventInstanceEvent):
|
||||
"""Event of a water_level instance."""
|
||||
|
||||
EMPTY = "empty"
|
||||
LOW = "low"
|
||||
NORMAL = "normal"
|
||||
|
||||
|
||||
class WaterLeakInstanceEvent(EventInstanceEvent):
|
||||
"""Event of a water_leak instance."""
|
||||
|
||||
DRY = "dry"
|
||||
LEAK = "leak"
|
||||
|
||||
|
||||
EventInstanceEventT = TypeVar("EventInstanceEventT", bound=EventInstanceEvent)
|
||||
|
||||
|
||||
def get_event_class_for_instance(instance: EventPropertyInstance) -> type[EventInstanceEvent]:
|
||||
"""Return EventInstanceEvent enum for event property instance."""
|
||||
return {
|
||||
EventPropertyInstance.VIBRATION: VibrationInstanceEvent,
|
||||
EventPropertyInstance.OPEN: OpenInstanceEvent,
|
||||
EventPropertyInstance.BUTTON: ButtonInstanceEvent,
|
||||
EventPropertyInstance.MOTION: MotionInstanceEvent,
|
||||
EventPropertyInstance.SMOKE: SmokeInstanceEvent,
|
||||
EventPropertyInstance.GAS: GasInstanceEvent,
|
||||
EventPropertyInstance.BATTERY_LEVEL: BatteryLevelInstanceEvent,
|
||||
EventPropertyInstance.FOOD_LEVEL: FoodLevelInstanceEvent,
|
||||
EventPropertyInstance.WATER_LEVEL: WaterLevelInstanceEvent,
|
||||
EventPropertyInstance.WATER_LEAK: WaterLeakInstanceEvent,
|
||||
}[instance]
|
||||
|
||||
|
||||
def get_supported_events_for_instance(instance: EventPropertyInstance) -> list[EventInstanceEvent]:
|
||||
"""Return list of supported events for event property instance."""
|
||||
return list(get_event_class_for_instance(instance).__members__.values())
|
||||
|
||||
|
||||
class EventPropertyParameters(GenericAPIModel, Generic[EventInstanceEventT]):
|
||||
"""Parameters of an event property."""
|
||||
|
||||
instance: EventPropertyInstance
|
||||
events: list[dict[Literal["value"], EventInstanceEventT]] = []
|
||||
|
||||
@validator("events", pre=True, always=True)
|
||||
def set_events(cls, v: Any) -> Any:
|
||||
"""Update events list value."""
|
||||
if not v:
|
||||
instance_event: type[EventInstanceEventT] = cls.__fields__["events"].type_.__args__[1]
|
||||
return [{"value": m} for m in instance_event.__members__.values()]
|
||||
|
||||
return v # pragma: nocover
|
||||
|
||||
|
||||
class VibrationEventPropertyParameters(EventPropertyParameters[VibrationInstanceEvent]):
|
||||
instance: Literal[EventPropertyInstance.VIBRATION] = EventPropertyInstance.VIBRATION
|
||||
|
||||
|
||||
class OpenEventPropertyParameters(EventPropertyParameters[OpenInstanceEvent]):
|
||||
instance: Literal[EventPropertyInstance.OPEN] = EventPropertyInstance.OPEN
|
||||
|
||||
|
||||
class ButtonEventPropertyParameters(EventPropertyParameters[ButtonInstanceEvent]):
|
||||
instance: Literal[EventPropertyInstance.BUTTON] = EventPropertyInstance.BUTTON
|
||||
|
||||
|
||||
class MotionEventPropertyParameters(EventPropertyParameters[MotionInstanceEvent]):
|
||||
instance: Literal[EventPropertyInstance.MOTION] = EventPropertyInstance.MOTION
|
||||
|
||||
|
||||
class SmokeEventPropertyParameters(EventPropertyParameters[SmokeInstanceEvent]):
|
||||
instance: Literal[EventPropertyInstance.SMOKE] = EventPropertyInstance.SMOKE
|
||||
|
||||
|
||||
class GasEventPropertyParameters(EventPropertyParameters[GasInstanceEvent]):
|
||||
instance: Literal[EventPropertyInstance.GAS] = EventPropertyInstance.GAS
|
||||
|
||||
|
||||
class BatteryLevelEventPropertyParameters(EventPropertyParameters[BatteryLevelInstanceEvent]):
|
||||
instance: Literal[EventPropertyInstance.BATTERY_LEVEL] = EventPropertyInstance.BATTERY_LEVEL
|
||||
|
||||
|
||||
class FoodLevelEventPropertyParameters(EventPropertyParameters[FoodLevelInstanceEvent]):
|
||||
instance: Literal[EventPropertyInstance.FOOD_LEVEL] = EventPropertyInstance.FOOD_LEVEL
|
||||
|
||||
|
||||
class WaterLevelEventPropertyParameters(EventPropertyParameters[WaterLevelInstanceEvent]):
|
||||
instance: Literal[EventPropertyInstance.WATER_LEVEL] = EventPropertyInstance.WATER_LEVEL
|
||||
|
||||
|
||||
class WaterLeakEventPropertyParameters(EventPropertyParameters[WaterLeakInstanceEvent]):
|
||||
instance: Literal[EventPropertyInstance.WATER_LEAK] = EventPropertyInstance.WATER_LEAK
|
||||
@@ -0,0 +1,194 @@
|
||||
"""Schema for float property.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/float.html
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
from typing import Literal
|
||||
|
||||
from .base import APIModel
|
||||
|
||||
|
||||
class FloatPropertyInstance(StrEnum):
|
||||
"""Instance of an event property.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/float-instance.html
|
||||
"""
|
||||
|
||||
AMPERAGE = "amperage"
|
||||
BATTERY_LEVEL = "battery_level"
|
||||
CO2_LEVEL = "co2_level"
|
||||
ELECTRICITY_METER = "electricity_meter"
|
||||
FOOD_LEVEL = "food_level"
|
||||
GAS_METER = "gas_meter"
|
||||
HEAT_METER = "heat_meter"
|
||||
HUMIDITY = "humidity"
|
||||
ILLUMINATION = "illumination"
|
||||
METER = "meter"
|
||||
PM10_DENSITY = "pm10_density"
|
||||
PM1_DENSITY = "pm1_density"
|
||||
PM2_5_DENSITY = "pm2.5_density"
|
||||
POWER = "power"
|
||||
PRESSURE = "pressure"
|
||||
TEMPERATURE = "temperature"
|
||||
TVOC = "tvoc"
|
||||
VOLTAGE = "voltage"
|
||||
WATER_LEVEL = "water_level"
|
||||
WATER_METER = "water_meter"
|
||||
|
||||
|
||||
class FloatUnit(StrEnum):
|
||||
"""Unit used in a float property."""
|
||||
|
||||
AMPERE = "unit.ampere"
|
||||
CUBIC_METER = "unit.cubic_meter"
|
||||
GIGACALORIE = "unit.gigacalorie"
|
||||
KILOWATT_HOUR = "unit.kilowatt_hour"
|
||||
LUX = "unit.illumination.lux"
|
||||
MCG_M3 = "unit.density.mcg_m3"
|
||||
PERCENT = "unit.percent"
|
||||
PPM = "unit.ppm"
|
||||
VOLT = "unit.volt"
|
||||
WATT = "unit.watt"
|
||||
|
||||
|
||||
class PressureUnit(StrEnum):
|
||||
"""Pressure unit."""
|
||||
|
||||
PASCAL = "unit.pressure.pascal"
|
||||
MMHG = "unit.pressure.mmhg"
|
||||
ATM = "unit.pressure.atm"
|
||||
BAR = "unit.pressure.bar"
|
||||
|
||||
|
||||
class TemperatureUnit(StrEnum):
|
||||
"""Temperature unit."""
|
||||
|
||||
CELSIUS = "unit.temperature.celsius"
|
||||
KELVIN = "unit.temperature.kelvin"
|
||||
|
||||
|
||||
class FloatPropertyParameters(APIModel):
|
||||
"""Parameters of a float property."""
|
||||
|
||||
instance: FloatPropertyInstance
|
||||
unit: FloatUnit | PressureUnit | TemperatureUnit | None
|
||||
|
||||
@property
|
||||
def range(self) -> tuple[int | None, int | None]:
|
||||
"""Return value range."""
|
||||
return None, None
|
||||
|
||||
|
||||
class FloatPropertyAboveZeroMixin:
|
||||
"""Mixin for a property that has value only above zero."""
|
||||
|
||||
@property
|
||||
def range(self) -> tuple[int | None, int | None]:
|
||||
"""Return value range."""
|
||||
return 0, None
|
||||
|
||||
|
||||
class PercentFloatPropertyParameters(FloatPropertyParameters):
|
||||
unit: Literal[FloatUnit.PERCENT] = FloatUnit.PERCENT
|
||||
|
||||
@property
|
||||
def range(self) -> tuple[int | None, int | None]:
|
||||
"""Return value range."""
|
||||
return 0, 100
|
||||
|
||||
|
||||
class DensityFloatPropertyParameters(FloatPropertyAboveZeroMixin, FloatPropertyParameters):
|
||||
unit: Literal[FloatUnit.MCG_M3] = FloatUnit.MCG_M3
|
||||
|
||||
|
||||
class AmperageFloatPropertyParameters(FloatPropertyAboveZeroMixin, FloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.AMPERAGE] = FloatPropertyInstance.AMPERAGE
|
||||
unit: Literal[FloatUnit.AMPERE] = FloatUnit.AMPERE
|
||||
|
||||
|
||||
class BatteryLevelFloatPropertyParameters(PercentFloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.BATTERY_LEVEL] = FloatPropertyInstance.BATTERY_LEVEL
|
||||
|
||||
|
||||
class CO2LevelFloatPropertyParameters(FloatPropertyAboveZeroMixin, FloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.CO2_LEVEL] = FloatPropertyInstance.CO2_LEVEL
|
||||
unit: Literal[FloatUnit.PPM] = FloatUnit.PPM
|
||||
|
||||
|
||||
class ElectricityMeterFloatPropertyParameters(FloatPropertyAboveZeroMixin, FloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.ELECTRICITY_METER] = FloatPropertyInstance.ELECTRICITY_METER
|
||||
unit: Literal[FloatUnit.KILOWATT_HOUR] = FloatUnit.KILOWATT_HOUR
|
||||
|
||||
|
||||
class FoodLevelFloatPropertyParameters(PercentFloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.FOOD_LEVEL] = FloatPropertyInstance.FOOD_LEVEL
|
||||
|
||||
|
||||
class GasMeterFloatPropertyParameters(FloatPropertyAboveZeroMixin, FloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.GAS_METER] = FloatPropertyInstance.GAS_METER
|
||||
unit: Literal[FloatUnit.CUBIC_METER] = FloatUnit.CUBIC_METER
|
||||
|
||||
|
||||
class HeatMeterFloatPropertyParameters(FloatPropertyAboveZeroMixin, FloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.HEAT_METER] = FloatPropertyInstance.HEAT_METER
|
||||
unit: Literal[FloatUnit.GIGACALORIE] = FloatUnit.GIGACALORIE
|
||||
|
||||
|
||||
class HumidityFloatPropertyParameters(PercentFloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.HUMIDITY] = FloatPropertyInstance.HUMIDITY
|
||||
|
||||
|
||||
class IlluminationFloatPropertyParameters(FloatPropertyAboveZeroMixin, FloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.ILLUMINATION] = FloatPropertyInstance.ILLUMINATION
|
||||
unit: Literal[FloatUnit.LUX] = FloatUnit.LUX
|
||||
|
||||
|
||||
class MeterFloatPropertyParameters(FloatPropertyAboveZeroMixin, FloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.METER] = FloatPropertyInstance.METER
|
||||
unit: None = None
|
||||
|
||||
|
||||
class PM1DensityFloatPropertyParameters(DensityFloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.PM1_DENSITY] = FloatPropertyInstance.PM1_DENSITY
|
||||
|
||||
|
||||
class PM25DensityFloatPropertyParameters(DensityFloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.PM2_5_DENSITY] = FloatPropertyInstance.PM2_5_DENSITY
|
||||
|
||||
|
||||
class PM10DensityFloatPropertyParameters(DensityFloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.PM10_DENSITY] = FloatPropertyInstance.PM10_DENSITY
|
||||
|
||||
|
||||
class PowerFloatPropertyParameters(FloatPropertyAboveZeroMixin, FloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.POWER] = FloatPropertyInstance.POWER
|
||||
unit: Literal[FloatUnit.WATT] = FloatUnit.WATT
|
||||
|
||||
|
||||
class PressureFloatPropertyParameters(FloatPropertyAboveZeroMixin, FloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.PRESSURE] = FloatPropertyInstance.PRESSURE
|
||||
unit: PressureUnit
|
||||
|
||||
|
||||
class TemperatureFloatPropertyParameters(FloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.TEMPERATURE] = FloatPropertyInstance.TEMPERATURE
|
||||
unit: TemperatureUnit
|
||||
|
||||
|
||||
class TVOCFloatPropertyParameters(DensityFloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.TVOC] = FloatPropertyInstance.TVOC
|
||||
|
||||
|
||||
class VoltageFloatPropertyParameters(FloatPropertyAboveZeroMixin, FloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.VOLTAGE] = FloatPropertyInstance.VOLTAGE
|
||||
unit: Literal[FloatUnit.VOLT] = FloatUnit.VOLT
|
||||
|
||||
|
||||
class WaterLevelFloatPropertyParameters(PercentFloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.WATER_LEVEL] = FloatPropertyInstance.WATER_LEVEL
|
||||
|
||||
|
||||
class WaterMeterFloatPropertyParameters(FloatPropertyAboveZeroMixin, FloatPropertyParameters):
|
||||
instance: Literal[FloatPropertyInstance.WATER_METER] = FloatPropertyInstance.WATER_METER
|
||||
unit: Literal[FloatUnit.CUBIC_METER] = FloatUnit.CUBIC_METER
|
||||
@@ -0,0 +1,52 @@
|
||||
"""Schema for an API response.
|
||||
|
||||
https://yandex.ru/dev/dialogs/smart-home/doc/concepts/response-codes.html
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
|
||||
from .base import APIModel
|
||||
|
||||
|
||||
class ResponseCode(StrEnum):
|
||||
"""Response code."""
|
||||
|
||||
DOOR_OPEN = "DOOR_OPEN"
|
||||
LID_OPEN = "LID_OPEN"
|
||||
REMOTE_CONTROL_DISABLED = "REMOTE_CONTROL_DISABLED"
|
||||
NOT_ENOUGH_WATER = "NOT_ENOUGH_WATER"
|
||||
LOW_CHARGE_LEVEL = "LOW_CHARGE_LEVEL"
|
||||
CONTAINER_FULL = "CONTAINER_FULL"
|
||||
CONTAINER_EMPTY = "CONTAINER_EMPTY"
|
||||
DRIP_TRAY_FULL = "DRIP_TRAY_FULL"
|
||||
DEVICE_STUCK = "DEVICE_STUCK"
|
||||
DEVICE_OFF = "DEVICE_OFF"
|
||||
FIRMWARE_OUT_OF_DATE = "FIRMWARE_OUT_OF_DATE"
|
||||
NOT_ENOUGH_DETERGENT = "NOT_ENOUGH_DETERGENT"
|
||||
HUMAN_INVOLVEMENT_NEEDED = "HUMAN_INVOLVEMENT_NEEDED"
|
||||
DEVICE_UNREACHABLE = "DEVICE_UNREACHABLE"
|
||||
DEVICE_BUSY = "DEVICE_BUSY"
|
||||
INTERNAL_ERROR = "INTERNAL_ERROR"
|
||||
INVALID_ACTION = "INVALID_ACTION"
|
||||
INVALID_VALUE = "INVALID_VALUE"
|
||||
NOT_SUPPORTED_IN_CURRENT_MODE = "NOT_SUPPORTED_IN_CURRENT_MODE"
|
||||
ACCOUNT_LINKING_ERROR = "ACCOUNT_LINKING_ERROR"
|
||||
DEVICE_NOT_FOUND = "DEVICE_NOT_FOUND"
|
||||
|
||||
|
||||
class ResponsePayload(APIModel):
|
||||
"""Base class for an API response payload."""
|
||||
|
||||
|
||||
class Error(ResponsePayload):
|
||||
"""Error payload."""
|
||||
|
||||
error_code: ResponseCode
|
||||
error_message: str | None = None
|
||||
|
||||
|
||||
class Response(APIModel):
|
||||
"""Base API response."""
|
||||
|
||||
request_id: str | None = None
|
||||
payload: ResponsePayload | None = None
|
||||
Reference in New Issue
Block a user