Ми}{@лbI4

Блог хеллоуворлдщика

Блок с погодой в i3blocks

18.03.2024 linux, i3, i3blocks

Очередная ненужная никому история о Linux и i3. В этот раз я реализовал для себя блок с погодой. Не то, чтобы я не выхожу на улицу - что на самом деле является долей правды - просто мне так удобней и мне так понятней, когда можно выбежать за хлебушком. Зимой, конечно, вообще не хочется никуда выходить. Особенно, если температура ниже -10 градусов. Жуть! Вернемся к нашему блоку. Визуально он выглядит следующим образом:

i3blocks с погодой по г. Армавир

Здесь можно заметить самое простое визуальное оформление и иконки FontAwesome. Данные о погоде извлекаются благодаря API OpenWeather, которые предоставляют free план на 60 запросов в минуту или 1 млн в месяц. Для меня этого вполне достаточно, потому что я дергаю погоду только 1 раз в 15 минут. Это всего 2880 запросов в месяц.

Что ж, сам код блока i3blocks написан на Bash. Ниже представлен файл u-i3blocks-weather.sh:

#!/usr/bin/env bash

set -euo pipefail

WEATHER_SITE_URL="https://www.gismeteo.ru/weather-armavir-5220/10-days/"

nm-online -q -t 15 || exit 1

btn_code="${BLOCK_BUTTON:-"0"}"
if [ "${btn_code}" -eq "1" ]; then
  xdg-open $WEATHER_SITE_URL 1> /dev/null &
fi

/path/to/u-weather.py

exit 0

Здесь можно заметить константу WEATHER_SITE_URL, которая содержит ссылку на сайт с погодой. По этой ссылке открывается браузер, когда происходит левый клик по блоку в i3bar. Также в этом файлике у нас есть путь до Bash файла /path/to/u-weather.py, который как раз и содержит весь важный код для предоставления данных о погоде. Данный файл представляет собой код на языке Python:

#!/usr/bin/env python3

from pycurl import Curl, FOLLOWLOCATION, HTTPGET, WRITEDATA, error as CurlError
import sys
import os
from io import BytesIO
import json
from json import JSONDecodeError
from typing import List
from urllib.parse import urlencode
from subprocess import CalledProcessError

# https://openweathermap.org/current
# https://openweathermap.org/weather-conditions

OPENWEATHERMAP_API_KEY = ''
LOCATION_NAME = 'Armavir'

SYMBOL_DEGREE = '\u00B0'

ICON_WIND = '\uf72e'
ICON_CLEAR = '\uf185'
ICON_CLOUDS = '\uf0c2'
ICON_RAIN = '\uf73d'
ICON_THUNDERSTORM = '\uf76c'
ICON_SNOW = '\uf2dc'
ICON_SMOG = '\uf75f'

request = Curl()
request.setopt(
    request.URL,
    'https://api.openweathermap.org/data/2.5/weather?' + urlencode({
        'q': LOCATION_NAME,
        'appid': OPENWEATHERMAP_API_KEY,
        'units': 'metric',
        'lang': 'en'
    })
)
request.setopt(FOLLOWLOCATION, True)
request.setopt(HTTPGET, True)
buffer = BytesIO()
request.setopt(WRITEDATA, buffer)
try:
    request.perform()
except (CurlError) as e:
    print(e, file=sys.stderr)
    sys.exit(os.EX_DATAERR)
request.close()

try:
    weather_data = json.loads(buffer.getvalue())
except (JSONDecodeError, CalledProcessError) as e:
    print(e, file=sys.stderr)
    sys.exit(os.EX_DATAERR)

output: List[str] = []

if (
    'weather' in weather_data
    and len(weather_data['weather']) > 0
    and 'id' in weather_data['weather'][0]
):
    weather_id = weather_data['weather'][0]['id']
    if (200 <= weather_id <= 232):
        output.append(ICON_THUNDERSTORM)
    elif (300 <= weather_id <= 321 or 500 <= weather_id <= 531):
        output.append(ICON_RAIN)
    elif (600 <= weather_id <= 622):
        output.append(ICON_SNOW)
    elif (701 <= weather_id <= 781):
        output.append(ICON_SMOG)
    elif (weather_id == 800):
        output.append(ICON_CLEAR)
    elif (801 <= weather_id <= 804):
        output.append(ICON_CLOUDS)

if ('name' in weather_data):
    output.append(weather_data['name'])

if ('main' in weather_data and 'temp' in weather_data['main']):
    output.append(
        str(round(weather_data['main']['temp'])) + SYMBOL_DEGREE + 'C'
    )

if ('wind' in weather_data and 'speed' in weather_data['wind']):
    output.append(ICON_WIND)
    #    m/s
    # --------- = m/s * 3.6
    # 1000/3600
    output.append(str(round(weather_data['wind']['speed'] * 3.6)))
    output.append('km/h')

print(' '.join(output))

sys.exit(os.EX_OK)

В этом файле можно заметить две важные константы. Первая OPENWEATHERMAP_API_KEY, а вторая - LOCATION_NAME. В OPENWEATHERMAP_API_KEY указывается ключ API для OpenWeather, который вы сможете скопировать после регистрации на сайте OpenWeather в личном профиле пользователя. А в LOCATION_NAME указывается ваше текущее местоположение. Данный блок разрабатывался исключительно под использование на стационарном компьютере, поэтому если у вас ноутбук и вы часто куда-то путешествуете, то данный код потребует некоторых доработок.

Теперь осталось все добавить в i3blocks:

[weather]
command=/path/to/u-i3blocks-weather.sh
interval=900

Перезапускаем i3 - i3-msg restart - и радуемся. =)