236 lines
11 KiB
Python
236 lines
11 KiB
Python
from pydantic import BaseModel, Field
|
|
from typing import Optional, List, Dict, Any, Literal
|
|
from datetime import datetime
|
|
from enum import Enum
|
|
|
|
class SensorType(str, Enum):
|
|
ENERGY = "energy"
|
|
CO2 = "co2"
|
|
TEMPERATURE = "temperature"
|
|
HUMIDITY = "humidity"
|
|
HVAC = "hvac"
|
|
LIGHTING = "lighting"
|
|
SECURITY = "security"
|
|
|
|
class SensorStatus(str, Enum):
|
|
ONLINE = "online"
|
|
OFFLINE = "offline"
|
|
ERROR = "error"
|
|
MAINTENANCE = "maintenance"
|
|
|
|
class CO2Status(str, Enum):
|
|
GOOD = "good"
|
|
MODERATE = "moderate"
|
|
POOR = "poor"
|
|
CRITICAL = "critical"
|
|
|
|
class OccupancyLevel(str, Enum):
|
|
LOW = "low"
|
|
MEDIUM = "medium"
|
|
HIGH = "high"
|
|
|
|
# Base Models
|
|
class SensorReading(BaseModel):
|
|
"""Individual sensor reading model"""
|
|
sensor_id: str = Field(..., description="Unique sensor identifier")
|
|
room: Optional[str] = Field(None, description="Room where sensor is located")
|
|
sensor_type: SensorType = Field(..., description="Type of sensor")
|
|
timestamp: int = Field(..., description="Unix timestamp of reading")
|
|
created_at: datetime = Field(default_factory=datetime.utcnow, description="Record creation timestamp")
|
|
|
|
# Sensor values
|
|
energy: Optional[Dict[str, Any]] = Field(None, description="Energy reading with value and unit")
|
|
co2: Optional[Dict[str, Any]] = Field(None, description="CO2 reading with value and unit")
|
|
temperature: Optional[Dict[str, Any]] = Field(None, description="Temperature reading with value and unit")
|
|
humidity: Optional[Dict[str, Any]] = Field(None, description="Humidity reading with value and unit")
|
|
motion: Optional[Dict[str, Any]] = Field(None, description="Motion detection reading")
|
|
|
|
# Metadata
|
|
metadata: Optional[Dict[str, Any]] = Field(default_factory=dict, description="Additional sensor metadata")
|
|
|
|
class Config:
|
|
json_encoders = {
|
|
datetime: lambda v: v.isoformat()
|
|
}
|
|
|
|
class LegacySensorReading(BaseModel):
|
|
"""Legacy sensor reading format for backward compatibility"""
|
|
sensor_id: str = Field(..., alias="sensorId")
|
|
timestamp: int
|
|
value: float
|
|
unit: str
|
|
created_at: datetime = Field(default_factory=datetime.utcnow)
|
|
|
|
class Config:
|
|
allow_population_by_field_name = True
|
|
|
|
class SensorMetadata(BaseModel):
|
|
"""Sensor configuration and metadata"""
|
|
sensor_id: str = Field(..., description="Unique sensor identifier")
|
|
name: str = Field(..., description="Human-readable sensor name")
|
|
sensor_type: SensorType = Field(..., description="Type of sensor")
|
|
room: Optional[str] = Field(None, description="Room assignment")
|
|
status: SensorStatus = Field(default=SensorStatus.OFFLINE, description="Current sensor status")
|
|
|
|
# Physical location and installation details
|
|
location: Optional[str] = Field(None, description="Physical location description")
|
|
floor: Optional[str] = Field(None, description="Floor level")
|
|
building: Optional[str] = Field(None, description="Building identifier")
|
|
|
|
# Technical specifications
|
|
model: Optional[str] = Field(None, description="Sensor model")
|
|
manufacturer: Optional[str] = Field(None, description="Sensor manufacturer")
|
|
firmware_version: Optional[str] = Field(None, description="Firmware version")
|
|
hardware_version: Optional[str] = Field(None, description="Hardware version")
|
|
|
|
# Network and connectivity
|
|
ip_address: Optional[str] = Field(None, description="IP address if network connected")
|
|
mac_address: Optional[str] = Field(None, description="MAC address")
|
|
connection_type: Optional[str] = Field(None, description="Connection type (wifi, ethernet, zigbee, etc.)")
|
|
|
|
# Power and maintenance
|
|
battery_level: Optional[float] = Field(None, description="Battery level percentage")
|
|
last_maintenance: Optional[datetime] = Field(None, description="Last maintenance date")
|
|
next_maintenance: Optional[datetime] = Field(None, description="Next scheduled maintenance")
|
|
|
|
# Operational settings
|
|
sampling_rate: Optional[int] = Field(None, description="Data sampling rate in seconds")
|
|
calibration_date: Optional[datetime] = Field(None, description="Last calibration date")
|
|
|
|
# Capabilities
|
|
monitoring_capabilities: List[str] = Field(default_factory=list, description="List of monitoring capabilities")
|
|
control_capabilities: List[str] = Field(default_factory=list, description="List of control capabilities")
|
|
|
|
# Timestamps
|
|
installed_at: Optional[datetime] = Field(None, description="Installation timestamp")
|
|
last_seen: Optional[datetime] = Field(None, description="Last communication timestamp")
|
|
created_at: datetime = Field(default_factory=datetime.utcnow, description="Record creation timestamp")
|
|
updated_at: datetime = Field(default_factory=datetime.utcnow, description="Record update timestamp")
|
|
|
|
class Config:
|
|
json_encoders = {
|
|
datetime: lambda v: v.isoformat() if v else None
|
|
}
|
|
|
|
class RoomMetrics(BaseModel):
|
|
"""Aggregated room-level metrics"""
|
|
room: str = Field(..., description="Room identifier")
|
|
timestamp: int = Field(..., description="Metrics calculation timestamp")
|
|
created_at: datetime = Field(default_factory=datetime.utcnow, description="Record creation timestamp")
|
|
|
|
# Sensor inventory
|
|
sensor_count: int = Field(0, description="Total number of sensors in room")
|
|
active_sensors: List[str] = Field(default_factory=list, description="List of active sensor IDs")
|
|
sensor_types: List[SensorType] = Field(default_factory=list, description="Types of sensors present")
|
|
|
|
# Energy metrics
|
|
energy: Optional[Dict[str, Any]] = Field(None, description="Energy consumption metrics")
|
|
# Format: {"current": float, "total": float, "average": float, "peak": float, "unit": str}
|
|
|
|
# Environmental metrics
|
|
co2: Optional[Dict[str, Any]] = Field(None, description="CO2 level metrics")
|
|
# Format: {"current": float, "average": float, "max": float, "min": float, "status": CO2Status, "unit": str}
|
|
|
|
temperature: Optional[Dict[str, Any]] = Field(None, description="Temperature metrics")
|
|
# Format: {"current": float, "average": float, "max": float, "min": float, "unit": str}
|
|
|
|
humidity: Optional[Dict[str, Any]] = Field(None, description="Humidity metrics")
|
|
# Format: {"current": float, "average": float, "max": float, "min": float, "unit": str}
|
|
|
|
# Occupancy and usage
|
|
occupancy_estimate: OccupancyLevel = Field(default=OccupancyLevel.LOW, description="Estimated occupancy level")
|
|
motion_detected: bool = Field(default=False, description="Recent motion detection status")
|
|
|
|
# Time-based metrics
|
|
last_activity: Optional[datetime] = Field(None, description="Last detected activity timestamp")
|
|
daily_usage_hours: Optional[float] = Field(None, description="Estimated daily usage in hours")
|
|
|
|
class Config:
|
|
json_encoders = {
|
|
datetime: lambda v: v.isoformat() if v else None
|
|
}
|
|
|
|
class SystemEvent(BaseModel):
|
|
"""System events and alerts"""
|
|
event_id: str = Field(..., description="Unique event identifier")
|
|
event_type: str = Field(..., description="Type of event")
|
|
severity: Literal["info", "warning", "error", "critical"] = Field(..., description="Event severity")
|
|
timestamp: int = Field(..., description="Event timestamp")
|
|
created_at: datetime = Field(default_factory=datetime.utcnow, description="Record creation timestamp")
|
|
|
|
# Event details
|
|
title: str = Field(..., description="Event title")
|
|
description: str = Field(..., description="Event description")
|
|
source: Optional[str] = Field(None, description="Event source (sensor_id, system component, etc.)")
|
|
|
|
# Context
|
|
sensor_id: Optional[str] = Field(None, description="Related sensor ID")
|
|
room: Optional[str] = Field(None, description="Related room")
|
|
|
|
# Event data
|
|
data: Optional[Dict[str, Any]] = Field(default_factory=dict, description="Additional event data")
|
|
|
|
# Status tracking
|
|
acknowledged: bool = Field(default=False, description="Whether event has been acknowledged")
|
|
resolved: bool = Field(default=False, description="Whether event has been resolved")
|
|
acknowledged_by: Optional[str] = Field(None, description="Who acknowledged the event")
|
|
resolved_by: Optional[str] = Field(None, description="Who resolved the event")
|
|
acknowledged_at: Optional[datetime] = Field(None, description="Acknowledgment timestamp")
|
|
resolved_at: Optional[datetime] = Field(None, description="Resolution timestamp")
|
|
|
|
class Config:
|
|
json_encoders = {
|
|
datetime: lambda v: v.isoformat() if v else None
|
|
}
|
|
|
|
class DataQuery(BaseModel):
|
|
"""Data query parameters for historical data retrieval"""
|
|
sensor_ids: Optional[List[str]] = Field(None, description="Filter by sensor IDs")
|
|
rooms: Optional[List[str]] = Field(None, description="Filter by rooms")
|
|
sensor_types: Optional[List[SensorType]] = Field(None, description="Filter by sensor types")
|
|
|
|
# Time range
|
|
start_time: Optional[int] = Field(None, description="Start timestamp (Unix)")
|
|
end_time: Optional[int] = Field(None, description="End timestamp (Unix)")
|
|
|
|
# Aggregation
|
|
aggregate: Optional[str] = Field(None, description="Aggregation method (avg, sum, min, max)")
|
|
interval: Optional[str] = Field(None, description="Aggregation interval (1m, 5m, 1h, 1d)")
|
|
|
|
# Pagination
|
|
limit: int = Field(default=100, description="Maximum number of records to return")
|
|
offset: int = Field(default=0, description="Number of records to skip")
|
|
|
|
# Sorting
|
|
sort_by: str = Field(default="timestamp", description="Field to sort by")
|
|
sort_order: Literal["asc", "desc"] = Field(default="desc", description="Sort order")
|
|
|
|
class DataResponse(BaseModel):
|
|
"""Response model for data queries"""
|
|
data: List[Dict[str, Any]] = Field(default_factory=list, description="Query results")
|
|
total_count: int = Field(0, description="Total number of matching records")
|
|
query: DataQuery = Field(..., description="Original query parameters")
|
|
execution_time_ms: float = Field(..., description="Query execution time in milliseconds")
|
|
|
|
class HealthCheck(BaseModel):
|
|
"""Health check response model"""
|
|
status: str = Field(..., description="Overall system status")
|
|
timestamp: datetime = Field(default_factory=datetime.utcnow)
|
|
|
|
# Database status
|
|
mongodb_connected: bool = Field(..., description="MongoDB connection status")
|
|
redis_connected: bool = Field(..., description="Redis connection status")
|
|
|
|
# Data statistics
|
|
total_sensors: int = Field(0, description="Total number of registered sensors")
|
|
active_sensors: int = Field(0, description="Number of active sensors")
|
|
total_readings: int = Field(0, description="Total sensor readings in database")
|
|
|
|
# System metrics
|
|
uptime_seconds: float = Field(..., description="System uptime in seconds")
|
|
memory_usage_mb: Optional[float] = Field(None, description="Memory usage in MB")
|
|
|
|
class Config:
|
|
json_encoders = {
|
|
datetime: lambda v: v.isoformat()
|
|
} |