Files
sac4cps-backend/microservices/sensor-service/sensor_service.py
rafaeldpsilva 02a0d54e14 Add room and analytics services with CRUD API endpoints
- Implement RoomService for room management and metrics - Add
AnalyticsService for sensor data analytics and trends - Extend models
with Room, RoomCreate, RoomUpdate, RoomInfo - Add room CRUD endpoints to
FastAPI app - Add database connection logic for MongoDB and Redis -
Refactor sensor service logic into SensorService class
2025-09-22 15:13:14 +01:00

251 lines
9.0 KiB
Python

"""
Sensor service business logic
"""
import logging
from datetime import datetime, timedelta
from typing import List, Dict, Any, Optional
import json
logger = logging.getLogger(__name__)
class SensorService:
"""Service for managing sensors and sensor data"""
def __init__(self, db, redis_client):
self.db = db
self.redis = redis_client
async def get_sensors(self, room: Optional[str] = None, sensor_type: Optional[str] = None, status: Optional[str] = None) -> List[Dict[str, Any]]:
"""Get sensors with optional filtering"""
try:
query = {}
if room:
query["room"] = room
if sensor_type:
query["sensor_type"] = sensor_type
if status:
query["status"] = status
cursor = self.db.sensors.find(query)
sensors = []
async for sensor in cursor:
sensor["_id"] = str(sensor["_id"])
sensors.append(sensor)
return sensors
except Exception as e:
logger.error(f"Error getting sensors: {e}")
raise
async def get_sensor_details(self, sensor_id: str) -> Optional[Dict[str, Any]]:
"""Get detailed sensor information"""
try:
sensor = await self.db.sensors.find_one({"sensor_id": sensor_id})
if sensor:
sensor["_id"] = str(sensor["_id"])
# Get recent readings
recent_readings = await self.get_sensor_data(sensor_id, limit=10)
sensor["recent_readings"] = recent_readings.get("readings", [])
return sensor
return None
except Exception as e:
logger.error(f"Error getting sensor details: {e}")
raise
async def get_sensor_data(self, sensor_id: str, start_time: Optional[int] = None,
end_time: Optional[int] = None, limit: int = 100, offset: int = 0) -> Dict[str, Any]:
"""Get historical sensor data"""
try:
query = {"sensor_id": sensor_id}
if start_time or end_time:
query["timestamp"] = {}
if start_time:
query["timestamp"]["$gte"] = start_time
if end_time:
query["timestamp"]["$lte"] = end_time
# Get total count
total_count = await self.db.sensor_readings.count_documents(query)
# Get readings
cursor = self.db.sensor_readings.find(query).sort("timestamp", -1).skip(offset).limit(limit)
readings = []
async for reading in cursor:
reading["_id"] = str(reading["_id"])
readings.append(reading)
return {
"readings": readings,
"total_count": total_count,
"execution_time_ms": 0 # Placeholder
}
except Exception as e:
logger.error(f"Error getting sensor data: {e}")
raise
async def create_sensor(self, sensor_data) -> Dict[str, Any]:
"""Create a new sensor"""
try:
# Check if sensor already exists
existing = await self.db.sensors.find_one({"sensor_id": sensor_data.sensor_id})
if existing:
raise ValueError(f"Sensor {sensor_data.sensor_id} already exists")
# Create sensor document
sensor_doc = {
"sensor_id": sensor_data.sensor_id,
"name": sensor_data.name,
"sensor_type": sensor_data.sensor_type.value if hasattr(sensor_data.sensor_type, 'value') else str(sensor_data.sensor_type),
"room": sensor_data.room,
"location": sensor_data.location if hasattr(sensor_data, 'location') else None,
"status": "active",
"created_at": datetime.utcnow(),
"updated_at": datetime.utcnow()
}
result = await self.db.sensors.insert_one(sensor_doc)
return {"created_at": datetime.utcnow()}
except Exception as e:
logger.error(f"Error creating sensor: {e}")
raise
async def update_sensor(self, sensor_id: str, update_data: Dict[str, Any]) -> bool:
"""Update sensor metadata"""
try:
update_data["updated_at"] = datetime.utcnow()
result = await self.db.sensors.update_one(
{"sensor_id": sensor_id},
{"$set": update_data}
)
return result.modified_count > 0
except Exception as e:
logger.error(f"Error updating sensor: {e}")
raise
async def delete_sensor(self, sensor_id: str) -> Dict[str, Any]:
"""Delete a sensor and its data"""
try:
# Delete readings
readings_result = await self.db.sensor_readings.delete_many({"sensor_id": sensor_id})
# Delete sensor
await self.db.sensors.delete_one({"sensor_id": sensor_id})
return {"readings_deleted": readings_result.deleted_count}
except Exception as e:
logger.error(f"Error deleting sensor: {e}")
raise
async def ingest_sensor_data(self, sensor_data) -> Dict[str, Any]:
"""Ingest real-time sensor data"""
try:
# Create reading document
reading_doc = {
"sensor_id": sensor_data.sensor_id,
"timestamp": sensor_data.timestamp,
"value": sensor_data.value,
"unit": sensor_data.unit if hasattr(sensor_data, 'unit') else None,
"room": sensor_data.room if hasattr(sensor_data, 'room') else None,
"created_at": datetime.utcnow()
}
# Store in database
await self.db.sensor_readings.insert_one(reading_doc)
# Cache recent value in Redis
if self.redis:
cache_key = f"sensor:{sensor_data.sensor_id}:latest"
await self.redis.setex(cache_key, 3600, json.dumps(reading_doc, default=str))
return {"success": True}
except Exception as e:
logger.error(f"Error ingesting sensor data: {e}")
raise
async def export_data(self, start_time: int, end_time: int, sensor_ids: Optional[str] = None,
format: str = "json") -> Dict[str, Any]:
"""Export sensor data"""
try:
query = {
"timestamp": {"$gte": start_time, "$lte": end_time}
}
if sensor_ids:
sensor_list = [s.strip() for s in sensor_ids.split(",")]
query["sensor_id"] = {"$in": sensor_list}
cursor = self.db.sensor_readings.find(query).sort("timestamp", 1)
readings = []
async for reading in cursor:
reading["_id"] = str(reading["_id"])
readings.append(reading)
return {
"format": format,
"data": readings,
"total_records": len(readings),
"period": {"start": start_time, "end": end_time}
}
except Exception as e:
logger.error(f"Error exporting data: {e}")
raise
async def get_events(self, severity: Optional[str] = None, event_type: Optional[str] = None,
hours: int = 24, limit: int = 50) -> List[Dict[str, Any]]:
"""Get system events"""
try:
start_time = datetime.utcnow() - timedelta(hours=hours)
query = {"timestamp": {"$gte": start_time}}
if severity:
query["severity"] = severity
if event_type:
query["event_type"] = event_type
cursor = self.db.system_events.find(query).sort("timestamp", -1).limit(limit)
events = []
async for event in cursor:
event["_id"] = str(event["_id"])
events.append(event)
return events
except Exception as e:
logger.error(f"Error getting events: {e}")
return []
async def cleanup_old_data(self, cutoff_date: datetime):
"""Clean up old sensor data"""
try:
result = await self.db.sensor_readings.delete_many({
"created_at": {"$lt": cutoff_date}
})
logger.info(f"Cleaned up {result.deleted_count} old sensor readings")
except Exception as e:
logger.error(f"Error cleaning up old data: {e}")
raise