97 lines
3.0 KiB
Python
97 lines
3.0 KiB
Python
"""Contact Sensor Capability - Fensterkontakt (read-only).
|
|
|
|
This module defines the ContactState model for door/window contact sensors.
|
|
These sensors report their open/closed state and are read-only devices.
|
|
|
|
Capability Version: contact_sensor@1.0.0
|
|
"""
|
|
|
|
from datetime import datetime
|
|
from typing import Annotated, Literal
|
|
|
|
from pydantic import BaseModel, Field, field_validator
|
|
|
|
|
|
# Capability metadata
|
|
CAP_VERSION = "contact_sensor@1.0.0"
|
|
DISPLAY_NAME = "Contact Sensor"
|
|
|
|
|
|
class ContactState(BaseModel):
|
|
"""State model for contact sensors (door/window sensors).
|
|
|
|
Contact sensors are read-only devices that report whether a door or window
|
|
is open or closed. They typically also report battery level and signal quality.
|
|
|
|
Attributes:
|
|
contact: Current state of the contact ("open" or "closed")
|
|
battery: Battery level percentage (0-100), optional
|
|
linkquality: MQTT link quality indicator, optional
|
|
device_temperature: Internal device temperature in °C, optional
|
|
voltage: Battery voltage in mV, optional
|
|
ts: Timestamp of the state reading, optional
|
|
|
|
Examples:
|
|
>>> ContactState(contact="open")
|
|
ContactState(contact='open', battery=None, ...)
|
|
|
|
>>> ContactState(contact="closed", battery=95, linkquality=87)
|
|
ContactState(contact='closed', battery=95, linkquality=87, ...)
|
|
"""
|
|
|
|
contact: Literal["open", "closed"] = Field(
|
|
...,
|
|
description="Contact state: 'open' for open door/window, 'closed' for closed"
|
|
)
|
|
|
|
battery: Annotated[int, Field(ge=0, le=100)] | None = Field(
|
|
None,
|
|
description="Battery level in percent (0-100)"
|
|
)
|
|
|
|
linkquality: int | None = Field(
|
|
None,
|
|
description="Link quality indicator (typically 0-255)"
|
|
)
|
|
|
|
device_temperature: float | None = Field(
|
|
None,
|
|
description="Internal device temperature in degrees Celsius"
|
|
)
|
|
|
|
voltage: int | None = Field(
|
|
None,
|
|
description="Battery voltage in millivolts"
|
|
)
|
|
|
|
ts: datetime | None = Field(
|
|
None,
|
|
description="Timestamp of the state reading"
|
|
)
|
|
|
|
@staticmethod
|
|
def normalize_bool(is_open: bool) -> "ContactState":
|
|
"""Convert boolean to ContactState.
|
|
|
|
Helper method to convert a boolean value to a ContactState instance.
|
|
Useful when integrating with systems that use True/False for contact state.
|
|
|
|
Args:
|
|
is_open: True if contact is open, False if closed
|
|
|
|
Returns:
|
|
ContactState instance with appropriate contact value
|
|
|
|
Examples:
|
|
>>> ContactState.normalize_bool(True)
|
|
ContactState(contact='open', ...)
|
|
|
|
>>> ContactState.normalize_bool(False)
|
|
ContactState(contact='closed', ...)
|
|
"""
|
|
return ContactState(contact="open" if is_open else "closed")
|
|
|
|
|
|
# Public API
|
|
__all__ = ["ContactState", "CAP_VERSION", "DISPLAY_NAME"]
|