Goal
Make a really simple timelapse camera. Runs on a Pi and uploads photos when WiFi available
- Always taking photos and saving.
- Always trying to upload photos.
- Wifi setup to act as host or client
Option: Battery Bank
Not that efficient but handy for traveling. Plug-in to battery bank (via usb). Using 10,000 mAh we get performance:
- Calculator says only lasts 20 hours . A basic test agrees with this
- With a Pijuice and battery, to top-up the 4000mAh battery takes 60%.
Wifi Connection and Uploads
- On boot:
- if Host Mode, starts as an AP.
- if Normal Mode and there is WiFi available, connect
- if Normal Mode and there is on WiFi available, run without connecting
- Uses list of WiFi networks (wpa_supplicant) to try to connect to internet
- Tried https://github.com/jasbur/RaspiWiFi to open an Access Point (“host mode”). This kindof worked, but at some point I lost all access after a host-reset. Checking the code, it’s pretty gun-ho in reset (rm -f style). Be careful or find another!
- (A different option, untried, is to only connect to WiFi and upload when power is supplied (via PiJuice events))
Setup Camera and WiFi
# Basics and some dependancies
sudo apt-get install -y vim git python3-pip libopenjp2-7 libtiff5
git config --global credential.helper store
# Pi-Timolo for TMV
git clone https://github.com/brettbeeson/pi-timolo.git pi-timolo-root
ln -s pi-timolo-root/source pi-timolo
# ...and its requirements
python3 -m pip install --user -r requirements.txt
cd pi-timolo
crontab -e # blank
./install-tmv.sh # append to crontab
sudo apt-get install rclone
echo IMPORTANT: configure rclone or:
cp ./rclone.conf ~/.config/rclone/
Limiting Energy Consumption
# no hdmi (-p to restore). Careful! You might be in the dark for debugging.
sudo /opt/vc/bin/tvservice -o
# No BT. No Camera LED. In /boot/config:
dtoverlay=pi3-disable-bt
disable_camera_led=1
# I2C and Camera
# dtparam=i2c_arm=on # set pijuice install
# WiFi: leave on. 10mA consumption (?)
PiJuice Hat
Since a battery bank is in-efficient and can’t schedule times, we add a PiJuice. This covers setting up a PiZero W, powered by a PiJuice Zero, to wake and sleep. It can also manage a battery and solar panel. There are some good resources. This is a cheat-sheet to get going quickly.
- Install hardware: PiJuice HAT and a 4000mAh battery and a 5W solar panel.
- Install software: I used the cli (pijuice_cli) from github
Install, check settings and finish off
# Activate i2c sudo raspi-config # and select I2C # Install cd #git clone https://github.com/PiSupply/PiJuice.git sudo apt-get install -y pijuice-base # Make easier to see config file sudo chmod 755 /var/lib/pijuice/ sudo chmod 644 /var/lib/pijuice/pijuice_config.JSON # check service is enabled sudo systemctl status pijuice # Run to check status pijuice_cli
So that’s all good and running okay. Let’s configure it.
Real Time Clock, Sleeping and Wakeups
We want to use the hardware clock (it’s on the pijuice), for setting the time if we’re off WiFi.
# Add RTC to system, then reboot
sudo echo dtoverlay=i2c-rtc,ds1339 >> /boot/config.txt
# Check the RTC is correctly on I2C bus:
i2cdetect -y 1
# Check hwclock is available (note sudo!)
sudo hwclock
# Connect to internet, then set it
sudo hwclock --date --set
Now we need to sync the pi’s time to the RTC on boot with a service. See background. Use a service as this is a system thing. Specifically:
wget "https://gist.githubusercontent.com/brettbeeson/ed6799df73a885da58a3df564a40a05e/raw/c109ec3f7288f5cf19c4853af886c6a3e21db680/sync-to-rtc.service"
sudo cp sync-to-rtc.service /etc/systemd/system/
sudo systemctl enable sync-to-rtc.service
Ensure wakeup alarm is active (can be reset upon reboot):
#!/usr/bin/python3
# This script is started at reboot by cron:
# @reboot /usr/bin/python3 /home/pi/wakeup_enable.py
import pijuice, time, os
# cron starts it very early in the boot sequence we wait for the i2c-1 device
while not os.path.exists('/dev/i2c-1'):
time.sleep(0.1)
pj = pijuice.PiJuice(1, 0x14)
pj.rtcAlarm.SetWakeupEnabled(True)
Call this to shutdown pijuice correctly (i.e. ask it to halt the system, then go into deep sleep):
#!/usr/bin/python3
# Shutdown with cron:
# 5 19 * * * /usr/bin/python3 /home/pi/pijuice-shutdown.py
import os
from pijuice import PiJuice
pj=PiJuice()
pj.power.SetPowerOff(60) # pijuice will turn off power in 60s...
os.system("sudo shutdown now") # ... to give the system time to shutdown
Configure wakeup. Note pijuice_cli this uses UTC time, so we write a script to convert to local time.
>pijuice_wakeup enable 6am
Wakeup enabled: True
Wakeup time (local):2000-01-02 06:00:00+10:00
Wakeup time (UTC):2000-01-01 20:00:00+00:00
System off conditions
- Other miscellaneous options, via pijuice_cli. Some of the ‘off’ options need careful use.
- SYSTEM_HALT_POWER_OFF: the action which turns off power to the pi (in addition to halting it). This is required to save battery.
- Changes
- System Task: everything on including Watchdog, Wake on charge, Min charge, Min volt, Power off
- System Events: important: set the action required (e.g. power off sys halt) for low charge, etc.
- Button Press: change 10s press to SYSTEM_HALT_POWER_OFF instead of just SYSTEM_HALT
Results and Battery Life: No Camera
- Over the morning, battery level when from 70% to 20%. Hence we get about a day’s (12 hours) running on a 4000mAh battery.
- Battery voltage is slowly dropping.
- With a 5v 10,000mAh powerbank , to top-up the 4000mAh battery takes 60%.
Results with a Camera
- We get about 6 hours run-time with a 4000mAh battery
- Hence we use 700mA (700mAh per hour of run-time).
- This is higher than “idle” (220mA) because even idling, the pizero+camera uses 700mA
- 3s interval photos use 1160mA
Improving Results with Camera
We can modify the code to “destroy” the PiCamera() object and achieve 250mA. This is a three fold improvement, so worth the complexity.
Just turn it off
We can turn off the PiZero using the PiJuice. Be careful regarding UTC v local time!
A quick test showed turning off for 6h resulted in a 20% battery drain (so 0.2 x 2600mAh battery = 520mAh). This means we’re using 100mA but expect PiJuice to use (10mA max, surely? can’t find an figure). This needs more investigation!
Summary of results
- On the 4000mAh battery we get 6h. Enough for a good timelapse.
- A 2W panel enables run-on-sun. Would need full sun all the time. For travel, this is okay as we could charge on alternate days.
- A 5W panel would enable for continuous day time operation.
- (Carrying a spare 10,000mAh battery bank would extend this to 6h + about 9h top-up = 15h. This is not ideal considering the mass of the battery bank. Too many efficiencies in conversion.)
Failures – don’t look at me
Failed efforts below here
- Enable logging: Call a user function to write to journal and set configuration as desired (e.g. close on low battery). Stored in a JSON file in /var/lib
- Enable persistent logging if desired.
- Checking this, seems to NOT log, but fails. Give up on this.
Feb 17 13:00:07 raspberrypi pijuice_sys.py[405]: File "/usr/bin/pijuice_sys.py", line 126, in _EvalButtonEvents Feb 17 13:00:07 raspberrypi pijuice_sys.py[405]: if btConfig[b][ev]['function'] != 'USER_EVENT': Feb 17 13:00:07 raspberrypi pijuice_sys.py[405]: KeyError: 'SW1' # btConfig debug print: {'SW1': {'DOUBLE_PRESS': {'function': 'USER_FUNC1', 'parameter': 0}, 'LONG_PRESS1': {'function': 'SYS_FUNC_HALT', 'parameter': 10000}, 'LONG_PRESS2': {'function': 'HARD_FUNC_POWER_OFF', 'parameter': 20000}, 'PRESS': {'function': 'NO_FUNC', 'parameter': 0}, 'RELEASE': {'function': 'NO_FUNC', 'parameter': 0}, 'SINGLE_PRESS': {'function': 'HARD_FUNC_POWER_ON', 'parameter': 800}}, 'SW2': {'DOUBLE_PRESS': {'function': 'USER_FUNC2', 'parameter': 600}, 'LONG_PRESS1': {'function': 'NO_FUNC', 'parameter': 0}, 'LONG_PRESS2': {'function': 'NO_FUNC', 'parameter': 0}, 'PRESS': {'function': 'NO_FUNC', 'parameter': 0}, 'RELEASE': {'function': 'NO_FUNC', 'parameter': 0}, 'SINGLE_PRESS': {'function': 'USER_FUNC1', 'parameter': 400}}, 'SW3': {'DOUBLE_PRESS': {'function': 'NO_FUNC', 'parameter': 0}, 'LONG_PRESS1': {'function': 'NO_FUNC', 'parameter': 0}, 'LONG_PRESS2': {'function': 'NO_FUNC', 'parameter': 0}, 'PRESS': {'function': 'USER_FUNC3', 'parameter': 0}, 'RELEASE': {'function': 'USER_FUNC4', 'parameter': 0}, 'SINGLE_PRESS': {'function': 'NO_FUNC', 'parameter': 0}}}