#!/usr/bin/env python3 """ Bootstrap script to populate the database with sensors and room configurations. This script creates a realistic smart building sensor setup for testing and development. """ import asyncio import json import sys import logging from datetime import datetime from typing import List, Dict, Any import aiohttp # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Base URLs API_BASE_URL = "http://localhost:8000" SENSOR_SERVICE_URL = "http://localhost:8007" s = { 'id': 'sensor_1', 'name': 'Energy Monitor 1', 'type': 'energy', 'room': 'Conference Room A', 'status': 'online', 'lastSeen': Date.now() / 1000, 'capabilities': { 'monitoring': ['energy'], 'actions': [], }, 'metadata': { 'location': 'Wall mounted', 'model': 'EM-100', 'firmware': '2.1.0', }, },{ 'id': 'sensor_2', 'name': 'HVAC Controller 1', 'type': 'hvac', 'room': 'Conference Room A', 'status': 'online', 'lastSeen': Date.now() / 1000, 'capabilities': { 'monitoring': ['temperature', 'co2'], 'actions': [ { 'id': 'temp_adjust', 'name': 'Adjust Temperature', 'type': 'adjust', 'icon': '🌡️', 'parameters': { min: 18, max: 28, step: 0.5 }, }, { 'id': 'fan_speed', 'name': 'Fan Speed', 'type': 'adjust', 'icon': '💨', 'parameters': { min: 0, max: 5, step: 1 }, }, { 'id': 'power_toggle', 'name': 'Power', 'type': 'toggle', 'icon': '⚡' }, ], }, metadata: { location: 'Ceiling mounted', model: 'HVAC-200', firmware: '3.2.1', }, }, { id: 'sensor_3', name: 'Smart Light Controller', type: 'lighting', room: 'Office Floor 1', status: 'online', lastSeen: Date.now() / 1000, capabilities: { monitoring: ['energy'], actions: [ { id: 'brightness', name: 'Brightness', type: 'adjust', icon: '💡', parameters: { min: 0, max: 100, step: 5 }, }, { id: 'power_toggle', name: 'Power', type: 'toggle', icon: '⚡' }, { id: 'scene', name: 'Scene', type: 'adjust', icon: '🎨', parameters: { options: ['Work', 'Meeting', 'Presentation', 'Relax'] }, }, ], }, metadata: { location: 'Ceiling grid', model: 'SL-300', firmware: '1.5.2', }, }, { id: 'sensor_4', name: 'CO2 Sensor', type: 'co2', room: 'Meeting Room 1', status: 'online', lastSeen: Date.now() / 1000, capabilities: { monitoring: ['co2', 'temperature', 'humidity'], actions: [{ id: 'calibrate', name: 'Calibrate', type: 'trigger', icon: '⚙️' }], }, metadata: { location: 'Wall mounted', model: 'CO2-150', firmware: '2.0.3', battery: 85, }, }, { id: 'sensor_5', name: 'Security Camera', type: 'security', room: 'Lobby', status: 'online', lastSeen: Date.now() / 1000, capabilities: { monitoring: ['motion'], actions: [ { id: 'record_toggle', name: 'Recording', type: 'toggle', icon: '📹' }, { id: 'ptz_control', name: 'Pan/Tilt/Zoom', type: 'trigger', icon: '🎥' }, { id: 'night_mode', name: 'Night Mode', type: 'toggle', icon: '🌙' }, ], }, metadata: { location: 'Corner ceiling', model: 'SEC-400', firmware: '4.1.0', }, }, # Bootstrap data configuration BOOTSTRAP_SENSORS = [ # Living Room Sensors { "sensor_id": "lr_energy_001", "name": "Living Room Main Energy Monitor", "sensor_type": "energy", "room": "living_room", "location": "Main electrical panel - Living Room circuit", "floor": "1", "manufacturer": "SmartMeter Co", "model": "SM-E300", "status": "online" }, { "sensor_id": "lr_co2_001", "name": "Living Room Air Quality Monitor", "sensor_type": "co2", "room": "living_room", "location": "Wall mounted near seating area", "floor": "1", "manufacturer": "AirSense", "model": "AS-CO2-Pro", "status": "online" }, { "sensor_id": "lr_temp_001", "name": "Living Room Temperature Sensor", "sensor_type": "temperature", "room": "living_room", "location": "Central wall position", "floor": "1", "manufacturer": "TempTech", "model": "TT-T200", "status": "online" }, # Kitchen Sensors { "sensor_id": "kt_energy_001", "name": "Kitchen Appliances Energy Monitor", "sensor_type": "energy", "room": "kitchen", "location": "Kitchen appliance circuit", "floor": "1", "manufacturer": "SmartMeter Co", "model": "SM-E300", "status": "online" }, { "sensor_id": "kt_humidity_001", "name": "Kitchen Humidity Sensor", "sensor_type": "humidity", "room": "kitchen", "location": "Above sink area", "floor": "1", "manufacturer": "HumidSense", "model": "HS-H150", "status": "online" }, { "sensor_id": "kt_temp_001", "name": "Kitchen Temperature Monitor", "sensor_type": "temperature", "room": "kitchen", "location": "Central kitchen position", "floor": "1", "manufacturer": "TempTech", "model": "TT-T200", "status": "online" }, # Bedroom Sensors { "sensor_id": "br_energy_001", "name": "Bedroom Energy Monitor", "sensor_type": "energy", "room": "bedroom", "location": "Bedroom electrical circuit", "floor": "1", "manufacturer": "SmartMeter Co", "model": "SM-E200", "status": "online" }, { "sensor_id": "br_co2_001", "name": "Bedroom Air Quality Monitor", "sensor_type": "co2", "room": "bedroom", "location": "Bedside wall mount", "floor": "1", "manufacturer": "AirSense", "model": "AS-CO2-Basic", "status": "online" }, { "sensor_id": "br_temp_001", "name": "Bedroom Temperature Sensor", "sensor_type": "temperature", "room": "bedroom", "location": "Opposite wall from bed", "floor": "1", "manufacturer": "TempTech", "model": "TT-T100", "status": "online" }, # Office Sensors { "sensor_id": "of_energy_001", "name": "Office Equipment Energy Monitor", "sensor_type": "energy", "room": "office", "location": "Office equipment circuit", "floor": "1", "manufacturer": "SmartMeter Co", "model": "SM-E300", "status": "online" }, { "sensor_id": "of_co2_001", "name": "Office Air Quality Monitor", "sensor_type": "co2", "room": "office", "location": "Desk area wall mount", "floor": "1", "manufacturer": "AirSense", "model": "AS-CO2-Pro", "status": "online" }, { "sensor_id": "of_motion_001", "name": "Office Motion Detector", "sensor_type": "motion", "room": "office", "location": "Ceiling mounted - center", "floor": "1", "manufacturer": "MotionTech", "model": "MT-M100", "status": "online" }, # Bathroom Sensors { "sensor_id": "bt_humidity_001", "name": "Bathroom Humidity Monitor", "sensor_type": "humidity", "room": "bathroom", "location": "Ceiling mounted", "floor": "1", "manufacturer": "HumidSense", "model": "HS-H200", "status": "online" }, { "sensor_id": "bt_temp_001", "name": "Bathroom Temperature Sensor", "sensor_type": "temperature", "room": "bathroom", "location": "Wall mounted near mirror", "floor": "1", "manufacturer": "TempTech", "model": "TT-T150", "status": "online" }, # Garage Sensors { "sensor_id": "gr_energy_001", "name": "Garage Energy Monitor", "sensor_type": "energy", "room": "garage", "location": "Garage main circuit", "floor": "0", "manufacturer": "SmartMeter Co", "model": "SM-E100", "status": "online" }, { "sensor_id": "gr_motion_001", "name": "Garage Motion Detector", "sensor_type": "motion", "room": "garage", "location": "Ceiling mounted - entrance", "floor": "0", "manufacturer": "MotionTech", "model": "MT-M200", "status": "online" } ] BOOTSTRAP_ROOMS = [ { "name": "living_room", "display_name": "Living Room", "description": "Main living area with entertainment center", "floor": "1", "area_sqm": 35.5, "room_type": "living" }, { "name": "kitchen", "display_name": "Kitchen", "description": "Main kitchen with appliances", "floor": "1", "area_sqm": 15.2, "room_type": "kitchen" }, { "name": "bedroom", "display_name": "Master Bedroom", "description": "Primary bedroom", "floor": "1", "area_sqm": 20.1, "room_type": "bedroom" }, { "name": "office", "display_name": "Home Office", "description": "Work from home office space", "floor": "1", "area_sqm": 12.8, "room_type": "office" }, { "name": "bathroom", "display_name": "Main Bathroom", "description": "Primary bathroom", "floor": "1", "area_sqm": 8.5, "room_type": "bathroom" }, { "name": "garage", "display_name": "Garage", "description": "Two-car garage with workshop area", "floor": "0", "area_sqm": 42.0, "room_type": "garage" } ] async def generate_auth_token() -> str: """Generate authentication token for API calls""" token_payload = { "name": "bootstrap_user", "list_of_resources": ["sensors", "rooms", "analytics", "health", "data", "export", "events"], "data_aggregation": True, "time_aggregation": True, "embargo": 0, "exp_hours": 24 } async with aiohttp.ClientSession() as session: async with session.post( f"{API_BASE_URL}/api/v1/tokens/generate", json=token_payload, headers={"Content-Type": "application/json"} ) as response: if response.status == 200: data = await response.json() logger.info("Successfully generated authentication token") return data["token"] else: error_text = await response.text() raise Exception(f"Failed to generate token: {response.status} - {error_text}") async def create_rooms(auth_token: str) -> bool: """Create rooms in the database""" logger.info("Creating bootstrap rooms...") headers = { "Authorization": f"Bearer {auth_token}", "Content-Type": "application/json" } success_count = 0 async with aiohttp.ClientSession() as session: for room in BOOTSTRAP_ROOMS: try: async with session.post( f"{SENSOR_SERVICE_URL}/rooms", json=room, headers=headers ) as response: if response.status in [200, 201]: success_count += 1 logger.info(f"✓ Created room: {room['display_name']}") elif response.status == 400: # Room might already exist error_data = await response.json() if "already exists" in error_data.get("detail", ""): logger.info(f"○ Room already exists: {room['display_name']}") success_count += 1 else: logger.error(f"✗ Failed to create room {room['name']}: {error_data}") else: error_text = await response.text() logger.error(f"✗ Failed to create room {room['name']}: {response.status} - {error_text}") except Exception as e: logger.error(f"✗ Exception creating room {room['name']}: {e}") logger.info(f"Rooms created: {success_count}/{len(BOOTSTRAP_ROOMS)}") return success_count > 0 async def create_sensors(auth_token: str) -> bool: """Create sensors in the database""" logger.info("Creating bootstrap sensors...") headers = { "Authorization": f"Bearer {auth_token}", "Content-Type": "application/json" } success_count = 0 async with aiohttp.ClientSession() as session: for sensor in BOOTSTRAP_SENSORS: try: async with session.post( f"{SENSOR_SERVICE_URL}/sensors", json=sensor, headers=headers ) as response: if response.status in [200, 201]: success_count += 1 logger.info(f"✓ Created sensor: {sensor['name']} ({sensor['sensor_id']})") elif response.status == 400: # Sensor might already exist error_data = await response.json() if "already exists" in error_data.get("detail", ""): logger.info(f"○ Sensor already exists: {sensor['sensor_id']}") success_count += 1 else: logger.error(f"✗ Failed to create sensor {sensor['sensor_id']}: {error_data}") else: error_text = await response.text() logger.error(f"✗ Failed to create sensor {sensor['sensor_id']}: {response.status} - {error_text}") except Exception as e: logger.error(f"✗ Exception creating sensor {sensor['sensor_id']}: {e}") logger.info(f"Sensors created: {success_count}/{len(BOOTSTRAP_SENSORS)}") return success_count > 0 async def verify_bootstrap() -> None: """Verify that sensors were created successfully""" logger.info("Verifying bootstrap results...") try: # Check sensors directly on sensor service (no auth required for health checks) async with aiohttp.ClientSession() as session: async with session.get(f"{SENSOR_SERVICE_URL}/sensors/get") as response: if response.status == 200: data = await response.json() logger.info(f"✓ Total sensors in database: {data['count']}") # Group by room rooms = {} for sensor in data.get('sensors', []): room = sensor.get('room', 'unknown') if room not in rooms: rooms[room] = [] rooms[room].append(sensor['sensor_id']) for room, sensors in rooms.items(): logger.info(f" - {room}: {len(sensors)} sensors") else: logger.error(f"Failed to verify sensors: {response.status}") async with session.get(f"{SENSOR_SERVICE_URL}/rooms") as response: if response.status == 200: data = await response.json() logger.info(f"✓ Total rooms in database: {data.get('count', 0)}") else: logger.error(f"Failed to verify rooms: {response.status}") except Exception as e: logger.error(f"✗ Exception during verification: {e}") async def main(): """Main bootstrap function""" logger.info("=== Starting Sensor Bootstrap Process ===") try: # Step 1: Generate authentication token logger.info("Step 1: Generating authentication token...") auth_token = await generate_auth_token() # Step 2: Create rooms logger.info("Step 2: Creating rooms...") rooms_success = await create_rooms(auth_token) # Step 3: Create sensors logger.info("Step 3: Creating sensors...") sensors_success = await create_sensors(auth_token) # Step 4: Verify results logger.info("Step 4: Verifying bootstrap...") await verify_bootstrap() if rooms_success and sensors_success: logger.info("=== Bootstrap Complete! ===") logger.info("You can now run the data simulator to generate real-time sensor data.") logger.info("Run: python data_simulator_enhanced.py") return True else: logger.error("=== Bootstrap Failed ===") return False except Exception as e: logger.error(f"Bootstrap failed with error: {e}") return False if __name__ == "__main__": # Run the bootstrap success = asyncio.run(main()) sys.exit(0 if success else 1)