Back to skills
SkillHub ClubShip Full StackFull StackBackend

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.

Stars
3,058
Hot score
99
Updated
March 20, 2026
Overall rating
C0.0
Composite score
0.0
Best-practice grade
B71.9

Install command

npx @skill-hub/cli install openclaw-skills-weather-plus

Repository

openclaw/skills

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 repository

Best 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

Claude CodeCodex CLIGemini CLIOpenCode

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"
    }
  ]
}

```

weather-plus | SkillHub