Disclaimer: I stricltly encourage you not to use code from this article in production

In this article I’m…

  • Using an old webcam with a raspberry pi
  • Writing stupid telegram bot
  • Downloading images from bot
  • Stitching images into a gif with ffmpeg

Idea

So. Plants are weird. They move, like, A LOT, but you never see plants moving. So I’ve decided to spy on them. It was time to shake off the dust from my raspberry pi and the damn old webcam and write some code to ocassionaly take pictures.

I thought telegram bot would be a cool thing to do - it’s fast to code and there is no need to frequently access raspberry pi (which is some kind of pain in … ssh) to figure out what’s up.

Of course I had to visualize the result as a gif or something - ffmpeg was my hero of choice for such quest (ugh, such a show-off).

You probably would like to skip technical details and skip to result.

How to do this

CamBot (oh god sorry for this naming) is written in python with use of python-telegram-bot and APScheduler. Every 30 minutes it takes a picture with a webcam and sends to a list of telegram ids. It’s possible to request an image time you want with a /-command but who cares.

Note: for “security” (I’m a “secure” guy you know) reasons CamBot has a whitelist (should I be sorry for this naming?) of telegram ids. Do not try to find my bot. Just don’t. Please?

For those zero enthusiasts who would do the same there are some (dirty and in some cases I really mean it) hacks.

APScheduler on rpi

(And/or python <= 3.5.3)

Use version ==3.6.3 and for more convinience update CronScheduler with code from future releases:

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 on rpi and sending images

(And/or python <= 3.5.3)

My rpi on python 3.5.3 is ok ==13.1.

I wasted some time on trying to send images - read image from webcam to memory and send bytes but it seems like an old version of python-telegram-bot is somehow broken (or my arms are) and is not able to do that.

So (I had warned you in disclaimer!) I stopped wasting my time on this side-project and did that:

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)

Survive reboot of rpi without docker

Docker would be too heavy for my rpi so I considered using systemd. I’m no expert there but it works just fine for me. Here’s my 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

To install:

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

ffmpeg images to gif (on mac)

It’s dangerous to go alone. Take this… awesome one-liner:

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

Result!

Calathea Orbifolia

Calathea Orbifolia

Calathea Orbifolia

Calathea Orbifolia