Weather Api 1 — 建筑施工天气数据
v1.0.1用于建筑施工调度的天气数据获取,包括历史数据、预报和户外工作风险评估。帮助您根据天气条件安排施工计划、评估风险和调整生产力。
0· 1,049·4 当前·4 累计
安全扫描
OpenClaw
安全
medium confidence该技能的代码和指令与其声明的目的(获取和评估天气数据)一致,没有请求无关的凭据或安装;内部逻辑一致。
评估建议
该技能在获取和评估建筑施工天气方面内部一致。安装前注意:(1)它向公共天气API(Open-Meteo)发出出站HTTP请求,并会传输位置坐标——如果位置隐私是一个问题,请避免分享精确坐标;(2)提供的Python代码依赖于包(requests、pandas),运行时必须有这些包;(3)包含的_meta.json中有小的元数据/版本不匹配;(4)如任何调用外部服务的技能一样,验证您信任源和运行时的网络策略。如果需要离线操作或更严格的隐私,请请求一个运行在内部天气服务或记录数据保留/使用的变体。...详细分析 ▾
✓ 用途与能力
名称/描述(建筑天气、历史/预报/风险评估)与提供的调用公共天气API(Open-Meteo)的Python客户端代码和包含建筑特定风险阈值一致。没有请求无关的环境变量、二进制文件或配置路径。小提示:_meta.json版本(1.0.0)与注册表版本(1.0.1)不同——可能是包装元数据不匹配,但不是安全红旗。
✓ 指令范围
SKILL.md包含一个完整的Python实现,只执行对公共天气API的HTTP调用、解析响应和计算风险评估。指令/代码不指示读取任意主机文件、其他凭据或无关系统状态。它会在API请求中发送位置坐标(预期用于天气查询)——用户应该意识到位置数据被传输到天气API。
✓ 安装机制
这是一个指令-only技能,没有安装规格和没有由安装程序执行的代码文件。这降低了安装风险。代码依赖于Python包(requests、pandas),这些包没有被声明为所需的二进制文件——代理/运行时必须已经提供它们;这是一个运营考虑但不是不一致。
✓ 凭证需求
没有请求环境变量、凭据或配置路径。技能明智地不要求无关的秘密。它执行对公共API(Open-Meteo)的网络调用,这种实现不需要API密钥。
✓ 持久化与权限
技能不请求持久存在(always: false)并且不尝试修改其他技能或系统范围的设置。模型调用被启用(默认),这是用户可调用技能的正常情况。
安全有层次,运行前请审查代码。
运行时依赖
无特殊依赖
版本
latestv1.0.12026/2/9
内部元数据在_meta.json中更新。没有用户面向或功能变化。
● 无害
安装命令 点击复制
官方npx clawhub@latest install weather-api-1
镜像加速npx clawhub@latest install weather-api-1 --registry https://cn.clawhub-mirror.com
技能文档
请参见下方翻译的SKILL.md内容(由于字符限制,未在此重复粘贴,但应根据原文翻译)
# Weather API for Construction
Overview
Weather impacts 50% of construction activities. This skill fetches weather data for scheduling, risk assessment, and productivity adjustments.Python Implementation
``python
import requests
import pandas as pd
from typing import Dict, Any, List, Optional
from dataclasses import dataclass
from datetime import datetime, timedelta
from enum import Enum
class WeatherRisk(Enum):
"""Weather risk levels for construction."""
LOW = "low"
MODERATE = "moderate"
HIGH = "high"
CRITICAL = "critical"
@dataclass
class WeatherCondition:
"""Weather condition at a point in time."""
timestamp: datetime
temperature: float # Celsius
humidity: float # Percent
wind_speed: float # m/s
precipitation: float # mm
conditions: str
@dataclass
class WorkabilityAssessment:
"""Assessment of weather workability."""
date: datetime
risk_level: WeatherRisk
workable_hours: int
affected_activities: List[str]
recommendations: List[str]
class WeatherAPIClient:
"""Client for weather APIs."""
# Free tier endpoints
OPEN_METEO_BASE = "https://api.open-meteo.com/v1"
def __init__(self, api_key: Optional[str] = None):
self.api_key = api_key
def get_forecast(self, latitude: float, longitude: float,
days: int = 7) -> List[WeatherCondition]:
"""Get weather forecast."""
url = f"{self.OPEN_METEO_BASE}/forecast"
params = {
'latitude': latitude,
'longitude': longitude,
'hourly': 'temperature_2m,relative_humidity_2m,wind_speed_10m,precipitation',
'forecast_days': days
}
response = requests.get(url, params=params)
if response.status_code != 200:
raise Exception(f"API error: {response.status_code}")
data = response.json()
return self._parse_forecast(data)
def get_historical(self, latitude: float, longitude: float,
start_date: str, end_date: str) -> List[WeatherCondition]:
"""Get historical weather data."""
url = f"{self.OPEN_METEO_BASE}/archive"
params = {
'latitude': latitude,
'longitude': longitude,
'start_date': start_date,
'end_date': end_date,
'hourly': 'temperature_2m,relative_humidity_2m,wind_speed_10m,precipitation'
}
response = requests.get(url, params=params)
if response.status_code != 200:
raise Exception(f"API error: {response.status_code}")
data = response.json()
return self._parse_forecast(data)
def _parse_forecast(self, data: Dict) -> List[WeatherCondition]:
"""Parse API response to WeatherCondition list."""
conditions = []
hourly = data.get('hourly', {})
times = hourly.get('time', [])
temps = hourly.get('temperature_2m', [])
humidity = hourly.get('relative_humidity_2m', [])
wind = hourly.get('wind_speed_10m', [])
precip = hourly.get('precipitation', [])
for i in range(len(times)):
conditions.append(WeatherCondition(
timestamp=datetime.fromisoformat(times[i]),
temperature=temps[i] if i < len(temps) else 0,
humidity=humidity[i] if i < len(humidity) else 0,
wind_speed=wind[i] if i < len(wind) else 0,
precipitation=precip[i] if i < len(precip) else 0,
conditions=self._describe_conditions(
temps[i] if i < len(temps) else 0,
precip[i] if i < len(precip) else 0,
wind[i] if i < len(wind) else 0
)
))
return conditions
def _describe_conditions(self, temp: float, precip: float, wind: float) -> str:
"""Generate weather description."""
conditions = []
if temp < 0:
conditions.append("Freezing")
elif temp > 35:
conditions.append("Extreme heat")
elif temp > 30:
conditions.append("Hot")
elif temp < 10:
conditions.append("Cold")
if precip > 10:
conditions.append("Heavy rain")
elif precip > 2:
conditions.append("Rain")
elif precip > 0:
conditions.append("Light rain")
if wind > 15:
conditions.append("Strong winds")
elif wind > 10:
conditions.append("Windy")
return ", ".join(conditions) if conditions else "Clear"
def to_dataframe(self, conditions: List[WeatherCondition]) -> pd.DataFrame:
"""Convert conditions to DataFrame."""
data = [{
'timestamp': c.timestamp,
'temperature': c.temperature,
'humidity': c.humidity,
'wind_speed': c.wind_speed,
'precipitation': c.precipitation,
'conditions': c.conditions
} for c in conditions]
return pd.DataFrame(data)
class ConstructionWeatherRisk:
"""Assess weather risk for construction activities."""
# Activity-specific thresholds
THRESHOLDS = {
'concrete_pour': {
'min_temp': 5, 'max_temp': 35,
'max_wind': 12, 'max_precip': 0.5
},
'crane_work': {
'min_temp': -10, 'max_temp': 40,
'max_wind': 10, 'max_precip': 5
},
'exterior_paint': {
'min_temp': 10, 'max_temp': 35,
'max_wind': 8, 'max_precip': 0
},
'roofing': {
'min_temp': 5, 'max_temp': 38,
'max_wind': 12, 'max_precip': 0
},
'earthwork': {
'min_temp': -5, 'max_temp': 40,
'max_wind': 20, 'max_precip': 10
}
}
def assess_workability(self, condition: WeatherCondition,
activities: List[str] = None) -> WorkabilityAssessment:
"""Assess workability for given conditions."""
if activities is None:
activities = list(self.THRESHOLDS.keys())
affected = []
recommendations = []
for activity in activities:
if activity in self.THRESHOLDS:
thresh = self.THRESHOLDS[activity]
reasons = []
if condition.temperature < thresh['min_temp']:
reasons.append(f"Too cold ({condition.temperature}°C)")
if condition.temperature > thresh['max_temp']:
reasons.append(f"Too hot ({condition.temperature}°C)")
if condition.wind_speed > thresh['max_wind']:
reasons.append(f"High wind ({condition.wind_speed} m/s)")
if condition.precipitation > thresh['max_precip']:
reasons.append(f"Precipitation ({condition.precipitation} mm)")
if reasons:
affected.append(activity)
recommendations.append(f"{activity}: " + ", ".join(reasons))
# Determine overall risk level
if len(affected) >= len(activities) 0.8:
risk = WeatherRisk.CRITICAL
workable = 0
elif len(affected) >= len(activities) 0.5:
risk = WeatherRisk.HIGH
workable = 4
elif len(affected) > 0:
risk = WeatherRisk.MODERATE
workable = 6
else:
risk = WeatherRisk.LOW
workable = 8
return WorkabilityAssessment(
date=condition.timestamp,
risk_level=risk,
workable_hours=workable,
affected_activities=affected,
recommendations=recommendations
)
def weekly_forecast_risk(self, conditions: List[WeatherCondition],
activities: List[str] = None) -> pd.DataFrame:
"""Assess risk for week of weather data."""
# Group by date
daily_conditions = {}
for c in conditions:
date = c.timestamp.date()
if date not in daily_conditions:
daily_conditions[date] = []
daily_conditions[date].append(c)
assessments = []
for date, day_conditions in daily_conditions.items():
# Use midday condition as representative
midday = [c for c in day_conditions
if 10 <= c.timestamp.hour <= 16]
representative = midday[len(midday)//2] if midday else day_conditions[0]
assessment = self.assess_workability(representative, activities)
assessments.append({
'date': date,
'risk_level': assessment.risk_level.value,
'workable_hours': assessment.workable_hours,
'affected_count': len(assessment.affected_activities)
})
return pd.DataFrame(assessments)
`
Quick Start
`python
# Initialize client
weather = WeatherAPIClient()
# Get forecast for site
conditions = weather.get_forecast(latitude=52.52, longitude=13.41, days=7)
df = weather.to_dataframe(conditions)
print(df.head())
# Assess construction risk
risk = ConstructionWeatherRisk()
weekly_risk = risk.weekly_forecast_risk(conditions)
print(weekly_risk)
`
Common Use Cases
1. Schedule Planning
`python
conditions = weather.get_forecast(52.52, 13.41, days=14)
risk = ConstructionWeatherRisk()
# Check concrete pour window
for c in conditions:
assessment = risk.assess_workability(c, ['concrete_pour'])
if assessment.risk_level == WeatherRisk.LOW:
print(f"Good for concrete: {c.timestamp}")
`
2. Historical Analysis
`python
historical = weather.get_historical(52.52, 13.41, '2024-01-01', '2024-03-31')
df = weather.to_dataframe(historical)
# Count rain days
rain_days = df[df['precipitation'] > 2]['timestamp'].dt.date.nunique()
print(f"Rain days in Q1: {rain_days}")
``
Resources
- DDC Book: Chapter 2.2 - Open Data Integration
- Open-Meteo API: https://open-meteo.com/
数据来源:ClawHub ↗ · 中文优化:龙虾技能库
OpenClaw 技能定制 / 插件定制 / 私有工作流定制
免费技能或插件可能存在安全风险,如需更匹配、更安全的方案,建议联系付费定制