Skill: alkselsv/yandex-weather-smarthome (version 0.0.1)

--- name: yandex-weather-smarthome description: > Gets current weather and short forecast (today/tomorrow) for the user's configured home location via Yandex Weather API. Trigger when user asks about weather, temperature, wind, conditions, or forecast in Russian/English: "какая погода", "погода", "погода на сегодня", "погода на завтра", "прогноз", "weather", "forecast", "weather tomorrow". metadata: openclaw: requires: bins: - python3 env: - YANDEX_WEATHER_KEY - YANDEX_WEATHER_LAT - YANDEX_WEATHER_LON primaryEnv: YANDEX_WEATHER_KEY emoji: "WEA" aliases: - yandex weather - weather - погода - прогноз tags: - weather - forecast - yandex - smarthome - погода - прогноз --- # Yandex Weather SmartHome ## Purpose Use this skill to quickly return the current weather and short forecast for the user's configured home coordinates. Data source: - Yandex Weather API (`https://api.weather.yandex.ru/v2/forecast`) ## Activation Rules Activate automatically when the user asks about: - current weather ("какая погода", "погода сейчас", "weather now") - short forecast ("погода на сегодня", "погода на завтра", "forecast today/tomorrow") - weather conditions ("температура", "ветер", "осадки", "condition", "wind") If the request is clearly about weather but location is not specified, use configured home coordinates from environment variables (do not ask for coordinates unless user explicitly requests another city/location). ## Security and Secrets - Never print or expose `YANDEX_WEATHER_KEY`. - Never store API keys in files. - Read credentials only from environment variables. - If key/config is missing, explain what variable is missing in one short sentence. ## Execution Workflow 1. Run the local script: ```bash python3 ~/.nanobot/workspace/skills/yandex-weather-smarthome/weather.py ``` 2. If the user asked for structured/raw output, run: ```bash python3 ~/.nanobot/workspace/skills/yandex-weather-smarthome/weather.py --json ``` 3. Return weather result in Russian using the exact fixed multiline template below. 4. Do not paraphrase, compress, or rewrite labels/sentences. ## Response Style - Non-technical user-facing text: do not mention headers, endpoints, or internals unless user asks. - Always include: - current temperature - feels like - condition - wind speed - Include today/tomorrow forecast when available. - Use clear units (`°C`, `м/с`). ### Strict Output Contract - Output MUST match the same section names and field labels: - `Сейчас` -> `Температура`, `Ощущается как`, `Погода`, `Ветер` - `Сегодня` -> `Днём`, `Ночью`, `Описание` - `Завтра` -> `Днём`, `Ночью`, `Описание` - Do not add extra words in headers (forbidden: `Сейчас дома`, `Сейчас у вас`). - Do not merge multiple fields into one sentence. - Do not rewrite in narrative style. - If a value is missing, keep the same label and print `нет данных`. Required output format (use exactly this structure and labels): ```text Сейчас: Температура: 9 °C Ощущается как: 4 °C Погода: облачно с прояснениями Ветер: 4 м/с Сегодня: Днём: 12 °C Ночью: 1 °C Описание: пасмурно Завтра: Днём: 18 °C Ночью: 7 °C Описание: небольшой дождь ``` ## Error Handling - If required env var is missing: - Return one short action-oriented message naming the missing variable. - If HTTP/API error: - Retry once. - If still failing, return: "Не удалось получить погоду сейчас. Попробуйте чуть позже." - If script returns partial data: - Keep the same template and fill missing values as `нет данных`. ## Required Environment Variables ```bash YANDEX_WEATHER_KEY=<api_key> YANDEX_WEATHER_LAT=<latitude> YANDEX_WEATHER_LON=<longitude> ``` ## How to get API key (short) 1. Open Yandex Weather SmartHome page and go to personal cabinet registration. 2. Register with phone number and accept the user agreement. 3. After registration, copy API key from the personal cabinet. 4. Export the key as `YANDEX_WEATHER_KEY`. Official page with FAQ and onboarding: - https://yandex.ru/pogoda/b2b/smarthome Example: ```bash export YANDEX_WEATHER_KEY="your_key" export YANDEX_WEATHER_LAT="52.721" export YANDEX_WEATHER_LON="41.452" ``` ## Notes - The script already localizes weather conditions to Russian. - Default behavior is text output; use `--json` only when structured output is needed.

path: weather.py
content: #!/usr/bin/env python3
import json
import os
import argparse
from urllib import request, parse, error

API_URL = "https://api.weather.yandex.ru/v2/forecast"

CONDITION_RU = {
    "clear": "ясно",
    "partly-cloudy": "малооблачно",
    "cloudy": "облачно с прояснениями",
    "overcast": "пасмурно",
    "drizzle": "морось",
    "light-rain": "небольшой дождь",
    "rain": "дождь",
    "moderate-rain": "умеренный дождь",
    "heavy-rain": "сильный дождь",
    "continuous-heavy-rain": "проливной дождь",
    "showers": "ливень",
    "wet-snow": "дождь со снегом",
    "light-snow": "небольшой снег",
    "snow": "снег",
    "snow-showers": "снегопад",
    "hail": "град",
    "thunderstorm": "гроза",
    "thunderstorm-with-rain": "гроза с дождём",
    "thunderstorm-with-hail": "гроза с градом",
}


def getenv_required(name: str) -> str:
    value = os.getenv(name)
    if not value:
        raise RuntimeError(f"Environment variable {name} is not set")
    return value


def fetch_weather():
    key = getenv_required("YANDEX_WEATHER_KEY")
    lat = getenv_required("YANDEX_WEATHER_LAT")
    lon = getenv_required("YANDEX_WEATHER_LON")

    params = parse.urlencode({
        "lat": lat,
        "lon": lon,
        "lang": "ru_RU",
        "limit": 2,
        "hours": "false",
    })

    url = f"{API_URL}?{params}"

    req = request.Request(url, headers={
        "X-Yandex-Weather-Key": key,
        "Accept": "application/json",
    })

    try:
        with request.urlopen(req, timeout=20) as resp:
            payload = resp.read().decode("utf-8", errors="replace")
    except error.HTTPError as e:
        payload = e.read().decode("utf-8", errors="replace")
        raise RuntimeError(f"HTTP error {e.code}: {payload}")

    return json.loads(payload)


def cond(code):
    return CONDITION_RU.get(code, code)


def build_result(data):
    fact = data.get("fact", {})
    forecasts = data.get("forecasts", [])

    result = {
        "now": {
            "temp": fact.get("temp"),
            "feels_like": fact.get("feels_like"),
            "condition": cond(fact.get("condition")),
            "wind_speed": fact.get("wind_speed"),
        }
    }

    if forecasts:
        today = forecasts[0]
        parts = today.get("parts", {})
        result["today"] = {
            "day_temp": parts.get("day", {}).get("temp_max"),
            "night_temp": parts.get("night", {}).get("temp_min"),
            "condition": cond(parts.get("day", {}).get("condition")),
        }

    if len(forecasts) > 1:
        tomorrow = forecasts[1]
        parts = tomorrow.get("parts", {})
        result["tomorrow"] = {
            "day_temp": parts.get("day", {}).get("temp_max"),
            "night_temp": parts.get("night", {}).get("temp_min"),
            "condition": cond(parts.get("day", {}).get("condition")),
        }

    return result


def print_text(res):
    now = res.get("now", {})

    print("Сейчас:")
    print(f"Температура: {now.get('temp')} °C")
    print(f"Ощущается как: {now.get('feels_like')} °C")
    print(f"Погода: {now.get('condition')}")
    print(f"Ветер: {now.get('wind_speed')} м/с")

    if "today" in res:
        t = res["today"]
        print("\nСегодня:")
        print(f"Днём: {t.get('day_temp')} °C")
        print(f"Ночью: {t.get('night_temp')} °C")
        print(f"Описание: {t.get('condition')}")

    if "tomorrow" in res:
        t = res["tomorrow"]
        print("\nЗавтра:")
        print(f"Днём: {t.get('day_temp')} °C")
        print(f"Ночью: {t.get('night_temp')} °C")
        print(f"Описание: {t.get('condition')}")


def main():
    parser = argparse.ArgumentParser(description="Yandex Weather SmartHome")
    parser.add_argument("--json", action="store_true", help="Output JSON instead of text")
    args = parser.parse_args()

    try:
        data = fetch_weather()
        result = build_result(data)

        if args.json:
            print(json.dumps(result, ensure_ascii=False, indent=2))
        else:
            print_text(result)

    except Exception as e:
        err = {"ok": False, "error": str(e)}
        if args.json:
            print(json.dumps(err, ensure_ascii=False))
        else:
            print(f"Ошибка получения погоды: {e}")


if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)