<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:atom="http://www.w3.org/2005/Atom">

<channel>

<title>Блоги: заметки с тегом python</title>
<link>https://blogengine.ru/blogs/tags/python/</link>
<description>Автоматически собираемая лента заметок, написанных в блогах на Эгее</description>
<author></author>
<language>ru</language>
<generator>Aegea 11.0 (v4079e)</generator>

<itunes:subtitle>Автоматически собираемая лента заметок, написанных в блогах на Эгее</itunes:subtitle>
<itunes:image href="" />
<itunes:explicit>no</itunes:explicit>

<item>
<title>Получаем данные с сайта СГК для Home Assistant</title>
<guid isPermaLink="false">134734</guid>
<link>https://kini24.ru/all/poluchaem-dannye-s-sayta-sgk-dlya-home-assistant/</link>
<pubDate>Thu, 20 Feb 2025 08:22:01 +0500</pubDate>
<author>Копытов Иван</author>
<comments>https://kini24.ru/all/poluchaem-dannye-s-sayta-sgk-dlya-home-assistant/</comments>
<description>
&lt;p&gt;&lt;a href="https://kini24.ru/"&gt;Копытов Иван&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;В Home Assistant у меня было отслеживание почти всех счетов по квартире: электроэнергия, коммунальные платежи, ТКО, капитальный ремонт и т. д. Проблема была только с сайтом компании СГК, которая занимается предоставлением горячей и холодной воды, отоплением и водоотведением. При помощи таких интеграций, как scrape и multiscrape загрузить данные с их сайта не получалось, поэтому пришлось пойти более сложным путем и написать свой скрипт. На деле он оказался совсем простым, требует доработки в плане проверок ответов сервера, но даже в таком виде он вполне работоспособен. Чтобы не перечислять все данные, возьму только отопление.&lt;/p&gt;
&lt;code python&gt;
import requests
import json

login = data.get("username", "")
password = data.get("password", "")
login_url = 'https://krk.sibgenco.services/Account/Auth'
data_url = 'https://krk.sibgenco.services/fl/accounts/getAccounts'

headers = {
    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0",
}

# Создаем новую сессию
session = requests.Session()
# Авторизуемся на сервере
result = session.post(login_url, data = 'login=' + login + '&amp;password=' + password, headers = headers)
# print(result.text)

# Получаем данные в JSON формате
result = session.get(data_url, headers = headers).json()
session.close()

# Перекодируем текст в читаемый
result = result.encode().decode('unicode-escape', 'ignore')
result = json.dumps(result)
result = json.loads(result)

# Убираем лишние кавычки в разделе "Cards" (откуда взялись?)
result = result.replace('"Cards":"', '"Cards":').replace('}]"}', '}]}')
# print(type(result))
# print(result)

if len(result) &gt; 0:
    logger.info("Данные от СКГ получены")
else:
    logger.warning("Ошибка получения данных от СГК")
# print(result.encode().decode('unicode-escape', 'ignore'))

# Преобразуем строку данных в JSON объект
json_data = json.loads(result)["Accounts"][0]["CalcData"]["Products"]#[0]["ToPay"]

# print(json_data, '\n')
# print(json.dumps(json_data), '\n')

# for product in json_data["Accounts"][0]["CalcData"]["Products"]:
#     print(product["ItemName"] + ": " + str(product["ToPay"]) + " руб.")

if json_data[0]["ToPay"] &gt; 0:
    hass.states.set('sensor.sgk_heating', json_data[0]["ToPay"] * -1)
else:
    hass.states.set('sensor.sgk_heating', json_data[0]["ToPay"])
&lt;/code&gt;
&lt;p&gt;В ходе работы скрипта получаем несколько секций для каждой из услуг, которые выглядят вот так:&lt;/p&gt;
&lt;code json&gt;
  - IsFine: false
    Item: 13
    ContractId: 307015
    ItemName: Отопление
    SaldoBegin: 4228.65
    Paid: 4228.65
    SaldoEnd: 0
    FineEndCheck: true
    FineEnd: 0
    AccrualsCheck: false
    Accruals: 0
    Recalculation: 0
    ToPayCheck: true
    ToPay: 0
    ChargeDetails: ""
    PayDetails: 08.02.2025 4228.65;
    FinePayDetails: ""
    WebPayDetails: 08.02.2025=5338.65=20250208171312-99240-6764617.585349
&lt;/code&gt;
&lt;p&gt;Далее просто создаем автоматизацию в Home Assistant, которая будет запускать этот скрипт. Для надежности перед первым запуском создаем несколько новых сенсоров в примерно таком формате:&lt;/p&gt;
&lt;code python&gt;
    # Задолженность за отопление, итого
    heating_debt_summary:
      unique_id: &lt;тут ваш ID сенсора&gt;
      attribute_templates:
        Пеня: "{{ states('sensor.sgk_heating_penya') }} ₽"
      device_class: monetary
      friendly_name: Задолженность за отопление
      unit_of_measurement: "RUB"
      # value_template: "{{ states('sensor.sgk_heating') | float(0) + states('sensor.sgk_heating_penya') | float(0) }}"
      value_template: "{{ states('sensor.sgk_heating') | float(0) }}"
&lt;/code&gt;
&lt;p&gt;Как видно, в сенсоре будет также атрибут «пеня». Можно вывести суммарную задолженность — долг+пеня, можно вывести только основную — на выбор.&lt;br /&gt;
И вот после сайта СГК меня слегка «понесло» и сделал схожие скрипты для получения информации с сайтов ФНС, капремонта, энергосбыта и регистратора доменов. С ФНС было интересно — там сначала нужно пройти basic-авторизацию, получить токен безопасности, авторизоваться еще раз и слать его при каждом запросе данных. А дальше было уже намного легче — у ФНС существует API, которое они активно используют. Официальной документации по нему нет, но, покопавшись на сайте, можно легко получить все запросы. Для чего нужны эти данные? Например, чтобы отслеживать задолженность по налогам (в том числе и самозанятого), недвижимость и банковские счета. Сейчас такое время, что на тебя могут открыть какой-то счет в банке, сделать тебя «начальником» какой-то конторы, а ты даже будешь не в курсе. Но стоит отметить, что в налоговой отображаются только обычные, дебетовые счета, информации по кредитам там нет.&lt;/p&gt;
</description>
</item>

<item>
<title>Необычная система счисления в bc</title>
<guid isPermaLink="false">134183</guid>
<link>https://bolknote.ru/all/neobychnaya-sistema-schisleniya-v-bc/</link>
<pubDate>Tue, 11 Feb 2025 22:05:21 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/neobychnaya-sistema-schisleniya-v-bc/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;В моём временно любимом &lt;tt&gt;bc&lt;/tt&gt; есть интересная, но не сразу понятная особенность работы с числами. Даже в режиме ввода десятичных чисел принимаются буквы в верхнем регистре, то есть число может состоять из цифр в диапазонах 0…9 и &lt;i&gt;A&lt;/i&gt;…&lt;i&gt;Z&lt;/i&gt;. Буквы при этом обозначают цифры от десяти до тридцати пяти.&lt;/p&gt;
&lt;p&gt;Но так как режим десятичный, результирующее значение числа, содержащего буквы, вычисляется необычно. Я специально не описываю словами, ниже скажу почему. Принцип на картинке, думаю, понятно как всё получается.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2025.02.11@2x.webp" width="1000" height="377" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Мне стало интересно решить задачу конвертации десятичных чисел в такую необычную систему. Из самого принципа следует, что десятичное число может быть представлено несколькими способами, так что придумать можно куда больше одного алгоритма.&lt;/p&gt;
&lt;p&gt;Сегодня на работе, пока обедали с братишкой, пытались в режиме обсуждения решить задачу в уме. Потратили на это почти весь обед, в конце я перенёс то, что придумалось, в код программы:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="python"&gt;def convert(num):
    if num == 0: return 0
    out, orig_num = &amp;quot;&amp;quot;, num

    while num:
        num, r = divmod(num, 10)
        v = min(2 if r &amp;gt; 5 else 3, num)
        if (digit := v * 10 + r) &amp;gt; 9:
            out = chr(digit - 10 + ord(&amp;#039;A&amp;#039;)) + out
        else:
            out = str(digit) + out

        num -= v

    return out if len(out) &amp;lt; len(str(orig_num)) else orig_num&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;А потом мы решили развлечься ещё одним способом — аккуратно сформулировать эту задачу в тексте и решить её искусственным интеллектом. Взяли топовые сети — ЧатГПТ, ДипСик и так далее.&lt;/p&gt;
&lt;p&gt;Я намеренно не показываю получившийся промпт, вдруг вы захотите тоже попробовать, но скажу сразу — с первого или даже пятого раза сформулировать задачу так, чтобы хоть какая-нибудь нейросеть решила её правильно у нас не получилось. Я, в итоге, сдался, а братишка добился-таки код, который её решает, от ДипСика. Листинг, правда, получился вдвое длиннее, чем у меня.&lt;/p&gt;
&lt;p&gt;Из этого можно сделать важный и почему-то не всем очевидный вывод: иногда задачу проще решить самому, потому что сформулировать её нейросети — очень сложное занятие.&lt;/p&gt;
&lt;p&gt;А если посмотреть чуть глубже, то можно додуматься вот до чего. В ближайшее время искусственный интеллект не убьёт профессию программиста, а просто её модифицирует. Сейчас программисты описывают задачу, переведённую ими в алгоритм, на языке программирования, а в будущем буду описывать её на натуральных языках.&lt;/p&gt;
</description>
</item>

<item>
<title>Возвращение плагина Pogoda​Status​Bar</title>
<guid isPermaLink="false">133616</guid>
<link>https://bolknote.ru/all/vozvraschenie-plagina-pogoda-status-bar/</link>
<pubDate>Fri, 10 Jan 2025 20:48:14 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/vozvraschenie-plagina-pogoda-status-bar/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;У меня есть традиция — время от времени чинить мой старенький и порядком уже поднадоевший мне плагин для редактора «Саблайм 3». Плагин называется &lt;a href="https://github.com/bolknote/PogodaStatusBar"&gt;&lt;i&gt;Pogoda​Status​Bar&lt;/i&gt;&lt;/a&gt;, потому что он когда-то показывал пробки и погоду с сервиса «Яндекс.Погоды».&lt;/p&gt;
&lt;p&gt;Эпоха бесплатных сервисов кончилась и «Яндекс» постепенно стал закрывал все те ходы, которыми я пользовался, чтобы получать эти данные. Я искал новые, но в какой-то момент дрогнул и &lt;a href="https://bolknote.ru/all/opyat-chinil-pogodastatusbar/"&gt;перешёл на «Гисметео»&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Всё нормально работало, но в какой-то момент плагин снова сломался. Если ничего не путаю, я предпринял попытку его починить, но у меня с наскоку не вышло и пришлось отложить эту проблему в долгий ящик — были другие дела.&lt;/p&gt;
&lt;p&gt;После новогоднего отдыха появились время и силы и я решил их часть израсходовать на плагин. Как-то зудело у меня, что он не работает.&lt;/p&gt;
&lt;p&gt;Надо сказать, что я не знаю как правильно отлаживать плагины в «Саблайме». В документации ничего не нашёл, поэтому написал небольшую обвязку и запускаю свой плагин просто из командной строки. Но в этот раз этот способ не сработал — в обвязке плагин работал, а внутри «Сайблайма» — нет.&lt;/p&gt;
&lt;p&gt;Я уже с таким сталкивался. У «Саблайма» внутри две версии «Пайтона» — 3.3 и 3.8. Обе, в общем-то, уже старые. Мой плагин запускается с версией 3.3 и у меня никак не дойдут руки залезть в общий репозиторий плагинов и переписать для моего плагина версию «Пайтона».&lt;/p&gt;
&lt;p&gt;Таким образом между «Пайтоном» у меня в командной строке и внутри «Сайблайма» — десять версий. Иногда я использую в коде что-то, чего «Сайблайм» не понимает.&lt;/p&gt;
&lt;p&gt;И вот непонятно как об этом узнавать. Можно, думаю, раздобыть старенький «Пайтон» в контейнере, но лень.&lt;/p&gt;
&lt;p&gt;Обычно я просто пристально смотрю на код, пока не понимаю как его исправить. А в этот раз так не вышло. Мне несколько раз казалось, что я понимаю в чём дело, я коммитил новый код, собирал релиз, дожидался, пока тулчейн репозитория плагинов «Саблайма» увидит новую версию, обновлялся и не получал положительного результата.&lt;/p&gt;
&lt;p&gt;В итоге, мне это надоело. Я нашёл в какой папке «Саблайм» держит плагины, они там лежат, к слову, в архивированном виде, и попытался подсунуть туда свой код — паковал папку с модифицированным кодом и заменял файл плагина. Но гадкий «Саблайм» как-то это понимал и затирал мои правки.&lt;/p&gt;
&lt;p&gt;С этим я опять поленился разбираться, вместо этого попытался отредактировать код прямо в архиве через консольный файловый менеджер &lt;tt&gt;mc&lt;/tt&gt;. Неожиданно это сработало. Так я узнал, что ошибка была в том, что я использую вызов &lt;tt&gt;html.unescape&lt;/tt&gt;, который появился только в «Пайтоне» 3.4. Пришлось заменить его на вполне устроивший меня в этом месте &lt;tt&gt;replace(&amp;apos;&amp;amp;quot;&amp;apos;, &amp;apos;&amp;quot;&amp;apos;)&lt;/tt&gt; и всё заработало.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2025.01.10@2x.webp" width="1000" height="625" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Код плагина, открытый через редактор консольного файлового менеджера&lt;/div&gt;
&lt;/div&gt;
</description>
</item>

<item>
<title>«Киберслав»</title>
<guid isPermaLink="false">133501</guid>
<link>https://bolknote.ru/all/kiberslav/</link>
<pubDate>Wed, 01 Jan 2025 18:40:25 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/kiberslav/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Вчера вышла первая серия отечественного сериала «Киберслав». Я выхода первой серии ждал несколько лет, с тех пор как впервые увидел тизер. Очень боялся, что результат окажется очень слабым, всё-таки какого-то сильного сюжетного материала не обещали — сериал не по книге или готовому миру от какого-то нибудь мэтра, это реализация идеи «давайте объединим славян и киберпанк».&lt;/p&gt;
&lt;p&gt;Но обошлось, смотрится отлично.&lt;/p&gt;
&lt;p&gt;В заставке серии, кстати, используется идея, в чём-то похожая на «дождь» из «Матрицы» Вачовски — изображение составленное из символов. Только в «Кибреславе» используется другая цветовая гамма и буквы старославянской кириллицы. Мне настолько понравилась эта отсылка, что я сделал &lt;a href="https://github.com/bolknote/CyberslavRain"&gt;свою консольную версию&lt;/a&gt; «дождя» из «Матрицы», но в стиле «Киберслава».&lt;/p&gt;
&lt;p&gt;Заодно посмотрел как модуль &lt;tt&gt;curses&lt;/tt&gt; в «Пайтоне» позволяет облегчить работу в консоли. Много про него слышал, но не доводилось попробовать.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2025.01.01@2x.jpg" width="1000" height="586" alt="" /&gt;
&lt;/div&gt;
</description>
</item>

<item>
<title>Замена цифр</title>
<guid isPermaLink="false">130690</guid>
<link>https://bolknote.ru/all/zamena-cifr/</link>
<pubDate>Wed, 18 Sep 2024 22:37:35 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/zamena-cifr/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Придумал тут штуку интересную. Как у я уже &lt;a href="https://bolknote.ru/all/nol-nol/"&gt;писал ранее&lt;/a&gt;, полюбилось мне что-то писать время с минутами в верхнем индексе. Для этого мне пришлось решить проблему ввода всего набора таких символов.&lt;/p&gt;
&lt;p&gt;Сначала я сделал достаточно просто, — отредактировал раскладку, которой я пользуюсь. Мне не нравилось это решение, так как пришлось выкинуть из неё кое-какие полезные символы, которые мне бы тоже пригодились.&lt;/p&gt;
&lt;p&gt;А сегодня мне пришло в голову решение лучше — попробовать обойтись функцией «Замены текста», которая встроена в «МакОСь». Мысль простая — заменять двоеточие и две цифры на то же самое, но без двоеточия и в верхнем индексе. Сначала я пытался набрать всё нужное руками, а потом случайно нашёл функцию импорта.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2024.09.18@2x.webp" width="1000" height="194" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Формат для импорта оказался довольно простым. После того как я в нём разобрался, накидал небольшую программу на «Пайтоне», которая мне за мгновение сформировала нужный файл.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="python"&gt;print(&amp;quot;&amp;quot;&amp;quot;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;!DOCTYPE plist PUBLIC &amp;quot;-//Apple//DTD PLIST 1.0//EN&amp;quot; &amp;quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&amp;quot;&amp;gt;
&amp;lt;plist version=&amp;quot;1.0&amp;quot;&amp;gt;
&amp;lt;array&amp;gt;&amp;quot;&amp;quot;&amp;quot;)

trans = str.maketrans(&amp;quot;0123456789&amp;quot;, &amp;quot;⁰¹²³⁴⁵⁶⁷⁸⁹&amp;quot;)

for i in range(0, 60):
	print(f&amp;quot;&amp;quot;&amp;quot;
	&amp;lt;dict&amp;gt;
		&amp;lt;key&amp;gt;phrase&amp;lt;/key&amp;gt;
		&amp;lt;string&amp;gt;{f&amp;quot;{i:02d}&amp;quot;.translate(trans)}&amp;lt;/string&amp;gt;
		&amp;lt;key&amp;gt;shortcut&amp;lt;/key&amp;gt;
		&amp;lt;string&amp;gt;:{i:02d}&amp;lt;/string&amp;gt;
	&amp;lt;/dict&amp;gt;&amp;quot;&amp;quot;&amp;quot;)


print(&amp;quot;&amp;lt;/array&amp;gt;&amp;lt;/plist&amp;gt;&amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Чтобы его импортировать, нужно перейти в «Системные настройки…», оттуда в  «Клавитуру», там нажать на кнопку «Замены текста…» и перетащить на открывшийся список получившийся файл.&lt;/p&gt;
&lt;p&gt;После этого можно проверить что получилось, — если написать в любом месте «13:00», оно должно само преобразоваться в «13⁰⁰».&lt;/p&gt;
</description>
</item>

<item>
<title>И опять чинил PogodaStatusBar</title>
<guid isPermaLink="false">129444</guid>
<link>https://bolknote.ru/all/i-opyat-chinil-pogodastatusbar/</link>
<pubDate>Tue, 16 Jul 2024 20:27:06 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/i-opyat-chinil-pogodastatusbar/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Прям заметно, что эпоха открытого веба закончилась. Было время вокруг были открытые сервисы, используй сколько влезет. Потом всё как-то изменилось. Сначала стали появляться ограничения на количество запросов, потом все повально стали бороться с ботами, а то и и просто убирать сервисы из открытого доступа.&lt;/p&gt;
&lt;p&gt;В общем, &lt;a href="https://bolknote.ru/all/opyat-chinil-pogodastatusbar/"&gt;прошла неделя&lt;/a&gt; и мне снова прикрыли лавочку — урл «Гисметео», который я использовал, чтобы определять айди населённого пункта по названию вдруг меня забанил. На любой запрос выдаётся «доступ запрещён». Да что ж такое!&lt;/p&gt;
&lt;p&gt;Полез я снова смотреть погодный плагин, смотреть как сделано там. Он же как-то определяет текущий населённый пункт, значит и я как-то могу получить эти данные. Оказалось, что есть у «Гисметео» ещё один сервис — &lt;tt&gt;services.gismeteo.net/inform-service/inf_chrome/cities/&lt;/tt&gt;, который определяет местоположение по АйПи (ошибается в моём случае) или по координатам.&lt;/p&gt;
&lt;p&gt;Координаты у меня уже есть, я их могу забрать у «Яндекса», надо только распарсить:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="python"&gt;@functools.cache
def _getRegionData(self):
    try:
        url = &amp;quot;https://yandex.ru/tune/geo/&amp;quot;
        content = urllib.request.urlopen(url).read().decode(&amp;#039;utf-8&amp;#039;)
        region_data = re.search(r&amp;#039;data-bem=&amp;quot;([^&amp;quot;]+coords[^&amp;quot;]+)&amp;quot;&amp;#039;, content).group(1)
        parsed_region_data = json.loads(html.unescape(region_data))

        # {&amp;#039;id&amp;#039;: xx, &amp;#039;region&amp;#039;: &amp;#039;XXXXX&amp;#039;, &amp;#039;coords&amp;#039;: [&amp;#039;XX.XXXXX&amp;#039;, &amp;#039;XX.XXXXX&amp;#039;], &amp;#039;accuracy&amp;#039;: &amp;#039;XXXXXX&amp;#039;}
        return parsed_region_data[&amp;#039;checkbox&amp;#039;][&amp;#039;auto&amp;#039;]
    except (IOError, AttributeError):
        return None&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;В итоге, получилась такая схема: в «Яндексе» получаем координаты и айди населённого пункта у «Яндекса», по этому айди получаем информацию по пробкам. Далее по координатам получаем айди населённого пункта у «Гисметео», по которому получаем погоду.&lt;/p&gt;
&lt;p&gt;Ей-богу я в полушаге от того, чтобы прекратить борьбу и забросить проект.&lt;/p&gt;
</description>
</item>

<item>
<title>Опять чинил PogodaStatusBar</title>
<guid isPermaLink="false">129270</guid>
<link>https://bolknote.ru/all/opyat-chinil-pogodastatusbar/</link>
<pubDate>Tue, 09 Jul 2024 17:28:22 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/opyat-chinil-pogodastatusbar/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Сегодня участвовал в довольно скучной видеоконференции. Моё участие там было хоть и необходимое, но небольшое. А чтобы не одуреть от безделья, пока я слушал всю эту скуку, решил чем-то занять руки. Давно хотел починить свой плагин для «Саблайма» «&lt;a href="https://github.com/bolknote/PogodaStatusBar/"&gt;&lt;i&gt;PogodaStatusBar&lt;/i&gt;&lt;/a&gt;», этим и занялся.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2024.07.09@2x.jpg" width="300" height="38" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Внешний вид плагина на настоящий момент&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Плагин в строке статуса показывает текущую погоду и пробки в вашем городе. Много лет данные для этого я брал с неофициального урла «Яндекса», но компания решила коммерциализировать погоду и, сколько я не искал новый способ получить её бесплатно, так и не нашёл.&lt;/p&gt;
&lt;p&gt;Пробки, кстати, тоже перестали нормально работать. Когда-то регион определялся автоматически, но это сломали. Я &lt;a href="https://bolknote.ru/all/pogodastatusbar-fixed/"&gt;чинил&lt;/a&gt; это через парсинг страницы погоды, но теперь и это не работает — «Яндекс» борется с автоматическими роботами. Поэтому пришлось искать другой способ.&lt;/p&gt;
&lt;p&gt;Я перебрал несколько малоизвестных сервисов, пока, наконец, не увидел, что страница &lt;tt&gt;yandex.ru/tune/geo/&lt;/tt&gt; содержит в себе необходимый номер. Этого хватило, чтобы починить показ пробок.&lt;/p&gt;
&lt;p&gt;С «Гисметео» пришлось повозиться. Не нашёл официальную информацию о каких-либо АПИ, которые можно вызвать без токена, но внутри погодного плагина для браузера нашёлся адрес &lt;tt&gt;services.gismeteo.ru/inform-service/inf_chrome/forecast&lt;/tt&gt;. В нём есть всё что нужно — текущая температура и закодированная иконка погоды.&lt;/p&gt;
&lt;p&gt;Определить номер города в формате «Гисметео» помогает сервис &lt;tt&gt;www.gismeteo.ru/rmq/search/{название}/1/&lt;/tt&gt;, куда я подставляю название, полученное от «Яндекс.Пробок» — там он возвращается вместе с остальными данными.&lt;/p&gt;
&lt;p&gt;Оставалось только расшифровать иконку погоды. В документации есть часть описания (остаток можно понять, скачав с «Гисметео» значки погоды), выглядит всё несложно. Например, &lt;tt&gt;d.r3&lt;/tt&gt; означает «день» (&lt;i&gt;day&lt;/i&gt;) и «дождь максимальной интенсивности» (&lt;i&gt;rain 3&lt;/i&gt;).&lt;/p&gt;
&lt;p&gt;Поскольку у меня Юникод, в нём есть не все необходимые значки, я сделал вот такой объект, содержащий признаки, которые позволяют мне выбрать какую иконку показать:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="python"&gt;_icons = {
    &amp;quot;🌞&amp;quot;: {&amp;quot;d&amp;quot;}, # day
    &amp;quot;🌙&amp;quot;: {&amp;quot;n&amp;quot;}, # nite
    &amp;quot;☁️&amp;quot;: {&amp;quot;n&amp;quot;, &amp;quot;c&amp;quot;}, # night, cloud
    &amp;quot;🌧&amp;quot;: {&amp;quot;rs&amp;quot;, &amp;quot;c&amp;quot;, &amp;quot;r&amp;quot;}, # rain+snow, cloud, rain
    &amp;quot;🌤&amp;quot;: {&amp;quot;d&amp;quot;, &amp;quot;c&amp;quot;}, # day, cloud
    &amp;quot;🌦&amp;quot;: {&amp;quot;d&amp;quot;, &amp;quot;r&amp;quot;}, # day, rain
    &amp;quot;🌩️&amp;quot;: {&amp;quot;c&amp;quot;, &amp;quot;st&amp;quot;}, # #day, storm
    &amp;quot;⛈️&amp;quot;: {&amp;quot;c&amp;quot;, &amp;quot;st&amp;quot;, &amp;quot;r&amp;quot;}, # cloud, storm, rain
    &amp;quot;🌨&amp;quot;: {&amp;quot;c&amp;quot;, &amp;quot;s&amp;quot;}, # cloud, storm
    &amp;quot;💨&amp;quot;: {&amp;quot;mist&amp;quot;}, # mist
    &amp;quot;⚡️&amp;quot;: {&amp;quot;st&amp;quot;}, # storm
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;И вот такой простой алгоритм для выбора иконки:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="python"&gt;def _getStatus(self, coded_weather):
    codes = {x.strip(&amp;quot;0123456789&amp;quot;) for x in coded_weather.split(&amp;quot;.&amp;quot;)}

    max_icon = None
    max_score = 0

    for icon, code in self._icons.items():
        result = codes &amp;amp; code
        score = sum(len(x) for x in result)
        if score &amp;gt; max_score:
            max_icon, max_score = icon, score

    return max_icon&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Идея простая — чем больше значков совпало, тем лучше; если совпал значок с более длинным названием (&lt;i&gt;st&lt;/i&gt;, &lt;i&gt;mist&lt;/i&gt;), считаем его более конкретным и важным.&lt;/p&gt;
</description>
</item>

<item>
<title>Графики в стиле xkcd</title>
<guid isPermaLink="false">129046</guid>
<link>https://bolknote.ru/all/grafiki-v-stile-xkcd/</link>
<pubDate>Sat, 29 Jun 2024 15:42:10 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/grafiki-v-stile-xkcd/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;i&gt;xkcd&lt;/i&gt; — культовая серия веб-комиксов. Когда-то я их обожал, но потом их перестали переводить, а мой английский в то время было недостаточно хорош, чтобы понимать их без посредников. Сейчас, наверное, можно было бы попытаться их читать, но уже нет желания.&lt;/p&gt;
&lt;p&gt;У &lt;i&gt;xkcd&lt;/i&gt; очень узнаваемый стиль рисовки и, когда я их вдруг встречаю, они по-прежнему вызывают у меня улыбку. Сегодня я узнал, что в «Пайтоне» есть возможность рисовать графики в этом стиле. Надо добавить всего одну строку — вызов метода &lt;tt&gt;plt.xkcd()&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Вот код:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class="python"&gt;import matplotlib.pyplot as plt
import numpy as np

t = np.linspace(0, 2*np.pi, 1000)
x = 16 * np.sin(t)**3
y = 13 * np.cos(t) - 5 * np.cos(2*t) - 2 * np.cos(3*t) - np.cos(4*t)

plt.xkcd()

plt.figure(figsize=(8, 6))
plt.plot(x, y, color=&amp;#039;b&amp;#039;)
plt.title(&amp;#039;cos(…) = ?&amp;#039;)
plt.show()&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;А вот результат:&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2024.06.29.1@2x.jpg" width="1000" height="800" alt="" /&gt;
&lt;/div&gt;
</description>
</item>

<item>
<title>Шутка, которая не работает</title>
<guid isPermaLink="false">125983</guid>
<link>https://bolknote.ru/all/shutka-kotoraya-ne-rabotaet/</link>
<pubDate>Wed, 21 Feb 2024 09:16:51 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/shutka-kotoraya-ne-rabotaet/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Тут в чате бывших коллег, где мы постим мемы, пробежала картинка, которая больше повеселила меня не смыслом, который в неё вкладывал автор, а тем, что на системе, под которую написан код на ней (Виндоуз, очевидно), она не выполнится.&lt;/p&gt;
&lt;p&gt;Проблема тут в том, что вызов &lt;tt&gt;os.remove&lt;/tt&gt; умеет удалять только файл, тогда как &lt;tt&gt;System32&lt;/tt&gt; — папка, знакомая многим пользователям Виндоуз. Я не уверен точно, но думаю, что при её удалении система будет сопротивляться. Она, вроде, как-то защищена от такого.&lt;/p&gt;
&lt;p&gt;Возможно, кстати, код и не предполагалось делать рабочим, а шутка немного тоньше — ведь вызов &lt;tt&gt;os.remove&lt;/tt&gt; можно прочитать как «удалить операционную систему», не знаю, я в любом случае хотел рассказать не об этом.&lt;/p&gt;
&lt;p&gt;Дело в том, что шутка написана под ОС, под которой она работать не будет, но смешно то, что под ОС, на которую она рассчитана не была, она вполне может заработать.&lt;/p&gt;
&lt;p&gt;В Линуксе или МакОСи надо в любом месте, где будет запускаться эта программа, создать папку &lt;tt&gt;C:&lt;/tt&gt;, в ней — папку &lt;tt&gt;Windows&lt;/tt&gt;, а в ней — файл &lt;tt&gt;System32&lt;/tt&gt;, который и удалится, если выпадет искомое число на рандомайзере.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2024.02.20.1@2x.png" width="582" height="167" alt="" /&gt;
&lt;/div&gt;
</description>
</item>

<item>
<title>Починил PogodaStatusBar</title>
<guid isPermaLink="false">133623</guid>
<link>https://bolknote.ru/all/pogodastatusbar-fixed/</link>
<pubDate>Mon, 27 Jul 2020 22:18:39 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/pogodastatusbar-fixed/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Обратил внимание, что мой &lt;a href="https://bolknote.ru/all/4605/"&gt;погодно-пробочный плагин&lt;/a&gt; для «Саблайма» сломался — ничего не показывает. Я заметил не сразу, сейчас редко запускаю этот редактор. Ребята, которые пользуются регулярно, говорят, что сломался довольно давно.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2020.07.27@2x.png" width="500" height="47" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Строка статуса: в Казани +20°C, пробки три балла&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Пришлось исправить две вещи — во-первых, импорт одного из модулей перестал работать, это произошло, как я думаю, с обновлением интерпретатора, во-вторых, АПИ «Яндекса», которое я использую, перестало корректно определять регион, в котором надо показать погоду. Пришлось искать обходные манёвры.&lt;/p&gt;
&lt;p&gt;Остался ещё один баг — если «Яндекс» не отдаёт информацию о пробках (в некоторых небольших городах такой информации нет), то плагин работать не будет. Не знаю, стоит ли это править, всё-таки популярностью у него невелика́ и делал я его больше для себя.&lt;/p&gt;
</description>
</item>

<item>
<title>Погодный плагин для «Sublime Text»</title>
<guid isPermaLink="false">133622</guid>
<link>https://bolknote.ru/all/4605/</link>
<pubDate>Sat, 24 Jun 2017 20:03:00 +0500</pubDate>
<author>Евгений Степанищев</author>
<comments>https://bolknote.ru/all/4605/</comments>
<description>
&lt;p&gt;&lt;a href="https://bolknote.ru/"&gt;Евгений Степанищев&lt;/a&gt;:&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://bolknote.ru/pictures/2017.06.24@2x.jpg" width="747" height="482" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Окно редактора «Саблайм Текст» с погодой и пробками в строке состояния&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Написал свой первый плагин для «Саблайма» — для отображения в строке состояния &lt;a href="https://github.com/bolknote/PogodaStatusBar/"&gt;погоды и пробок&lt;/a&gt; «Яндекса». Заодно немного повспоминал «Пайтон», давно на нём ничего не писал.&lt;/p&gt;
&lt;p&gt;Удивительно, но факт — другого работоспособного плагина на эту тему не обнаружилось. Единственный конкурент использует старое АПИ «Яху», которое уже не работает, потому не работает и плагин.&lt;/p&gt;
&lt;p&gt;Отдельное спасибо «Яндексу» за то, что их АПИ умеет определять текущее местоположение — ничего задавать в конфиге не надо, удобно.&lt;/p&gt;
&lt;p&gt;Поскольку в строке состояния можно выводить только буквы, воспользовался Юникодом для вывода погодных значков, для уровня пробок не нашлось ничего лучше фруктов, так что индикатором загруженности дорог у меня служат зелёное яблоко, жёлтый лимон и красный помидор. Не знаю будут ли видны эти символы пользователям Линукса или Виндоуза, мне негде посмотреть.&lt;/p&gt;
&lt;p&gt;Пришлось повозиться с АПИ самого «Саблайма». Во-первых, отдельного события на старт редактора нет, пришлось активировать плагин на получение фокуса окном. Во-вторых, некоторые авторы плохо читают документацию — у многих их плагины полностью переинициализируются на событие, это ни к чему, я, например, дёргаю «Яндекс» как можно реже, по таймеру в отдельном потоке, а в строке показываю кешированное.&lt;/p&gt;
&lt;p&gt;В настройках есть шаблон вывода, можно убрать пробки или погоду, если они не нужны.&lt;/p&gt;
&lt;p&gt;Подал пул реквест на включение в саблаймовский пакетный менеджер, но особо упорствовать не буду, если откажут.&lt;/p&gt;
</description>
</item>


</channel>
</rss>