#!/usr/bin/env python3 """ Weather Intelligence Pipeline v2 Road Binding → Risk Profiles → Event Generation → Mission Engine """ import sys import json import logging from datetime import datetime from pathlib import Path sys.path.insert(0, '/home/bernt/.openclaw/workspace/life-weather') from providers.weather_provider import WeatherProvider from storage.observation_store import ObservationStore from engine.risk_engine import RiskEngine LOG_DIR = Path("/home/bernt/.openclaw/workspace/life-weather/logs") LOG_DIR.mkdir(exist_ok=True) logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler(LOG_DIR / "pipeline_v2.log"), logging.StreamHandler() ] ) logger = logging.getLogger(__name__) class RoadBinding: """Steg 1: Koppla väg till väderobservation""" def __init__(self, store): self.store = store def bind_road(self, road_id, weather_data): """Koppla väg till väderobservation""" logger.info(f"Road {road_id}: Binding to weather observation") observations = [] if weather_data.get("temperature"): obs_id = self.store.save_observation( road_id=road_id, observation_type="temperature", value=weather_data["temperature"]["value"], unit="celsius", timestamp=weather_data["timestamp"], raw_data=weather_data["temperature"] ) if obs_id: observations.append(obs_id) if weather_data.get("precipitation"): obs_id = self.store.save_observation( road_id=road_id, observation_type="precipitation", value=weather_data["precipitation"]["value"], unit="mm", timestamp=weather_data["timestamp"], raw_data=weather_data["precipitation"] ) if obs_id: observations.append(obs_id) if weather_data.get("wind"): obs_id = self.store.save_observation( road_id=road_id, observation_type="wind", value=weather_data["wind"]["value"], unit="m/s", timestamp=weather_data["timestamp"], raw_data=weather_data["wind"] ) if obs_id: observations.append(obs_id) return { "road_id": road_id, "observations": observations, "timestamp": weather_data["timestamp"] } class RiskProfile: """Steg 2: Skapa riskprofil för väg""" def __init__(self, engine): self.engine = engine def create_profile(self, road_id, road_type, weather_data): """Skapa riskprofil""" logger.info(f"Road {road_id}: Creating risk profile") temp = weather_data.get("temperature", {}).get("value") if weather_data.get("temperature") else None precip = weather_data.get("precipitation", {}).get("value") if weather_data.get("precipitation") else None wind = weather_data.get("wind", {}).get("value") if weather_data.get("wind") else None risks = self.engine.calculate_risk(road_id, road_type, temp, precip, wind) profile = { "road_id": road_id, "road_type": road_type, "timestamp": weather_data["timestamp"], "weather": { "temperature": temp, "precipitation": precip, "wind": wind }, "risks": [ { "type": r.risk_type, "severity": r.severity, "score": r.score, "description": r.description } for r in risks ], "risk_count": len(risks), "max_severity": max([r.severity for r in risks], key=lambda x: {"low": 1, "medium": 2, "high": 3, "critical": 4}.get(x, 0)) if risks else "none" } return profile class EventGenerator: """Steg 3: Generera händelser från risker""" def __init__(self): self.events = [] def generate_events(self, risk_profile): """Generera händelser från riskprofil""" road_id = risk_profile["road_id"] risks = risk_profile["risks"] events = [] for risk in risks: if risk["severity"] in ["high", "critical"]: event = { "event_id": f"evt_{road_id}_{risk['type']}_{datetime.now().strftime('%Y%m%d_%H%M%S')}", "road_id": road_id, "event_type": risk["type"], "severity": risk["severity"], "description": risk["description"], "timestamp": risk_profile["timestamp"], "status": "active", "requires_verification": True } events.append(event) logger.info(f"Road {road_id}: Generated event {event['event_id']}") return events class MissionEngine: """Steg 4: Generera missions från events""" def __init__(self): self.missions = [] def generate_missions(self, events): """Generera missions från events""" missions = [] for event in events: if event["requires_verification"]: mission = { "mission_id": f"mission_{event['event_id']}", "event_id": event["event_id"], "road_id": event["road_id"], "mission_type": "verification", "description": f"Verify {event['event_type']} on road {event['road_id']}", "priority": event["severity"], "status": "pending", "created_at": event["timestamp"], "target": "quixzoom" # Skicka till quiXzoom } missions.append(mission) logger.info(f"Road {event['road_id']}: Generated mission {mission['mission_id']}") return missions class WeatherPipelineV2: """Huvudpipeline""" def __init__(self): self.provider = WeatherProvider() self.store = ObservationStore() self.engine = RiskEngine() self.road_binding = RoadBinding(self.store) self.risk_profile = RiskProfile(self.engine) self.event_generator = EventGenerator() self.mission_engine = MissionEngine() def run_for_road(self, road_id, road_type="primary"): """Kör pipeline för en väg""" logger.info(f"=== Pipeline for Road {road_id} ===") # Steg 0: Hämta väderdata weather = self.provider.get_current_weather() if not weather.get("temperature"): logger.error("No weather data available") return None # Steg 1: Road Binding binding = self.road_binding.bind_road(road_id, weather) # Steg 2: Risk Profile profile = self.risk_profile.create_profile(road_id, road_type, weather) # Steg 3: Event Generation events = self.event_generator.generate_events(profile) # Steg 4: Mission Engine missions = self.mission_engine.generate_missions(events) result = { "road_id": road_id, "timestamp": weather["timestamp"], "binding": binding, "profile": profile, "events": events, "missions": missions } logger.info(f"Road {road_id}: Pipeline complete - {len(events)} events, {len(missions)} missions") return result if __name__ == "__main__": pipeline = WeatherPipelineV2() # Kör för första vägen result = pipeline.run_for_road(road_id=1, road_type="primary") if result: print(json.dumps(result, indent=2))