Graceful delayed shutdown with timer and 1 relay
My solution is based on this video - https://www.youtube.com/watch?v=rknBevexOcU on the Automate Everything channel and utilises a single standard automotive 12V relay and a programmable 12V timer.
Overview
In short the timer provides power to the RPi, screen and in my case peripherals (e.g. powered USB hub, external BT dongle, external sound card, reverse CAM etc.) when the IGN is on. When the IGN is switched off the timer continues to provide power to the RPi for a configurable amount of time before switching off (e.g. 15 mins). In tandem with this the relay closes when the IGN is switched off and sets a monitored GPIO pin low. A script on the RPi monitors the status of the GPIO pin and ensures that the RPi shuts down before the timer cuts power to the RPi, screen and peripherals (e.g. 14 minutes).
The advantages of this solution is that it is relatively simple, is straightforward to wire / connect and doesn't take up too much space. The disadvantage is that the timer is relatively expensive at €16 plus shipping (other suitable, less expensive timers may be out there - I didn't search). Also there is a very small chance that the script fails to shut down the RPi before the timer switches off. While idle (IGN off) the timer does consume 0.3 ma.
Setup diagram
Parts list:
Timer - https://www.amazon.com/gp/product/B015Z2...ct_title_1
12v - 5v buck converter - https://www.ebay.com/itm/24V-12V-to-5V-5...3349930955
Powered USB hub (optional) - https://www.amazon.fr/gp/product/B074VZD...le_o05_s01
12v automotive relay - either a SPST-NC (Single-Pole Single-Throw, Normally-Closed) or a SPDT (Single-Pole Double-Throw)
I would recommend configuring and testing on the bench before installing in the car. This makes troubleshooting (IMO) a lot easier.
1. Detail
When IGN is switched on the timer switches on it's output which powers the 12V - 5V converter (which in turn powers the RPi , screen, and in my case an external USB hub - used for BT, sound card, reverse cam and charging phone etc.).
When IGN is switched off the timer starts it's countdown timer (timer is configurable - e.g. 15 mins), when countdown is complete the timer switches off the output which powers off the 12V - 5V converter which in turn powers off the RPi, screen, USB hub and peripherals. If the IGN is switched back on before the countdown finishes then the timer resets / cancels the countdown timer.
When the timer is off it draws a very small current (0.3 ma in low power mode [the default] when idle).
The timer requires programming before use - see below and / or refer to https://www.youtube.com/watch?v=rknBevexOcU (Automate Everything)
To enable a graceful shutdown of the RPi (i.e. for the RPi to shutdown before the timer) I use a python script (running as a service on the RPi) which monitors the state of a nominated GPIO pin (e.g. GPIO 17). A standard 12V relay connected to the ignition controls the state of the monitored GPIO pin.
When the ignition is switched off the GPIO pin is set low by the relay which connects / shorts GND to GPIO 17. The scripts detects this and after a configurable delay initiates a graceful shutdown. To ensure that the RPi shuts down prior to the timer the configurable shutdown delay is less than the shutdown delay configured for the timer (e.g. 14 mins). If the ignition is turned back on the script detects this and no shutdown occurs.
The script and service definition file along with installation instructions are below.
2. Timer programming
Before use the timer must be programmed so that it powers off it's load x (e.g. 15) minutes after power (IGN) is lost.
This involves
- setting the required shutdown delay (e.g. 15 minutes) on the timer
- setting timer function to #12
- setting timer trigger to #2
Refer to example 11 in the timer cook book / programming guide - http://timers.shop/Timer-Cook-Book_ep_43...#example11 for more detail on how to program the timer (or to the Automate Everything video - https://www.youtube.com/watch?v=rknBevexOcU)
I highly recommend purchasing (or making your own) timer configuration button board to save frustration when programming - http://timers.shop/Timer-configuration-b..._p_18.html.
3. Relay wiring
Pin 86 of the relay is connected to the ignition and pin 85 to ground.
Pin 30 (COM) is connected to GPIO GND
Pin 87A on a SPDT relay or (pin 87 on a SPST relay) to the monitored GPIO pin (e.g. GPIO 17).
4. Timer wiring
POWER (red wire) - connected to an always live +12V (ensure that this feed isn't cut when the engine is cranked)
TRIGGER (blue wire) connected to the IGN line
LOAD (yellow) - the output of the timer - this is connected to the 12V - 5V buck converter (which in turns powers the RPi, screen, USB hub and peripherals)
GROUND (black) - vehicle ground
The green and white programming wires should be shielded / insulated.
Disclaimer: I am neither a developer or automotive electrician - YMMV
5. Python script / service installation
Script
i. Create file /home/pi/power-monitor.py - >touch /home/pi/power-monitor.py
ii. Copy and paste script (below) to /home/pi/power-monitor.py and then save the file - >nano /home/pi/power-monitor.py
iii. Create directory /opt/power-monitor - >sudo mkdir /opt/power-monitor
iv. Copy script to /opt/power-monitor/power-monitor.py >sudo cp /home/pi/power-monitor.py /opt/power-monitor/
v. Set owner - >sudo chown root:root /opt/power-monitor/power-monitor.py
vi. Add execute attribute to script - >sudo chmod +x /opt/power-monitor/power-monitor.py
vii. Set required GPIO pin (PORT) and shutdown delay (SHUTDOWN_DELAY) in script ->sudo nano /opt/power-monitor/power-monitor.py
Service
i. Create file /home/pi/power-monitor.py - >touch /home/pi/power-monitor.service
iii. Copy and paste service definition file (below) to /home/pi/power-monitor.service and then save the file - >nano /home/pi/power-monitor.service
iii. Copy service definition file to /etc/systemd/system/power-monitor.service ->sudo cp /home/pi/power-monitor.service /etc/systemd/system/
iv. Set owner - >sudo chown root:root /etc/systemd/system/power-monitor.service
v. Install service - >sudo systemctl enable power-monitor.service
vi. Start service - >sudo systemctl start power-monitor.service
vii. Check status of service - > sudo systemctl status power-monitor.service
Testing / debugging
i. In the script set the DEBUG variable to 1 - >sudo nano /opt/power-monitor/power-monitor.py
ii. Restart the service - >sudo systemctl restart power-monitor.service
iii. Debug output is directed to /var/log/daemon - view with >tail -f /var/log/daemon
iv. When finished set the DEBUG variable in the script back to 0 >sudo nano /opt/power-monitor/power-monitor.py
Troubleshooting
i. If, while the ignition is off and the timer is counting down, on restarting the car the RPi powers off it's likely that the 12V feed that the timer is connected to is cut when the engine is cranked. Find another 12V, always on feed to connect the timer to.
Notes
i. A SPST NO relay can be used instead of a SPST NC relay. To do so edit the power-monitor.py script and change all instances (3) of
if not IGN_UP
to
if IGN_UP
ii. The timer can be configured to draw zero current when idle by adding a second relay and implementing scenario 4 in the timer cook book "Time Off Delay Self latching circuit with zero current consumption during off state"
Service definition file - power-monitor.service
Script - power-monitor.py
My solution is based on this video - https://www.youtube.com/watch?v=rknBevexOcU on the Automate Everything channel and utilises a single standard automotive 12V relay and a programmable 12V timer.
Overview
In short the timer provides power to the RPi, screen and in my case peripherals (e.g. powered USB hub, external BT dongle, external sound card, reverse CAM etc.) when the IGN is on. When the IGN is switched off the timer continues to provide power to the RPi for a configurable amount of time before switching off (e.g. 15 mins). In tandem with this the relay closes when the IGN is switched off and sets a monitored GPIO pin low. A script on the RPi monitors the status of the GPIO pin and ensures that the RPi shuts down before the timer cuts power to the RPi, screen and peripherals (e.g. 14 minutes).
The advantages of this solution is that it is relatively simple, is straightforward to wire / connect and doesn't take up too much space. The disadvantage is that the timer is relatively expensive at €16 plus shipping (other suitable, less expensive timers may be out there - I didn't search). Also there is a very small chance that the script fails to shut down the RPi before the timer switches off. While idle (IGN off) the timer does consume 0.3 ma.
Setup diagram
Parts list:
Timer - https://www.amazon.com/gp/product/B015Z2...ct_title_1
12v - 5v buck converter - https://www.ebay.com/itm/24V-12V-to-5V-5...3349930955
Powered USB hub (optional) - https://www.amazon.fr/gp/product/B074VZD...le_o05_s01
12v automotive relay - either a SPST-NC (Single-Pole Single-Throw, Normally-Closed) or a SPDT (Single-Pole Double-Throw)
I would recommend configuring and testing on the bench before installing in the car. This makes troubleshooting (IMO) a lot easier.
1. Detail
When IGN is switched on the timer switches on it's output which powers the 12V - 5V converter (which in turn powers the RPi , screen, and in my case an external USB hub - used for BT, sound card, reverse cam and charging phone etc.).
When IGN is switched off the timer starts it's countdown timer (timer is configurable - e.g. 15 mins), when countdown is complete the timer switches off the output which powers off the 12V - 5V converter which in turn powers off the RPi, screen, USB hub and peripherals. If the IGN is switched back on before the countdown finishes then the timer resets / cancels the countdown timer.
When the timer is off it draws a very small current (0.3 ma in low power mode [the default] when idle).
The timer requires programming before use - see below and / or refer to https://www.youtube.com/watch?v=rknBevexOcU (Automate Everything)
To enable a graceful shutdown of the RPi (i.e. for the RPi to shutdown before the timer) I use a python script (running as a service on the RPi) which monitors the state of a nominated GPIO pin (e.g. GPIO 17). A standard 12V relay connected to the ignition controls the state of the monitored GPIO pin.
When the ignition is switched off the GPIO pin is set low by the relay which connects / shorts GND to GPIO 17. The scripts detects this and after a configurable delay initiates a graceful shutdown. To ensure that the RPi shuts down prior to the timer the configurable shutdown delay is less than the shutdown delay configured for the timer (e.g. 14 mins). If the ignition is turned back on the script detects this and no shutdown occurs.
The script and service definition file along with installation instructions are below.
2. Timer programming
Before use the timer must be programmed so that it powers off it's load x (e.g. 15) minutes after power (IGN) is lost.
This involves
- setting the required shutdown delay (e.g. 15 minutes) on the timer
- setting timer function to #12
- setting timer trigger to #2
Refer to example 11 in the timer cook book / programming guide - http://timers.shop/Timer-Cook-Book_ep_43...#example11 for more detail on how to program the timer (or to the Automate Everything video - https://www.youtube.com/watch?v=rknBevexOcU)
I highly recommend purchasing (or making your own) timer configuration button board to save frustration when programming - http://timers.shop/Timer-configuration-b..._p_18.html.
3. Relay wiring
Pin 86 of the relay is connected to the ignition and pin 85 to ground.
Pin 30 (COM) is connected to GPIO GND
Pin 87A on a SPDT relay or (pin 87 on a SPST relay) to the monitored GPIO pin (e.g. GPIO 17).
4. Timer wiring
POWER (red wire) - connected to an always live +12V (ensure that this feed isn't cut when the engine is cranked)
TRIGGER (blue wire) connected to the IGN line
LOAD (yellow) - the output of the timer - this is connected to the 12V - 5V buck converter (which in turns powers the RPi, screen, USB hub and peripherals)
GROUND (black) - vehicle ground
The green and white programming wires should be shielded / insulated.
Disclaimer: I am neither a developer or automotive electrician - YMMV
5. Python script / service installation
Script
i. Create file /home/pi/power-monitor.py - >touch /home/pi/power-monitor.py
ii. Copy and paste script (below) to /home/pi/power-monitor.py and then save the file - >nano /home/pi/power-monitor.py
iii. Create directory /opt/power-monitor - >sudo mkdir /opt/power-monitor
iv. Copy script to /opt/power-monitor/power-monitor.py >sudo cp /home/pi/power-monitor.py /opt/power-monitor/
v. Set owner - >sudo chown root:root /opt/power-monitor/power-monitor.py
vi. Add execute attribute to script - >sudo chmod +x /opt/power-monitor/power-monitor.py
vii. Set required GPIO pin (PORT) and shutdown delay (SHUTDOWN_DELAY) in script ->sudo nano /opt/power-monitor/power-monitor.py
Service
i. Create file /home/pi/power-monitor.py - >touch /home/pi/power-monitor.service
iii. Copy and paste service definition file (below) to /home/pi/power-monitor.service and then save the file - >nano /home/pi/power-monitor.service
iii. Copy service definition file to /etc/systemd/system/power-monitor.service ->sudo cp /home/pi/power-monitor.service /etc/systemd/system/
iv. Set owner - >sudo chown root:root /etc/systemd/system/power-monitor.service
v. Install service - >sudo systemctl enable power-monitor.service
vi. Start service - >sudo systemctl start power-monitor.service
vii. Check status of service - > sudo systemctl status power-monitor.service
Testing / debugging
i. In the script set the DEBUG variable to 1 - >sudo nano /opt/power-monitor/power-monitor.py
ii. Restart the service - >sudo systemctl restart power-monitor.service
iii. Debug output is directed to /var/log/daemon - view with >tail -f /var/log/daemon
iv. When finished set the DEBUG variable in the script back to 0 >sudo nano /opt/power-monitor/power-monitor.py
Troubleshooting
i. If, while the ignition is off and the timer is counting down, on restarting the car the RPi powers off it's likely that the 12V feed that the timer is connected to is cut when the engine is cranked. Find another 12V, always on feed to connect the timer to.
Notes
i. A SPST NO relay can be used instead of a SPST NC relay. To do so edit the power-monitor.py script and change all instances (3) of
if not IGN_UP
to
if IGN_UP
ii. The timer can be configured to draw zero current when idle by adding a second relay and implementing scenario 4 in the timer cook book "Time Off Delay Self latching circuit with zero current consumption during off state"
Service definition file - power-monitor.service
[Unit]
Description=Script to monitor ignition status
ConditionPathExists=/opt/power-monitor/power-monitor.py
After=multi-user.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 -u /opt/power-monitor/power-monitor.py
Restart=on-failure
StartLimitInterval=60
RestartSec=5
StartLimitBurst=3
[Install]
WantedBy=multi-user.target
Script - power-monitor.py
#!/usr/bin/python3 -u
import RPi.GPIO as GPIO
import time
import subprocess
DEBUG = 0
# GPIO / BCM 17 - physical pin 11
PORT = 17
# Shutdown delay in seconds
# 14.5 minutes
SHUTDOWN_DELAY = 870
# No. of seconds after ignition returns to cancel shutdown
CANCEL_SHUTDOWN = 5
IGN_STATUS = 1
SHUTDOWN = 0
IGN_OFF_TIME = 0
IGN_OFF_LAST_SEEN = 0
NOW = 0
# specify pin numbering format
GPIO.setmode(GPIO.BCM)
# set pin to input, set pull up resistor so it reads high
GPIO.setup((PORT), GPIO.IN, pull_up_down=GPIO.PUD_UP)
while True:
NOW = time.time()
# Get the status of the ignition
IGN_UP = GPIO.input(PORT)
# Ignition switched off? then set shutdown flag and igntion off time
if not IGN_UP and not SHUTDOWN:
SHUTDOWN = 1
IGN_OFF_TIME = NOW
print("Ignition switched off, shutdown flag set!")
# Increment this counter while ignition is off
if not IGN_UP and SHUTDOWN:
IGN_OFF_LAST_SEEN = NOW
# if igntion is off check if shutdown delay time reached
if (SHUTDOWN and not IGN_UP and ((NOW - IGN_OFF_TIME) > SHUTDOWN_DELAY)):
print("Shutdown delay of", SHUTDOWN_DELAY, "seconds reached, shutting down!")
try:
STATUS = subprocess.check_output(["shutdown", "-h", "now", "--no-wall"])
except subprocess.CalledProcessError as shutdowncmd:
print("Shutdown failed with error code: ", shutdowncmd.returncode)
break
# Cancel shutdown if power has been back for CANCEL_SHUTDOWN seconds
if ((NOW - IGN_OFF_LAST_SEEN) >= CANCEL_SHUTDOWN ) and SHUTDOWN:
print("Ignition has been back for : ", CANCEL_SHUTDOWN, " seconds - shutdown flag reset")
SHUTDOWN = 0
IGN_OFF_TIME = 0
IGN_OFF_LAST_SEEN = 0
if DEBUG:
STATUS = GPIO.input(PORT)
print("Pin status is: ", STATUS)
print("IGN_UP is set to: ", IGN_UP)
print("SHUTDOWN is set to: ", SHUTDOWN)
if SHUTDOWN:
print("Igntion off time is: ", IGN_OFF_TIME)
print("Igntion off last seen time is: ", IGN_OFF_LAST_SEEN)
print("Current time is : ", NOW)
print("Elapsed time is : ", (NOW - IGN_OFF_TIME))
time.sleep(1)
if DEBUG:
print("Exiting")
GPIO.cleanup()