I spend nearly every weekend with my SLR camera, but the last thing I want to do when I get home is pull out my computer to upload, organize, and backup the photos. I just feels like work. I know newer cameras have WiFi and all that, but my trusty D3300 isn’t going to be replaced anytime soon. That’s where I got the idea for PiPhoto.
PiPhoto
PiPhoto makes your raspberry pi automatically upload your photos when you insert your SD card.
Here is a video showing PiPhoto uploading photos to OSX:
In this post, I’ll discuss the core components and challenges I faced. I’ve open-sourced the project on Github.
Mounting the SD Card on Insert
The first challenge I faced was how to automatically mount the sd card when it is inserted inserted into the Raspberry Pi. UDev is the commonly accepted way to do this. With some help from the Arch Wiki, I settled upon this rule:
ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem", RUN{program}+="/usr/bin/systemd-mount --no-block --automount=no $devnode /media"
This tells the system to mount any filesystem block device to /media
when it is inserted into the USB port. Just pop that file into /etc/udev/rules.d/
and you're good to go.
Triggering A Command on Mount
Once the sd card is mounted, I wanted to trigger a command to be run that would upload the photos to my computer, cloud, whatever. Though systemd is controversial, I found it was pretty easy to write a quick service that did just that:
[Unit]
Description=PiPhoto Trigger on Usb Mount
Requires=media.mount
After=media.mount
[Service]
ExecStart=/usr/local/bin/piphoto
Type=oneshot
[Install]
WantedBy=media.mount
This systemd service triggers the piphoto
command to execute when the /media
directory is mounted.
Un-Mounting When The Job is Finished
Once the media are uploaded, I wanted the pi to unmount the sd card. This actually turned out to be a bit tricky: If the piphoto
command called unmount
, then systemd would kill the piphoto.service
, and it would report an error. Alternatively, if you have the systemd service call umount
after exit using ExecStartPost
, then it catches the cyclic logic and throws an error.
My solution was to have the systemd process unmount the drive, but do so in a different process. A quick and easy way to achieve this was to use at
:
[Service]
ExecStart=/usr/local/bin/piphoto
Type=oneshot
ExecStartPost=/bin/bash -c 'echo "systemd-umount /media" | at now'
This is a bit of a hack, so I’m open to better solutions :D.
Adding LED Feedback
Okay, so now I have the pi:
- mounting the sd card when inserted
- executing the piphoto command
- umounting the sd card when complete
Next, I wanted to add some user feedback so I know if the job failed. To do this, I leveraged the pi’s on-board LEDs.
As noted in the Pi Docs, you can change how the LED behaves by sending a string to /sys/class/leds/led{number}/trigger
. There are a number of different options such as timer
to flash the led and default-on
to keep it steady.
First, I made the green light flash while the photos were uploading:
echo timer | tee /sys/class/leds/led0/trigger
and solid green when the syncing was complete:
echo 'default-on' | tee /sys/class/leds/led0/trigger
Finally, I wanted the red led to flash if the sync command failed. Putting this all together into the pihole
script:
# start flashing the green led
echo timer | tee /sys/class/leds/led0/trigger
# upload the files
rsync -rav -e ssh /media ...
sync_status=$?
# Indicate success or failure
if [ $sync_status -eq 0 ] ; then
# sync successful
echo 'default-on' | tee /sys/class/leds/led0/trigger > /dev/null
else
# sync failure
echo 'none' | tee /sys/class/leds/led0/trigger > /dev/null
echo timer | tee /sys/class/leds/led1/trigger > /dev/null
fi
Using in Practice
Above I’ve detailed the basics of how PiPhoto works. In the open-source release, you can easily change the sync command to fit your needs. I’ve included guides for:
In addition, I added error handling and a Udev rule to reset the leds when you remove your SD card.
I’ve already found PiPhoto to be a great convenience in my life. I hope you do too! If you find problems or have ideas, please hit up the issue tracker on github.
Originally published at https://lou.dev.