weather-plus
Get current weather, multi-day forecasts, clothing index, and feels-like temperature. No API key required. Use when a user wants to: (1) Check current weather, (2) View multi-day forecasts, (3) Get clothing/dressing recommendations, (4) Check feels-like temperature and comfort index. Supports any city worldwide. Integrates SkillPay.me at 0.001 USDT/call.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install openclaw-skills-weather-plus
Repository
Skill path: skills/elevo11/weather-plus
Get current weather, multi-day forecasts, clothing index, and feels-like temperature. No API key required. Use when a user wants to: (1) Check current weather, (2) View multi-day forecasts, (3) Get clothing/dressing recommendations, (4) Check feels-like temperature and comfort index. Supports any city worldwide. Integrates SkillPay.me at 0.001 USDT/call.
Open repositoryBest for
Primary workflow: Ship Full Stack.
Technical facets: Full Stack, Backend.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: openclaw.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install weather-plus into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/openclaw/skills before adding weather-plus to shared team environments
- Use weather-plus for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: weather-plus
description: >
Get current weather, multi-day forecasts, clothing index, and feels-like temperature.
No API key required. Use when a user wants to: (1) Check current weather,
(2) View multi-day forecasts, (3) Get clothing/dressing recommendations,
(4) Check feels-like temperature and comfort index.
Supports any city worldwide. Integrates SkillPay.me at 0.001 USDT/call.
---
# Weather Plus
Weather, forecasts, clothing index & feels-like temperature. No API key needed. 0.001 USDT/call.
## Commands
| Command | Script | Description |
|:---|:---|:---|
| **weather** | `scripts/weather.py` | Current weather + feels-like |
| **forecast** | `scripts/forecast.py` | Multi-day forecast (up to 7 days) |
| **clothing** | `scripts/clothing.py` | Clothing/dressing index + recommendations |
| **billing** | `scripts/billing.py` | SkillPay charge/balance/payment |
## Workflow
```
1. Billing: python3 scripts/billing.py --charge --user-id <id>
2. Weather: python3 scripts/weather.py --city "Beijing"
3. Forecast: python3 scripts/forecast.py --city "Shanghai" --days 5
4. Clothing: python3 scripts/clothing.py --city "Chengdu"
```
## Examples
```bash
# Current weather
python3 scripts/weather.py --city "New York"
python3 scripts/weather.py --city "成都"
# Multi-day forecast
python3 scripts/forecast.py --city "Tokyo" --days 7
# Clothing index
python3 scripts/clothing.py --city "Beijing"
python3 scripts/clothing.py --city "London"
```
## Config
| Env Var | Required | Description |
|:---|:---:|:---|
| `SKILLPAY_API_KEY` | Yes | SkillPay.me API key |
## References
See `references/clothing-index.md` for dressing recommendation methodology.
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### scripts/billing.py
```python
#!/usr/bin/env python3
"""SkillPay.me billing for weather-plus."""
import json, sys, argparse, os
import urllib.request, urllib.error
API = "https://skillpay.me/api/v1"
SKILL_ID = "5f80663e-942f-4fd5-aaad-ecdf869658a9"
def _key(o=None):
return o or os.environ.get("SKILLPAY_API_KEY")
def _post(path, body, key):
req = urllib.request.Request(f"{API}{path}", data=json.dumps(body).encode(),
headers={"Content-Type": "application/json", "X-API-Key": key}, method="POST")
try:
with urllib.request.urlopen(req, timeout=15) as r: return json.loads(r.read())
except urllib.error.HTTPError as e: return json.loads(e.read())
def _get(path, key):
req = urllib.request.Request(f"{API}{path}", headers={"X-API-Key": key})
try:
with urllib.request.urlopen(req, timeout=15) as r: return json.loads(r.read())
except urllib.error.HTTPError as e: return json.loads(e.read())
def charge(uid, amount=0.001, key=None):
k = _key(key)
if not k: return {"success": False, "error": "SKILLPAY_API_KEY not set"}
d = _post("/billing/charge", {"user_id": uid, "skill_id": SKILL_ID, "amount": amount,
"currency": "USDT", "description": "Weather Plus"}, k)
if d.get("success"): return {"success": True, "charged": amount, "data": d}
return {"success": False, "needs_payment": bool(d.get("payment_url")),
"payment_url": d.get("payment_url", ""), "balance": d.get("balance", 0),
"message": d.get("message", "charge failed")}
def balance(uid, key=None):
k = _key(key)
if not k: return {"success": False, "error": "SKILLPAY_API_KEY not set"}
return {"success": True, "data": _get(f"/billing/balance?user_id={uid}", k)}
def payment_link(uid, amount=5.0, key=None):
k = _key(key)
if not k: return {"success": False, "error": "SKILLPAY_API_KEY not set"}
return {"success": True, "data": _post("/billing/payment-link",
{"user_id": uid, "skill_id": SKILL_ID, "Amount": amount}, k)}
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("--user-id", required=True)
p.add_argument("--amount", type=float, default=0.001)
p.add_argument("--api-key", default=None)
g = p.add_mutually_exclusive_group()
g.add_argument("--charge", action="store_true", default=True)
g.add_argument("--balance", action="store_true")
g.add_argument("--payment-link", action="store_true")
a = p.parse_args()
if a.balance: r = balance(a.user_id, a.api_key)
elif a.payment_link: r = payment_link(a.user_id, a.amount or 5.0, a.api_key)
else: r = charge(a.user_id, a.amount, a.api_key)
print(json.dumps(r, indent=2, ensure_ascii=False))
sys.exit(0 if r.get("success") else 1)
```
### scripts/weather.py
```python
#!/usr/bin/env python3
"""Current weather via wttr.in (no API key needed)."""
import argparse, json, sys, urllib.request, urllib.parse
def get_weather(city):
"""Fetch current weather from wttr.in."""
encoded = urllib.parse.quote(city)
url = f"https://wttr.in/{encoded}?format=j1"
req = urllib.request.Request(url, headers={"User-Agent": "curl/7.68.0"})
with urllib.request.urlopen(req, timeout=15) as r:
data = json.loads(r.read())
current = data.get("current_condition", [{}])[0]
area = data.get("nearest_area", [{}])[0]
# Extract data
temp_c = int(current.get("temp_C", 0))
feels_c = int(current.get("FeelsLikeC", 0))
humidity = int(current.get("humidity", 0))
wind_kmph = int(current.get("windspeedKmph", 0))
wind_dir = current.get("winddir16Point", "")
visibility = current.get("visibility", "N/A")
uv_index = current.get("uvIndex", "N/A")
pressure = current.get("pressure", "N/A")
cloud_cover = current.get("cloudcover", "N/A")
precip = current.get("precipMM", "0")
desc = current.get("weatherDesc", [{}])[0].get("value", "N/A")
city_name = area.get("areaName", [{}])[0].get("value", city)
country = area.get("country", [{}])[0].get("value", "")
region = area.get("region", [{}])[0].get("value", "")
# Weather emoji
emoji = _weather_emoji(desc, temp_c)
return {
"city": city_name,
"country": country,
"region": region,
"description": desc,
"emoji": emoji,
"temperature": temp_c,
"feels_like": feels_c,
"humidity": humidity,
"wind_speed": wind_kmph,
"wind_direction": wind_dir,
"visibility": visibility,
"uv_index": uv_index,
"pressure": pressure,
"cloud_cover": cloud_cover,
"precipitation": precip,
"comfort": _comfort_level(temp_c, humidity, wind_kmph),
}
def _weather_emoji(desc, temp):
desc_l = desc.lower()
if "sun" in desc_l or "clear" in desc_l: return "☀️"
if "cloud" in desc_l and "part" in desc_l: return "⛅"
if "cloud" in desc_l or "overcast" in desc_l: return "☁️"
if "rain" in desc_l and "heavy" in desc_l: return "🌧️"
if "rain" in desc_l or "drizzle" in desc_l: return "🌦️"
if "snow" in desc_l: return "❄️"
if "thunder" in desc_l: return "⛈️"
if "fog" in desc_l or "mist" in desc_l: return "🌫️"
if temp > 35: return "🥵"
if temp < 0: return "🥶"
return "🌤️"
def _comfort_level(temp, humidity, wind):
"""Calculate comfort level."""
if 18 <= temp <= 26 and humidity < 70:
return {"level": "舒适", "icon": "😊", "score": 5}
elif 15 <= temp <= 30 and humidity < 80:
return {"level": "较舒适", "icon": "🙂", "score": 4}
elif 10 <= temp <= 35:
return {"level": "一般", "icon": "😐", "score": 3}
elif 0 <= temp <= 40:
return {"level": "不舒适", "icon": "😣", "score": 2}
else:
return {"level": "极端", "icon": "⚠️", "score": 1}
def format_output(data):
lines = [
f"{data['emoji']} {data['city']}, {data['country']} — {data['description']}",
"",
f"🌡️ 温度:{data['temperature']}°C",
f"🤗 体感:{data['feels_like']}°C",
f"💧 湿度:{data['humidity']}%",
f"💨 风速:{data['wind_speed']} km/h {data['wind_direction']}",
f"👁️ 能见度:{data['visibility']} km",
f"☀️ UV指数:{data['uv_index']}",
f"🌡️ 气压:{data['pressure']} hPa",
f"☁️ 云量:{data['cloud_cover']}%",
f"🌧️ 降水:{data['precipitation']} mm",
"",
f"{data['comfort']['icon']} 舒适度:{data['comfort']['level']} ({data['comfort']['score']}/5)",
]
return "\n".join(lines)
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("--city", required=True, help="City name")
p.add_argument("--json", action="store_true")
a = p.parse_args()
data = get_weather(a.city)
print(json.dumps(data, indent=2, ensure_ascii=False) if a.json else format_output(data))
```
### scripts/forecast.py
```python
#!/usr/bin/env python3
"""Multi-day weather forecast via wttr.in."""
import argparse, json, sys, urllib.request, urllib.parse
def get_forecast(city, days=5):
encoded = urllib.parse.quote(city)
url = f"https://wttr.in/{encoded}?format=j1"
req = urllib.request.Request(url, headers={"User-Agent": "curl/7.68.0"})
with urllib.request.urlopen(req, timeout=15) as r:
data = json.loads(r.read())
area = data.get("nearest_area", [{}])[0]
city_name = area.get("areaName", [{}])[0].get("value", city)
country = area.get("country", [{}])[0].get("value", "")
forecasts = []
for day in data.get("weather", [])[:days]:
date = day.get("date", "")
max_c = int(day.get("maxtempC", 0))
min_c = int(day.get("mintempC", 0))
avg_c = (max_c + min_c) // 2
sun_hours = day.get("sunHour", "N/A")
uv = day.get("uvIndex", "N/A")
# Hourly details - use noon for description
hourly = day.get("hourly", [])
noon = hourly[4] if len(hourly) > 4 else hourly[0] if hourly else {}
desc = noon.get("weatherDesc", [{}])[0].get("value", "N/A")
humidity = noon.get("humidity", "N/A")
wind = noon.get("windspeedKmph", "N/A")
feels = noon.get("FeelsLikeC", avg_c)
precip = noon.get("precipMM", "0")
chance_rain = noon.get("chanceofrain", "0")
forecasts.append({
"date": date,
"description": desc,
"max_temp": max_c,
"min_temp": min_c,
"avg_temp": avg_c,
"feels_like": int(feels),
"humidity": humidity,
"wind": wind,
"precipitation": precip,
"chance_rain": chance_rain,
"sun_hours": sun_hours,
"uv_index": uv,
})
return {
"city": city_name,
"country": country,
"days": len(forecasts),
"forecasts": forecasts,
}
def _day_emoji(desc, max_t):
d = desc.lower()
if "sun" in d or "clear" in d: return "☀️"
if "cloud" in d and "part" in d: return "⛅"
if "cloud" in d: return "☁️"
if "rain" in d: return "🌧️"
if "snow" in d: return "❄️"
if "thunder" in d: return "⛈️"
return "🌤️"
def format_output(data):
lines = [f"📅 {data['city']}, {data['country']} — {data['days']}天预报", ""]
for f in data["forecasts"]:
emoji = _day_emoji(f["description"], f["max_temp"])
lines.append(f"{emoji} {f['date']} {f['description']}")
lines.append(f" 🌡️ {f['min_temp']}°C ~ {f['max_temp']}°C 体感:{f['feels_like']}°C")
lines.append(f" 💧 湿度:{f['humidity']}% 🌧️ 降雨概率:{f['chance_rain']}% 降水:{f['precipitation']}mm")
lines.append(f" 💨 风速:{f['wind']} km/h ☀️ UV:{f['uv_index']} 日照:{f['sun_hours']}h")
lines.append("")
return "\n".join(lines)
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("--city", required=True)
p.add_argument("--days", type=int, default=5)
p.add_argument("--json", action="store_true")
a = p.parse_args()
data = get_forecast(a.city, min(a.days, 7))
print(json.dumps(data, indent=2, ensure_ascii=False) if a.json else format_output(data))
```
### scripts/clothing.py
```python
#!/usr/bin/env python3
"""Clothing index and dressing recommendations based on weather."""
import argparse, json, sys, os
sys.path.insert(0, os.path.dirname(__file__))
from weather import get_weather
# Clothing index levels
CLOTHING_INDEX = [
{"range": (-999, -10), "level": 1, "name": "极寒", "icon": "🧥",
"clothes": "厚羽绒服、棉裤、雪地靴、围巾、手套、帽子、口罩",
"tip": "极寒天气,减少外出,注意防冻"},
{"range": (-10, 0), "level": 2, "name": "严寒", "icon": "🧥",
"clothes": "羽绒服、厚毛衣、棉裤、棉鞋、围巾、手套",
"tip": "寒冷刺骨,务必做好全身保暖"},
{"range": (0, 5), "level": 3, "name": "寒冷", "icon": "🧥",
"clothes": "厚外套/大衣、毛衣、保暖内衣、厚裤、靴子",
"tip": "天气寒冷,注意保暖防寒"},
{"range": (5, 10), "level": 4, "name": "冷", "icon": "🧶",
"clothes": "外套/风衣、薄毛衣、长裤、运动鞋",
"tip": "天气较冷,适当增加衣物"},
{"range": (10, 15), "level": 5, "name": "凉", "icon": "🧶",
"clothes": "薄外套/夹克、长袖衬衫、长裤",
"tip": "天气偏凉,早晚温差大注意添衣"},
{"range": (15, 20), "level": 6, "name": "舒适偏凉", "icon": "👔",
"clothes": "长袖衬衫/薄卫衣、休闲裤、薄外套备用",
"tip": "较舒适,建议备一件薄外套"},
{"range": (20, 25), "level": 7, "name": "舒适", "icon": "👕",
"clothes": "T恤/短袖衬衫、薄长裤/裙子",
"tip": "天气舒适,穿着轻便即可"},
{"range": (25, 30), "level": 8, "name": "温暖", "icon": "👕",
"clothes": "短袖、短裤/短裙、凉鞋",
"tip": "天气温暖,注意防晒"},
{"range": (30, 35), "level": 9, "name": "炎热", "icon": "🩳",
"clothes": "轻薄透气衣物、短裤、凉鞋、遮阳帽、防晒霜",
"tip": "天气炎热,注意防暑降温,多喝水"},
{"range": (35, 999), "level": 10, "name": "酷热", "icon": "🥵",
"clothes": "最轻薄透气衣物,避免户外活动",
"tip": "极端高温,避免长时间户外活动,注意中暑"},
]
def get_clothing_index(city):
"""Get clothing recommendation based on current weather."""
weather = get_weather(city)
feels_like = weather["feels_like"]
temp = weather["temperature"]
humidity = weather["humidity"]
wind = weather["wind_speed"]
# Find matching clothing level (use feels_like for better accuracy)
clothing = None
for c in CLOTHING_INDEX:
if c["range"][0] <= feels_like < c["range"][1]:
clothing = c
break
if not clothing:
clothing = CLOTHING_INDEX[-1]
# UV protection advice
uv = int(weather.get("uv_index", 0))
uv_advice = ""
if uv >= 8:
uv_advice = "⚠️ UV极强!务必涂防晒霜、戴墨镜和遮阳帽"
elif uv >= 6:
uv_advice = "☀️ UV较强,建议涂防晒霜、戴遮阳帽"
elif uv >= 3:
uv_advice = "🧴 UV中等,建议涂防晒霜"
# Rain advice
precip = float(weather.get("precipitation", 0))
rain_advice = ""
if precip > 5:
rain_advice = "🌧️ 降水较大,建议携带雨伞和防水鞋"
elif precip > 0:
rain_advice = "🌂 可能有小雨,建议携带雨伞"
# Wind advice
wind_advice = ""
if wind > 40:
wind_advice = "🌪️ 风力很大,注意安全,避免高处"
elif wind > 25:
wind_advice = "💨 风力较大,注意防风"
return {
"city": weather["city"],
"country": weather["country"],
"weather": weather["description"],
"weather_emoji": weather["emoji"],
"temperature": temp,
"feels_like": feels_like,
"humidity": humidity,
"wind_speed": wind,
"clothing_index": clothing["level"],
"clothing_name": clothing["name"],
"clothing_icon": clothing["icon"],
"clothes": clothing["clothes"],
"tip": clothing["tip"],
"uv_advice": uv_advice,
"rain_advice": rain_advice,
"wind_advice": wind_advice,
"comfort": weather["comfort"],
}
def format_output(data):
lines = [
f"{data['weather_emoji']} {data['city']}, {data['country']} — {data['weather']}",
"",
f"🌡️ 温度:{data['temperature']}°C | 体感:{data['feels_like']}°C",
f"💧 湿度:{data['humidity']}% | 💨 风速:{data['wind_speed']} km/h",
"",
f"{'='*40}",
f"{data['clothing_icon']} 穿衣指数:{data['clothing_index']}/10 — {data['clothing_name']}",
f"{'='*40}",
"",
f"👗 推荐穿搭:{data['clothes']}",
f"💡 温馨提示:{data['tip']}",
]
extras = []
if data["uv_advice"]:
extras.append(data["uv_advice"])
if data["rain_advice"]:
extras.append(data["rain_advice"])
if data["wind_advice"]:
extras.append(data["wind_advice"])
if extras:
lines.append("")
lines.append("📌 特别提醒:")
for e in extras:
lines.append(f" {e}")
lines.append("")
lines.append(f"{data['comfort']['icon']} 舒适度:{data['comfort']['level']} ({data['comfort']['score']}/5)")
return "\n".join(lines)
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("--city", required=True)
p.add_argument("--json", action="store_true")
a = p.parse_args()
data = get_clothing_index(a.city)
print(json.dumps(data, indent=2, ensure_ascii=False) if a.json else format_output(data))
```
### references/clothing-index.md
```markdown
# Clothing Index Reference
## 穿衣指数等级
| 等级 | 体感温度 | 名称 | 推荐穿搭 |
|:---:|:---:|:---|:---|
| 1 | <-10°C | 极寒 | 厚羽绒服、棉裤、雪地靴、全套防寒 |
| 2 | -10~0°C | 严寒 | 羽绒服、厚毛衣、棉裤、棉鞋 |
| 3 | 0~5°C | 寒冷 | 厚外套/大衣、毛衣、保暖内衣 |
| 4 | 5~10°C | 冷 | 外套/风衣、薄毛衣、长裤 |
| 5 | 10~15°C | 凉 | 薄外套/夹克、长袖衬衫 |
| 6 | 15~20°C | 舒适偏凉 | 长袖/薄卫衣、备薄外套 |
| 7 | 20~25°C | 舒适 | T恤/短袖、薄长裤 |
| 8 | 25~30°C | 温暖 | 短袖、短裤、凉鞋 |
| 9 | 30~35°C | 炎热 | 轻薄透气、防晒 |
| 10 | >35°C | 酷热 | 最轻薄衣物、避免户外 |
## 体感温度计算
基于以下因素综合评估:
- 实际温度
- 湿度(高湿度使体感更热/更冷)
- 风速(风寒效应)
## UV 防护建议
| UV指数 | 级别 | 建议 |
|:---:|:---|:---|
| 0-2 | 低 | 无需特别防护 |
| 3-5 | 中等 | 建议涂防晒霜 |
| 6-7 | 高 | 防晒霜+遮阳帽 |
| 8-10 | 很高 | 防晒霜+墨镜+遮阳帽 |
| 11+ | 极端 | 避免户外活动 |
```
---
## Skill Companion Files
> Additional files collected from the skill directory layout.
### _meta.json
```json
{
"owner": "elevo11",
"slug": "weather-plus",
"displayName": "Weather Plus",
"latest": {
"version": "1.0.1",
"publishedAt": 1772789277599,
"commit": "https://github.com/openclaw/skills/commit/099f31538b97c8c71196161d57d75e8ba0760389"
},
"history": [
{
"version": "1.0.0",
"publishedAt": 1772789151701,
"commit": "https://github.com/openclaw/skills/commit/b5afa28e5efea2ba70c2cfcd95997e0467bde577"
}
]
}
```