[Перевод] Лампа для слежения за фазами Луны на Raspberry Pi и Python
Работая над этой новой моделью лампы, я хотел внести кое-какие улучшения в исходный проект и вырваться из моей «программистской зоны комфорта». В предыдущем проекте я кое-что сделал на скорую руку, поступая так, как мне удобно и привычно, а не так, как следовало бы поступать. Мне, кроме того, хотелось исследовать пределы возможностей Raspberry Pi в деле обеспечения энергией светодиодов NeoPixel.
Устройство «лунной» лампы похоже на устройство лампы «солнечной». Она представляет собой сферу, собранную в технике складывания фигур оригами, называемой «снапология». Свет даёт светодиодное кольцо NeoPixel, а в основе всего этого лежит Raspberry Pi. Новая лампа имеет такое же разнообразие программ освещения, что и старая. В частности, речь идёт об аналоге имитации спокойного восхода Солнца по утрам и о «программе засыпания», когда всё начинается с яркого синего света, который постепенно угасает, доходя до уровня, на котором лампа становится ночником.
Начало «программы засыпания»
Тут, как и прежде, сферический абажур лампы собран из треугольников. Эти треугольники получаются путём разбиения 20 треугольных граней икосаэдра на 25 более мелких фрагментов. «Лунная» лампа собрана из 500 таких фрагментов, а в «солнечной» их было 320. Мне хотелось, чтобы размеры новой лампы были такими же, как и старой, поэтому «лунные» треугольники я сделал немного меньше «солнечных». Полагаю, можно сказать, что новая лампа имеет более высокое «разрешение», чем старая.
Грани икосаэдров, из которых собраны лампы. Слева — грань «солнечной» лампы, справа — грань «лунной»
Некоторых подробностей о снапологии я касаюсь в моём видео о «солнечной» лампе. Если вы хотите поближе познакомиться с этой разновидностью оригами и посмотреть примеры её применения — взгляните на это видео. Если же рассказать о снапологии в двух словах, то окажется, что при таком стиле работы из прямоугольных полосок бумаги делают многоугольники, которые скрепляют друг с другом, используя бумажные соединительные элементы. Тут не используется ни клей, ни что-то подобное.
Две жёлтых «снапологических» детали скреплены синим соединительным элементом
Когда дело дошло до написания программы для первой лампы, то оказалось так, что поучиться мне на этом проекте особо не удалось, так как всё заработало с первого раза. Я действовал в соответствии с руководством по установке Adafruit и смотрел учебные материалы по MicroPython, ожидая, что столкнусь с проблемами. Но никаких проблем не возникло. Ничего не сгорело после того, как я проигнорировал просьбу из руководства Adafruit, касающуюся размещения конденсатора между «плюсом» и «минусом». Светодиодам хватило питания, они не светили тусклее, чем должны. RGB-значения не были обращены: красный был красным, зелёный — зелёным, а синий — синим. Поэтому мне не понадобилось рыться в коде примера. Когда я, наудачу, попробовал написать программу в моей обычной веб-IDE, всё у меня получилось. И мой первый опыт работы с crontab оказался удачным. В общем — всё было хорошо, но освоить что-то новое, решая проблемы, мне не удалось.
Подача питания на светодиоды NeoPixel
Первая задача моей учёбы заключалась в том, чтобы разобраться с питанием светодиодов NeoPixel от Raspberry Pi. Практически во всех встреченных мной описаниях разработок, подобных моей, использовался отдельный источник питания для светодиодов. Я нашёл несколько хороших видео, где показывали, как скрыть в конструкции устройства подходящий источник питания, но я почти не видел проектов, где светодиоды NeoPixel питались бы напрямую от 5В-пина Raspberry Pi. А на сайте Pi Hut, помимо других очень точных технических сведений, мне попалось такое предостережение общего характера:
… рекомендуется подавать питание непосредственно с Raspberry Pi лишь на незначительное количество светодиодов NeoPixel.
А «незначительное количество» — это сколько? И что произойдёт в тот момент, когда количество светодиодов превысит это таинственное «количество»? Будет ли единственным последствием этого постепенное уменьшение яркости светодиодов? Или результат окажется более интересным, скажем — Raspberry Pi просто взорвётся?
Красный провод подаёт 5 В на светодиодное кольцо
То, что я знаю об электричестве, то, что я в нём понимаю, до сих пор, по большей части, основано на том, что я изучал в школе. А именно, мне известно, что существует «треугольное» представление закона Ома, выражающее взаимоотношения между напряжением, силой тока и сопротивлением. В общем, нам нужно «топливо», «жар» и «кислород», а для того чтобы узнать электрический ток мы делим «топливо» на «кислород», и чем больше у нас «огня» — тем шире поток, и тем выше давление электронов. Правильно? Вроде, так оно и есть?
Я решил копнуть глубже.
На ресурсе RasPi.TV я узнал, что плата Raspberry Pi Zero использует, самое большее, 300 мА. А из одного хорошего видео я узнал о том, как найти сведения об ограничениях по току, применимых к Raspberry Pi. Большинство моделей этих плат имеют самовосстанавливающиеся предохранители, которые срабатывают при токе примерно в 2,5 А. Но такого предохранителя нет в Raspberry Pi Zero, в результате 5 В-пин подключается напрямую к источнику питания. На плате нет предохранителя! «А почему бы тогда не подключить вышеописанный мощный источник питания прямо к Raspberry Pi?», — подумал я.
При этом у меня не было полного понимания того, что может пойти не так, если подключить к плате слишком большую нагрузку. В попытке найти хоть сколько-нибудь точную интерпретацию понятия «незначительное количество светодиодов NeoPixel», я воспользовался поиском по Stack Exchange и нашёл две жемчужины мудрости:
Зачем вы вообще размышляете об использовании Raspberry Pi в роли источника питания? … плата сыграет роль дорогого предохранителя.
Пины Raspberry Pi Zero напрямую подключены к питанию. Если их как следует перегрузить — можно сжечь дорожки печатной платы.
Получается, что всё дело — в «жаре»! Мне не хотелось бы превратить мою бумажную луну в пылающий метеорит. Поэтому я подумал, что должен обеспечить запас прочности моей конструкции. В результате я решил, что «незначительное количество» может означать 16 светодиодов NeoPixel, но не 24 или 60.
У меня получилось, аккуратнее чем раньше, припаять провода к кольцу светодиодов. Правда, при этом мне ещё и удалось прожечь дыру в нашей виниловой скатерти.
Кольцо светодиодов NeoPixel с припаянными проводами, установленное в основании лампы
В руководстве Adafruit по работе со светодиодами NeoPixel сказано, что один такой светодиод потребляет, самое большее, 60 мА. Поэтому моё кольцо из 16 светодиодов должно потреблять 960 мА, то есть — чуть меньше 1 А. Эта теоретическая цифра была близка к показателям, полученным с USB-измерителя мощности.
Приближение к 1 А на полной яркости светодиодов
Управление лампой из браузера
Следующим барьером моего обучения была организация такой схемы управления лампой, при использовании которой не наблюдалось бы больших задержек между выбором программы, задающей параметры работы лампы, и запуском этой программы.
Элементы управления моей «солнечной» лампой содержатся в форме, скрытой на моём персональном сайте. Когда выбирается программа работы лампы — PHP-программа записывает её имя в JSON-файл. Например, это может выглядеть как {«program»:«morning»}
. Python-скрипт на Raspberry Pi, благодаря crontab, ежеминутно проверяет этот файл на предмет того, имеется ли в нём запрос на изменение программы работы лампы.
Всё это работало, но не идеально. Это — вроде как если бы тостер постоянно, дожидаясь моего «да», спрашивал бы меня о том, нужен ли мне поджаренный хлеб. Если мне нужен тост — я сам «сообщу» об этом тостеру!
Если говорить о попавшихся мне Arduino-проектах, похожих на то, что мне нужно, то у меня возникло такое ощущение, что таких проектов имеется довольно много. Но я решил не отходить от Raspberry Pi. Я знал о том, что мне понадобится веб-сервер, и мне было интересно узнать о том, подойдёт ли мне Lighttpd, так как он, по всей видимости, применяется для управления хэллоуинскими световыми шоу.
Встреча с давнишним врагом
Я начал воплощать в жизнь идеи из руководства по установке Lighttpd с PHP и Python, но очень скоро на моём пути возник давнишний враг: разрешения для файлов. Установка не удалась, я попробовал Apache, после чего был вынужден принять тот факт, что мне необходимо разобраться с CHMOD. Тогда я прочитал руководство по разрешениям для файлов и решил остановиться на Apache. Очень скоро мне удалось подключиться напрямую к лампе.
Следующим приключением был запуск Python-скрипта из браузера. Я ожидал, что эта задача окажется гораздо сложнее, и что мне, возможно, придётся освоить некий новый фреймворк, вроде Flask. Но всё решила одна строка PHP-кода:
system("sudo python3 pulse.py");
Следующим камнем преткновения стал тот факт, что многие из моих программ, управляющие работой лампы, выполняются в цикле
while true
. Сначала у меня получилась веб-страница, которая, похоже, после нажатия на кнопку, никогда не загружалась полностью. Правда, скоро я выяснил, что скрипт может выполняться в фоне, для чего ему надо передать некоторые особые аргументы: system("sudo python3 pulse.py myargs /dev/null/ 2>&1");
Мне, кроме того, пришлось разобраться с отзывом на мой предыдущий проект по поводу корявого использования WGET для передачи файлов с моего сайта на Raspberry Pi. Редактирование Python-файла в веб-IDE и его передача — это одно, но, конечно, PHP — это совсем другое дело, учитывая передачу лишь выходных данных программы. Какие-то программные конструкции через WGET не передаются. Я почитал материал по безопасному копированию данных на сайте Raspberry Pi и перешёл на гораздо более приличную схему редактирования кода в Sublime на моём Pixelbook. Я, наконец, стал пользоваться SCP для передачи файлов на Raspberry Pi.
Я не знаю, насколько всё это близко к «хакам», не знаю о том, стоит ли мне, развивая проект и развиваясь самому, изучить Flask или что-то подобное, но если говорить о запуске простого Python-скрипта из браузера, то моя конструкция работала хорошо. Из одного руководства я узнал о том, что с использованием Flask светодиоды включаются практически мгновенно. А при моём подходе имеется короткая (вполне приемлемая) задержка. Я подозреваю, что причиной этой задержки является тот факт, что моя программа начинает работу с «убийства» существующих Python-процессов:
#функция, убивающая процессы.
def killAllButParent():
for proc in psutil.process_iter():
pinfo = proc.as_dict(attrs=['pid', 'name'])
procname = str(pinfo['name'])
procpid = str(pinfo['pid'])
if "python" in procname and procpid != str(os.getpid()):
print("Stopped Python Process ", proc)
proc.kill()
Использование сайта Visual Crossing для получения сведений о фазах Луны
Полумесяц
Я надеялся, что лампа сможет нагляднее демонстрировать фазы Луны в том случае, если я применю в её конструкции разделитель, показанный ниже. Но, даже когда надо было показать полумесяц, от элементов разделителя отражалось так много света (а это не входило в мои планы), что эффект от него, в общем-то, терялся. Правда, сами эксперименты с разделителем оказались довольно-таки поучительными.
Разделитель
Сведения о фазах Луны я нашёл на сайте Visual Crossing. Он даёт своим клиентам разнообразные API, позволяющие получать погодные и астрономические данные. После того, как я зарегистрировал на этом сайте бесплатную учётную запись, я смог воспользоваться их системой описания фаз Луны.
Система числового описания фаз Луны с сайта Visual Crossing
Интересующий меня API возвращает JSON-файл. Потом Python-скрипт извлекает из этого файла данные о фазе луны и использует эти данные для включения нужных светодиодов.
Visual Crossing — это, определённо, сервис, к которому я ещё вернусь, так как пользоваться им очень просто.
Итоги
Если говорить о снапологии, то я понимаю, что не уверен в том, что использование большего количества более мелких элементов может помочь в создании более качественной лампы, так как при этом возникают трудности с приданием лампе сферической формы. Но в остальном могу сказать, что моя лампа хорошо выполняет свои функции. А если говорить о дальнейшем развитии подобных проектов с точки зрения используемого в них ПО, то я думаю, что моим следующим шагом станет изучение Flask и MQTT.
Хотите сделать свою «лунную» лампу?