When spinning up a new Debian VM using KVM virsh console <vm>
does not work. The VM needs a running TTY for this:systemctl enable serial-getty@ttyS0.service
systemctl start serial-getty@ttyS0.service
A year in 4 minutes: Timelapse with 10k pictures
The Setup
The timelapse was shot with a Raspberry Pi 3 Model B and the camera module v2. The Pi was installed inside so there was no need to protect it against the weather. To better mount it to the wall the Pi was put inside a case. The benefits of having the Pi mounted inside are also stable Wi-Fi access and a more or less stable power supply (more on that later).


The case has openings for the USB ports, the RJ45 port, HDMI, etc. Since I only needed the power supply I used gaffer tape to seal all other openings.
Taking 10,000 Pictures Automatically And Unattended
Requirements
When regularly taking pictures over such a long period of time a simple cron job is not enough. I wrote a little software which fulfills the rather complex requirements, notably:- Only take pictures during the day and not when it’s night
- Backup the pictures to a remote location
- Delete pictures to avoid the SD card in the Pi running low on disk space – but only after performing a MD5 check to ensure the picture which will be deleted has been backed up successfully
- Recover from unexpected reboots, e.g. on power failure which occasionally happens
- Deal with a flaky or interrupted internet connection, even for a longer time
- Monitor the temperature of the Raspberry Pi
- Notify if pictures weren’t taken or any other exceptions occured
- Provide a web interface which displays the latest picture taken and a temperature graph
Taking Pictures With raspistill
I usedraspistill
to take pictures with the following parameters:
/usr/bin/raspistill --awb auto --nopreview --raw --quality 100 --encoding jpg --output photo.jpg
.
When using --raw
raw bayer data is added to the jpeg metadata. This results in files between 12 MB and 15 MB in size. At the time of implementing I was not sure if I would need raw data so I decided to use --raw
just in case. The pictures have a resolution of 3280 x 2464 pixels
To only take pictures during the day I used PHPs built in date_sunrise and date_sunset functions. I went with an interval of 30 minutes of taking pictures.
Backing Up The Pictures
The backup was done to a remote location usingrsync
over SSH. Originally I used --checksum
to really make sure files were transferred correctly. Over time and with more and more files this really became disk I/O consuming so I removed it again. By default rsync
uses modification time and size for comparison which works as well (and a lot faster) in this case.
I also used --bwlimit
to avoid blocking the entire upstream with transferring pictures. Once the entire upstream connection is blocked the external monitoring is unable to check the status of the Pi and will trigger an alert.
Removing Old Pictures
Every week a cron job deletes all pictures which were successfully backed up and not older than 14 days. Before deleting a picture from the SD card the MD5 checksum of the local and remote file is compared.Monitoring And Webinterface

/opt/vc/bin/vcgencmd measure_temp
. Especially when the Pi is exposed to direct sunlight in the afternoon the core temperature goes up to nearly 80 °C.
Post-processing
Stabilizing (Lucas–Kanade method)
Because of the temperature changes throughout the day and the Pi being mounted on a wood plank the Pi moves very slightly as temperature rises and falls again. This movement can be clearly seen when looking at the footage as the picture detail is not always 100% identical. To eliminate this movement between single pictures the Lucas–Kanade method can be applied. I went with ImageJ and a corresponding plugin which implements said algorithm. The plugin only exports in tif format so a second step is required to convert all files back to jpg or png. Depending on the scenery the plugin achieves best results when its run as the first step in the tool chain.Cropping
The camera of the Raspberry Pi takes pictures with a picture format of 4:3. Since I wanted to have a HD movie in the end I needed to crop all the pictures to 16:9. A little script did the job but many existing tools should work as well, e.g. GIMP. To achieve the 16:9 ratios the script removed a little bit from the top and bottom of every picture.Deflickering
Finally the footage needs to be deflickered. There are several scripts available, for example timelapse-deflicker, which is a Perl script, or deflicker, which is a Python module. Both work very well. The Python module also supports asigma
parameter which can be used to ignore pictures which are very light/dark.
Rendering The Timelapse
To render the final movie I used Kdenlive which is able to import a bunch of images and creates a so called Slideshow Clip. If you need more control over the rendering process you might want to take a look atffmpeg
oder mencoder
.
Further reading
GitLab Runner on Uberspace
23.09.2017: Updated instructions for 10.0.x release of GitLab Runner.
This post describes how to setup gitlab-runner on an Uberspace using the shell executor.
Download gitlab-runner-linux-amd64
Download the Runner binary into the ~/bin directory and make it executable:
$ mkdir ~/bin $ cd ~/bin $ wget https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64 $ chmod +x gitlab-runner-linux-amd64
Create a working directory for the Runner:
$ mkdir ~/gitlab-ci
Get configuration details for the Runner
In your GitLab project navigate to Settings > CI/CD Pipelines. Find the URL for the runner setup and the registration token as shown in the picture below:
Register the Runner
Provide the configuration details when asked and make sure to choose shell as executor:
$ ./gitlab-runner-linux-amd64 register WARNING: Running in user-mode. WARNING: The user-mode requires you to manually start builds processing: WARNING: $ gitlab-runner run WARNING: Use sudo for system-mode: WARNING: $ sudo gitlab-runner... Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/): https://gitlab.com/ci Please enter the gitlab-ci token for this runner: <TOKEN> Please enter the gitlab-ci description for this runner: [<DESCRIPTION>]: Please enter the gitlab-ci tags for this runner (comma separated): <YOUR TAGS> Whether to run untagged builds [true/false]: [false]: Whether to lock Runner to current project [true/false]: [false]: Registering runner... succeeded runner=wenFG1n6 Please enter the executor: docker, docker-ssh, parallels, shell, docker+machine, ssh, virtualbox, docker-ssh+machine, kubernetes: shell Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
Create a daemon to start the Runner
Create a daemon to start your GitLab Runner automatically on reboot and have it supervised. See https://wiki.uberspace.de/system:daemontools for reference.
First, setup your service directory:
$ test -d ~/service || uberspace-setup-svscan
Create a script called gitlab-ci inside your ~/bin directory. Note the exec command which prevents spawning a new process and allows the daemontools to fully control the Runner:
#!/usr/bin/env bash exec ~/bin/gitlab-runner-linux-amd64 run --working-directory ~/gitlab-ci
Make the script executable:
$ chmod +x ~/bin/gitlab-ci
Activate the daemon:
$ uberspace-setup-service gitlab-ci ~/bin/gitlab-ci Creating the ~/etc/run-gitlab-ci/run service run script Creating the ~/etc/run-gitlab-ci/log/run logging run script Symlinking ~/etc/run-gitlab-ci to ~/service/gitlab-ci to start the service Waiting for the service to start ... 1 2 3 4 5 6 started! Congratulations - the ~/service/gitlab-ci service is now ready to use! To control your service you'll need the svc command (hint: svc = service control): To start the service (hint: u = up): svc -u ~/service/gitlab-ci To stop the service (hint: d = down): svc -d ~/service/gitlab-ci To reload the service (hint: h = HUP): svc -h ~/service/gitlab-ci To restart the service (hint: du = down, up): svc -du ~/service/gitlab-ci To remove the service: cd ~/service/gitlab-ci rm ~/service/gitlab-ci svc -dx . log rm -rf ~/etc/run-gitlab-ci More information about controlling daemons can be found here: https://uberspace.de/dokuwiki/system:daemontools#wenn_der_daemon_laeuft
For details on how to manage a daemon see https://wiki.uberspace.de/system:daemontools#wenn_der_daemon_laeuft
That’s it!
Your GitLab Runner should now be ready to process your builds if your project is configured correctly. See https://docs.gitlab.com/ce/ci/ for reference.
Chrome 56: Install and use Extensions
Starting with Chrome 56 on Debian you might end up having no Extensions. To re-enable them again you have to start Chrome with
--enable-remote-extensions
To make this a default add this flag to the default flags in /etc/chromium.d/default-flags:
# Enable extensions export CHROMIUM_FLAGS="$CHROMIUM_FLAGS --enable-remote-extensions"
Reference: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=851927
Waiting for server to accept SSH connections
Sometimes you need to wait for a just booted server to accept SSH connections. This can be solved with a one-line bash script:
until nc -w 10 -z $SERVER_IP 22; do echo "SSH not available" && sleep 5; done