Disclaimer: Настоятельно не рекомендую использовать код из статьи в продакшне

В это статье я…

  • Использую старую вебку с raspberry pi
  • Пишу тупой телеграм бот
  • Скачиваю картинки от бота
  • Склеиваю картинки в гифку при помощи ffmpeg

Идея

Итак. Растения странные. Они двигаются. Много двигаются. Но вы этого не видим. Я решил за ними пошпионить. Пришло время сдуть пыль со старой малинки и чертовски древней веб-камеры и написать немного кода для периодического сбора картинок.

Как мне показалось, на эту историю хорошо ложится создане телеграм бота - его можно быстро накодить, не нужно грепать логи на raspberry pi, чтобы разобраться, что там происходит.

Ну и, конечно же, результат надо как-то продемонстрировать, например, в формате гифки. С чем мне поможет ffmpeg.

Так. Здесь кто-то, наверняка, просто захочет посмотреть результат, без технических подробностей.

Как это устроено

CamBot (за нейминг простите) написан на python с использованием библиотек python-telegram-bot и APScheduler. Каждые 30 минут бот делает фотку при помощи вебки и отрпавляет её списку телеграм айдишников. Также фотку можно запросить через /-команду, но кому какое дело.

Note: из соображений “безопасности” (я же весь такое “безопасный”) у CamBot есть whitelist (мне нужно извиниться за нейминг, да?) айдишников телеграма. Не пытайтесь стучаться в моего пода. Просто не пытайтесь. Пожалуйста?

Для тех никого, кто захочет повторить это добро, есть несколько (и порой реально грязных) хаков.

APScheduler на малинке

(И с питоном версией <= 3.5.3)

Используем версию APScheduler ==3.6.3 и, для большего удобства, своруем код CronScheduler из последующих релизов:

from apscheduler.triggers.cron import CronTrigger as VendorCronTrigger

class CronTrigger(VendorCronTrigger):
    @classmethod
    def from_crontab(cls, expr, timezone=None):
        values = expr.split()
        if len(values) != 5:
            raise ValueError('Wrong number of fields; got {}, expected 5'.format(len(values)))

        return cls(minute=values[0], hour=values[1], day=values[2], month=values[3],
                   day_of_week=values[4], timezone=timezone)


# usage:
scheduler.add_job(
	...
	CronTrigger.from_crontab("*/30 * * * *"),
	...
)

python-telegram-bot на малинке, отрпавка сообщений rpi

(И с питоном версией <= 3.5.3)

На моей малинке с питоном 3.5.3 отлично работает библиотека с версией ==13.1.

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

Так что (я предупреждал!) я забил и решил не тратить лишнее время, сделав следующее:

Image.frombytes("RGB", res, img).save(file_name)
with open(file_name, 'rb') as f:
	# for whatever reason, bot doesn't want to work with bytes or BytesIO
	update.send_photo(chat_id=user_id, photo=f)

Переживаем рестарт малинки без докера

Docker был бы оверкилом для малинки, так что я решил задеплоить всё через systemd. Я не эксперт, но оно работает. Так выглядит cam-py.sevice:

[Unit]
Description=Cam Bot
After=multi-user.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 /home/someusername/cam_bot.py
User=someusername

[Install]
WantedBy=multi-user.target

Устанавливаем:

cp cam-py.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable cam-py
systemctl start cam-py

ffmpeg - из картинок в гифку (на mac)

Одному туда идти опасно! Возьми этот… восхитительный однострочник:

ffmpeg -f image2 -framerate 25 -y -pattern_type glob -i "*.jpeg" calathea.gif

Результат!

Calathea Orbifolia

Calathea Orbifolia

Calathea Orbifolia

Calathea Orbifolia