Я запрограммировал кошачью кормушку, чтобы она выдавала мне конфеты за код

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.
Я смеюсь над этой историей все выходные, так что не могу не поделиться. Засидевшись до поздней ночи на Amazon, я купил автокормушку для животных PetKit FreshElement Solo. У меня имелось две проблемы, с решением которых она могла мне помочь: во-первых, мне сложно было себя замотивировать на работу над побочным проектом, во-вторых, я всерьез подсел на миндаль в темном шоколаде с морской солью из Target. Раз уж я кодер-мартышка, так почему бы не подкормить внутреннюю мартышку, когда выдаю код?



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

Вот тизер. Код лежит здесь. Чтобы запустить самим, вам придется выбрать имя пользователя и пароль по этой ссылке.

Обзор


REST API – это, по сути, язык, на котором говорит интернет. У большинства продуктов общение между устройством и сервером происходит посредством их. Мне попался старый фрагмент кода на Python, в котором уже была реализован процесс авторизации, так что было от чего оттолкнуться.

Я покопался в поисках API-запроса для кормления вручную, скопировал его на Python с помощью Requests и привязал скрипт к кнопке на своем контроллере для стриминга – она же отвечает за отправку коммита командой ctl+enter.

Есть и другие способы (причем получше) получить тот же результат – AWS, вебхуки, хуки в git (хуки в git – пожалуй, самый надежный вариант), но мне хотелось, чтобы система работала строго локально, чтобы конфеты не сыпались, если я уеду куда-нибудь. Нет смысла всё усложнять! В худшем случае забуду нажать на кнопку и съем меньше сладкого.

Аппаратное обеспечение


Говорю без преувеличений: для выдачи вкусностей ничего лучше этого устройства не найдешь. Порция еды отмеряется при помощи аккуратненького механизма с силиконовым стержнем и силиконовыми лопастями, отделяющими нужное количество, которое и выпадает в лоток выдачи. Ловко придумано и для продуктов безопасно – они не крошатся и не портятся.




А это просто трогательно:



Прилагается шкала для измерения частиц еды; говорится, что размер должен быть менее 12 миллиметров. Но измерение и высыпание происходит примерно так:



поэтому даже если там все 12 миллиметров, может нормально пройти под углом. Я планирую поэкспериментировать с кусочками вяленого мяса и сырными шариками. Там гигроскопическая прокладка сверху, чтобы всё оставалось свежим… думаю, можно изощряться со спокойной душой.

На момент написания статьи такие кормушки стоили 70 $ за штуку, но работают они отлично и сделаны на совесть. Купить можно здесь.

Приложение


Приложение неплохое. Единственное, немного странно с ним работать, когда домашних животных у тебя нет… Пришлось назваться собакой и выбрать себе породу.



Зато после этого я смог воспользоваться API. После нескольких тестов приложения на предмет размера порции, я узнал, что половина оборота – это примерно десятая часть стакана, то есть в среднем пять конфет.

Изыскания


Для ручного запуска кормления я использовал Packet Capture для Android.



И нашел там вот такой запрос:



Палочки-выручалочки не обнаружилось, мне пришлось просмотреть несколько групп запросов, чтобы отыскать то, что требовалось. Но мы видим /latest/d4/saveDailyFeed в качестве конечной точки, а это существенная подсказка! Секция URLENCODED говорит нам, что amount, time и deviceId входят в URL… Значит, всё можно повторить локально! В этой статье мы с Энди описали, как это делается на десктопе.

Код


Код можно найти здесь.

Я начал с ответвления PyPetKit авторства geeks4hire. Всё, что касается авторизации, там было уже сделано за меня, оставалось только добавить выход на API. Из упомянутого выше пакета я узнал, в какую конечную точку нужно метить, и добавил непримечательную функцию для отправки запросов к API в моё ответвление пакета:

def send_api_request(self, path, method="POST", params=None, json=None):
        """
        Sends an API request.
        """
        custom_headers = {
            "X-Session": self._access_token,
            "User-Agent": "PETKIT/7.26.1 (iPhone; iOS 14.7.1; Scale/3.00)",
            "X-Timezone": f"{round(self._tzone._utcoffset.seconds/60/60)}.0",
            "X-Api-Version": "7.26.1",
            "X-Img-Version": "1",
            "X-TimezoneId": self._tzone.zone,
            "X-Client": "ios(14.7.1;iPhone13,4)",
            "X-Locale": self._locale.replace("-", "_"),
        }

        return requests.request(
            method,
            self._apiServerBaseURL + path,
            headers=custom_headers,
            params=params,
            json=json,
        ).json()


Выглядит сложно, но все заголовки скопированы у человека, который делал всё ровно то же самое, но на айфоне. Здесь используются запросы (requests.request) для создания HTTP-запроса произвольным методом. То есть то самое, что делает браузер, только на Python. В той статье про скрейпинг, о которой говорилось выше, мы разбираем это подробно – если есть возможность скопировать заголовки, это многое дает!

И вот, чтобы добраться до вожделенных конфет, только и нужно, что:

from pypetkit import PetKitAPI
from settings import (
    API_USERNAME,
    API_PASSWORD,
    API_COUNTRY_CODE,
    API_LOCALE_CODE,
    API_TIMEZONE,
)
from pprint import pprint

petkit_api = PetKitAPI(
    API_USERNAME, API_PASSWORD, API_COUNTRY_CODE, API_LOCALE_CODE, API_TIMEZONE
)

#! Sign in
petkit_api.request_token()

print(f"Authorized: {petkit_api.is_authorized}")

#! Send the actual feeding request
pprint(
    petkit_api.send_api_request(
        "d4/saveDailyFeed", params={"deviceId": 10019856, "amount": 10, "time": -1}
    )
)


Мы задействовали реализацию авторизации из существующего кода и теперь посылаем запрос. Параметры соответствуют запросу, который мы обнаружили, когда вручную активировали кормушку из приложения. Я, конечно, попытался уменьшить размер порции, но, похоже, десять единиц – минимальное количество, которое может отмерить механизм. -1, кажется, запускает немедленную выдачу еды. В приложении можно задавать часы кормления, уверен, что и даты тоже.

Если всё работает как надо, выдача с run.py будет такой:



Затем негромкий писк и восхитительный звук конфет, падающих в (не заморачивайтесь, не так уж это и унизительно) миску.

«Развертывание»


Развертывание – это, конечно, сильно сказано, но иначе не назовешь. Система работает локально, чтобы еда не поступала, когда меня нет дома. У меня есть Elgato Stream Deck, который я очень люблю, и с его помощью я создал горячую клавишу.



System:Hotkey отправляет Ctl+Enter, чтобы отослать коммит, когда я допишу. System:Open открывает python c://run.py и тем самым обеспечивает мне сладкое шоколадное подкрепление правильных программистских привычек.

Всё это абсолютно точно можно реализовать «лучше», но в облаках и всяком таком просто нет необходимости – это маленький проект чисто для смеха.

В заключение


Огромное спасибо тем, кто провел обратную разработку в отношении этого агрегата до меня. Мне только и осталось, что найти конечную точку и создать запрос – проще простого. Не знаю, подстегнет ли это меня в самом деле писать больше кода, но у других я такого еще не видел и рад, что предпринял эту попытку. Она определенно подсластила мне решение проблем с непрерывной интеграцией.

Примечание о безопасности


Как вы увидите, данные у этих продуктов отправляются простым текстом, что на сервер, что с сервера. Это очень сомнительно. Также они отправляют все сведения о местонахождении, что еще более сомнительно. Я бы посоветовал пользоваться этим приложением по минимуму и установить одноразовый пароль, на случай если произойдет утечка данных… а это рано или поздно вполне может случиться.

Ссылки


PETKIT Fresh Element Solo
Репозиторий на Github
Packet Capture для Android
Elgato Stream Deck
Миндаль в темном шоколаде с морской солью на Target (серьезно, он обалденный)
Источник: https://habr.com/ru/company/productivity_inside/blog/693266/


Интересные статьи

Интересные статьи

Почти половина населения мира подвержена риску заражения малярией.По оценкам ВОЗ, в 2019 году от этой болезни погибло более 400 000 человек. Стартап ZzappMalaria над...
Я давно знаком с Битрикс24, ещё дольше с 1С-Битрикс и, конечно же, неоднократно имел дела с интернет-магазинами которые работают на нём. Да, конечно это дорого, долго, местами неуклюже...
Когда речь заходит об инспекции кода, внимание людей обычно сосредоточено на том, кто её проводит. Но разработчик, который писал код, играет в процессе такую же важную роль, как и про...
В Челябинске проходят митапы системных администраторов Sysadminka, и на последнем из них я делал доклад о нашем решении для работы приложений на 1С-Битрикс в Kubernetes. Битрикс, Kubernetes, Сep...
Тема статьи навеяна результатами наблюдений за методикой создания шаблонов различными разработчиками, чьи проекты попадали мне на поддержку. Порой разобраться в, казалось бы, такой простой сущности ка...