Pull to refresh

Оптимизация расходов Yota: попытка #3

Reading time5 min
Views30K
Привет, хабр!

Наступило лето и очень многие уезжают из города. Кто-то на время отпуска, а кто-то и на все лето (если работа позволяет). Но одна из главных проблем за городом (для всех людей, так или иначе связанных с IT) — отсутствие нормального проводного быстрого интернета. Но это частично решается благодаря существованию LTE-сетей.

В моем регионе крупных провайдеров LTE всего два: Мегафон и Yota. Мегафон существенно дешевле, но у него есть одна крайне неприятная особенность: ограничение в 20гб трафика в месяц даже на максимальном тарифе.

Поэтому выбор оператора, на мой взгляд, очевиден. Но все же платить за 20 мегабит в два раза больше чем за 100 дома — сомнительное удовольствие. Но при этом, в отличие от других операторов, Yota позволяет в в любой момент бесплатно изменять текущий тариф в личном кабинете с перерасчетом оплаченного времени. Нужна скорость — выкручиваем ползунок на максимум. Нет? Тогда можно снизить скорость и платить меньше. Ну как тут можно удержаться и не автоматизировать этот процесс?

На хабре уже были статьи (раз, два), описывающие попытки йотоводов-автоматизаторов. Однако, в силу некоторых особенностей, их творения мне не подошли и пришлось написать свой, существенно отличающийся, велосипедОднако, в силу некоторых особенностей, их творения мне не подошли и пришлось написать свой, существенно отличающийся, велосипед.

А начнем мы, пожалуй, с разбора причин, по которым мне не подошли чужие велосипеды. Особо нетерпеливые / материально заинтересованные могут сразу перейти к разделу, описывающему реализацию.

Постановка задачи

Вариант linx56 мне не подошел ну совсем никак, потому как он работает phantomjs, для работы которого нужно довольно нехилое железо (которым Raspberry PI не является). Да и даже если я поставлю это на свой основной компьютер и оставлю его работать круглосуточно, забив в cron расписание по которому нужно отключать интернет, то я получу счет за электричество больше, чем сэкономлю все равно не получу нормального результата, потому как интернет используется довольно непредсказуемо (и не только мной, но и членами семьи, для которых главное чтобы «просто работало»).

Второй вариант от bambrman существенно выигрывает у первого тем, что вместо phantomjs использует сильно менее прожерливый curl. Но в остальном все то же самое.

В итоге было решено написать еще один велосипед, в основе которого лежало бы не расписание (или руки человека), а текущая скорость, потребляемая всеми устройствами в локальной сети.

Реализация

Я использовал Raspberry Pi и скрипт на Python, который каждые n секунд подключается по SSH к главному домашнему роутеру (TP-LINK WDR4300 с OpenWrt на борту) и при помощи ifconfig стягивает статистику нужного интерфейса.

После этого он считает среднюю скорость за промежуток между последним и предыдущим замером и отправляет ее в модуль, который отвечает за переключение тарифов в соответствии с текущей скоростью и настройками конфига. Чтобы было понятнее, приведу здесь его часть:
modes: {
    0: 320,
    290: 512,
    495: 768,
    700: 1.0,
    900: 2.1,
    1900: 3.1,
    2900: 4.1,
    3900: 6.5,
    6500: 8.0,
    8000: 10.0,
    10000: 15.0,
    14800: 20.0
}


Как вы видите, в качестве ключа словаря выступает скорость в килобитах, а в качестве значения — тариф йоты.

По результатам замера текущей скорости у нас получилось, скажем, 1530 килобит. Округляем в меньшую сторону до значения ближайшего ключа в конфиге и получаем 900. Соответственно, должен использоваться тариф со скоростью 2.1 мегабит. В случае, если этот тариф уже активен, ничего не происходит. Но вот если тариф нужно повышать, то тут есть одна особенность.

Проблема в том, что если интернет долгое время не использовался (и активировался тариф в 320 кбит/с), а потом кто-то внезапно включил YouTube, то последовательное переключение с 320 кбит/с до 3.1 мбит/с может занять немало времени (не говоря уже о вечно лагающем ЛК Yota). С другой стороны, прыгать каждый раз на максимальный тариф, когда кто-то решил загрузить пару страниц и несколько картинок — тоже плохая идея. В общем я не придумал ничего лучше, чем добавить в конфиг

speed_increase_step: 1


Этот параметр указывает на размер шага апгрейда между тарифами. То есть при установке speed_increase_step = 5, апгрейд с 320 кбит/с произойдет сразу до 3.1 мегабит, а дальше 15.0 и 20.0. И если возможная скорость не будет использоваться полностью, это будет компенсировано механизмом даунгрейда.

Даунгрейд

В случае, если активный тариф долгое время не используется в полную силу (текущая скорость не превышает нужного для текущего тарифа порога), скрипт ждет n минут и выполняет переключение на тариф, который удовлетворяет текущим запросам локальной сети (на основании средней скорости). Это самое количество минут задается в параметре hold_high_speed_time в минутах.

hold_high_speed_time: 3


По сути, основной функционал на этом завершается. Правда, есть еще кое-что, что, возможно, кого-нибудь да заинтересует:

Уведомления о смене тарифа через PushBullet

Писалось, как и все остальное, в первую очередь для себя. Но, честно честно говоря, так и не пригодилось, потому как генерирует слишком много спама. Но может кому понравится ;)

Включается это дело все там же, в конфиге:
pb_enabled: true
pb_api: v13WA7HYfwj99gUz8rwvK2m7eLN1uheVxZujAgP8gn2su
pb_devices: [
    ujAgP8gn2sasFDsgsWhxs,
    ujAgP8gn2mkasnuH2Gtga
]


Как видите, здесь все довольно просто. pb_enabled принимает значения true/false. Назначение очевидно.
pb_api — ваш ключ со страницы www.pushbullet.com/account
pb_devices — список идентификаторов устройств, на которые рассылаются уведомления. Взять можно тут: api.pushbullet.com/v2/devices. При входе вас попросят авторизоваться: просто введите ключ api в поле логина. Полное описание метода тут: docs.pushbullet.com/v2/devices

Ну что же. Дело сделано, сообщение доставлено. Теперь можно и код показать рассказать, как все это дело готовить.

Установка

  • Первым делом идем и устанавливаем на свой роутер OpenWrt. Ну или что-нибудь подобное с SSH, авторизацией по ключам и утилитой ifconfig.
  • После этого нужно найти что-то вроде Raspberry Pi. То, на чем можно запустить третий питон и где есть ssh-клиент с авторизацией по ключам.
  • Настраиваем авторизацию по ключу для подключения к роутеру. Убеждаемся что команда вида (с вашими данными, конечно же) «ssh 192.168.1.1 -p 22 -l root ifconfig» работает без дополнительных вопросов
  • Ставим Python 3 и pip. Изначально все писалось и тестировалось на 3.2.3. На совместимость с более ранними версиями тестов не было
  • Клонируем репозиторий проекта с GitHub: https://github.com/wutiarn/yota-speed-controller
  • Делаем cd в папку с репозиторием
  • Выполняем pip3 install -r requirements.txt. Обратите внимание, что pip может иметь другое имя (pip-3.2, например)
  • Редактируем config.yaml. Описания большинства его параметров есть вверху. Остальные, как мне кажется, в представлении не нуждаются. Ну разве что кроме interface. По умолчанию там указан eth0.2. Обычно в openwrt именно eth0.2 является wan-интерфейсом, но лучше проверить. Также стоит отметить опцию use_ssh. Если выставить ее в false, то совершенно логично, мониториться будет локальный интерфейс. Ну это на случай если у кого-нибудь в качестве роутера используется полноценный компьютер. Ну или кто-то запустит все это дело прямо на роутере
  • После этого запускаем main.py. Можно как напрямую (предварительно дав ему права на исполнения), так и передав интерпретатору питона
  • Если все работает, то устанавливаем supervisor (обычно есть в стандартных репозиториях)
  • Перемещаем файл yota.conf в папку /etc/supervisor/conf.d/ попутно подправив в нем пути к main.py и, если хотите, к файлу, в который будет писаться лог
  • И перезапускаем supervisor командой supervisorctl reload. Демон должен запуститься автоматически. Посмотрите напоследок логи. В них должно быть что-то вроде:
    2014-07-06 14:16:01,805 [INFO] yota | Initializing
    2014-07-06 14:16:11,497 [INFO] yota.web | CURRENT TARIFF: 512
    2014-07-06 14:16:11,712 [INFO] yota | Initialised
    2014-07-06 14:16:11,718 [INFO] yota | Starting
    2014-07-06 14:16:16,016 [DEBUG] yota.current_speed_provider | Current speed: RX: 5 TX: 9. Summary: 14, Time: 3
    2014-07-06 14:16:17,262 [INFO] yota.speed_control | Downgrade started: 2014-07-06 14:19:16.022307
    2014-07-06 14:16:18,315 [DEBUG] yota.current_speed_provider | Current speed: RX: 7 TX: 19. Summary: 26, Time: 2
    2014-07-06 14:16:20,575 [DEBUG] yota.current_speed_provider | Current speed: RX: 12 TX: 20. Summary: 32, Time: 2


Вот, собственно, и все. Понимаю, что это некоторое злоупотребление щедростью Yota (хотя, учитывая тарифы, щедростью ли?), но тем не менее смею надеяться, что никто ничего менять не собирается. В конце концов, людей, способных развернуть у себя такое, не так много. А если учесть, что мало кто из них пользуется Yota, то так и вообще мелочь.
Tags:
Hubs:
+28
Comments28

Articles

Change theme settings