MicroPython на ESP32: отправка данных в Google Sheets
Однажды в один прекрасный летний выходной вместо того, чтобы пойти на на пляж или куда-нибудь еще, я находился дома и размышлял, как бы отправить что-нибудь с ESP32 в документ Google Sheets, используя MicroPython. Пусть даже ситуация будет совсем классической, и роль данных будут играть температура и влажность, героически измеренные всенародно любимым датчиком DHT22. Так всё и началось.
Быстрый поиск в Google показал, что идея не новая, и существуют люди, которые уже пытались отправлять что-то в Google таблицы, и их попытки даже увенчались успехом. Прочитав несколько статей об этом, были замечены две вещи: либо использовалась таблица, доступ к которой не ограничен ни для кого, либо проект использует посредника, такого как PushingBox или IFTTT.
Но ведь Google Sheets предоставляют прекрасный HTTP API, почему же просто не послать POST-запрос прямо с ESP, чтобы записать что-то в таблицу? Однако, на самом деле это не так просто, ведь Google Sheets заботиться о безопасности и требует аутентификации. Google Sheets API предлагает нам ровно два способа для подтверждения нашей с вами подлинности: API keys или OAuth2. Может показаться, что всё хорошо, и мы можем просто создать API key в Google IAM, забыть о безопасности и ротации этого API key и использовать его вечно для записи данных в нашу таблицу. Однако, к сожалению (или к счастью), этот сценарий не сработает, ведь Google Sheets API принимает API key, если мы хотим только почитать данные из таблицы, но если мы хотим туда что-то записать, то будьте любезны, используйте OAuth2.
И тут начинаются сложности. Сначала нам нужно создать service account в Google IAM, а потом там же сгенерировать ключик RSA для этого service account. Хорошо, пока вроде бы несложно. Дальше наш ESP микроконтроллер должен соорудить JWT запрос, включить в него текущее время, а потом еще и подписать этот запрос с помощью алгоритма RSA-SHA256. Потом наш ESP должен отправить этот запрос в Google OAuth2 service, который должен нам вернуть OAuth2 token, который наконец-то может быть использован при обращении к Google Sheets API.
Итак, перечислим то, что обязательно должно быть на ESP, чтобы записать строчку в Google Sheets: HTTP клиент, JSON parser, часы с правильным временем или же NTP client, реализация подписи с RSA-SHA256. К счастью, MicroPython нам любезно предоставляет почти всё из этого списка за исключением RSA-SHA256. Если быть точным, то MicroPython умеет считать SHA256, но вот создавать RSA подписи он еще не научился. Омрачает жизнь еще тот факт, что RSA подпись требует довольно много вычислений и памяти, но ESP микроконтроллеры не такие быстрые и ёмкие, как процессоры на обыкновенных PC.
Предположу, что сложность процесса получения OAuth2 token и отсутствие реализации RSA алгоритма для MicroPython и побудили использовать либо таблицы с открытым доступом, либо посредников, которые могут взять на себя процесс аутентификации. Конечно, как security engineer по роду деятельности, я не мог смириться с таблицей в открытом доступе, которая тем более будет содержать такую страшно конфиденциальную информацию, как температура и влажность воздуха в моем жилище. И опять же, как security engineer по роду занятий, я не люблю всяких middleman’ов. В результате не осталось другого выбора кроме воплощения в жизнь процесса аутентификации на ESP.
Как уже было сказано выше, MicroPython любезно предоставляет следующее:
- ujson для работы с JSON
- ntptime.py для получения времени по протоколу NTP
- uhashlib для хэшей SHA256
- http.client для работы с HTTP
Остается только раздобыть RSA подпись. Одно из главных правил в криптографии гласит: никогда не пишите сами никакие криптографические алгоритмы, а используйте уже существующие библиотеки. Это правило мы знаем, и быстро нашли довольно популярную библиотеку python-rsa, которая предоставляет алгоритм RSA, написанный на чистом Python. Помимо создания подписей, библиотека позволяет их проверять, шифровать и дешифровать тексты, загружать ключики из файлов и так далее. Все эти операции делают библиотеку немного тяжеловатой для худенького ESP. Поэтому было решено библиотеку укоротить и оставить лишь создание подписи, которое нужно для формирования JWT запросов. Пришлось даже удалить загрузку ключей из PKCS1, потому как это требовало портирования pyasn1. В процессе обрезания библиотеку внезапно выяснилось, что в MicroPython отсутствуют некоторые стандартный для CPython функции, например, возведение в степень по модулю. Попутно пришлось это упущение исправить. В результате получилась новая маленькая библиотечка micropython-rsa-signing, все желающие могут ей насладиться.
За основу был взят один из прошлых проектов. В целях удобства и экономии времени, сначала все было написано и протестировано на ноутбуке. И вот настал момент залить и запустить всё это дело на ESP. Первая попытка была с ESP8266, но она провалилась. RSA подпись работала очень медленно, но основная проблема заключалась в том, что процесс не мог завершиться, потому что попросту не хватало памяти во время возведения в степень по модулю. Были испробованы некоторые оптимизации, была даже попытка скомпилировать код вместе с МicroPython, но всё это не увенчалось успехом.
Последняя надежда была на ESP32, которая, как известно, чуть более быстрая и вместительная, чем ESP8266. До этого я не экспериментировал с ESP32, и c eBay была выписана новая платка с ESP32. И внезапно всё заработало. Код больше не ругался на недостаток памяти и вообще работал куда быстрее.
Код лежит на GitHub. Там же есть инструкции, правда, не сильно подробные и пока только на английском. Еще был создан проект на Hackaday.io. Надеюсь, удастся найти время и описать всё подробнее и на русском языке.