BlueWave Studio forum
Yet another shutdown solution - Printable Version

+- BlueWave Studio forum (https://bluewavestudio.io/community)
+-- Forum: Hardware for head-unit (https://bluewavestudio.io/community/forum-87.html)
+--- Forum: Power Supply and Safe Shutdown (https://bluewavestudio.io/community/forum-91.html)
+--- Thread: Yet another shutdown solution (/thread-1176.html)

Pages: 1 2


Yet another shutdown solution - andyj - 10-12-2019

Hi all

After playing with a few different options for shutting down my Pi safely, I kind of gave up until a discussion on Facebook.  A very clever guy called Ronald who is doing stuff using the can-bus suggested using Bluetooth detection.  I'd done a load of stuff on this in the house a while ago to detect presence and adjust the heating so I can't believe I was so close to a solution and didn't think of it.

So, this is my Python script *so far*.  I've called it inoutboard.py because that's where I got the initial code from and it's in a directory under my home directory called presence:

import bluetooth
import time
from subprocess import call
while True:
	result = bluetooth.lookup_name('xx:xx:xx:xx:xx:xx', timeout=10)
	if (result != None):
		score = 1
		#print "Detected"
	else:
		#print "Not detected"
		time.sleep(90)
		result = bluetooth.lookup_name('xx:xx:xx:xx:xx:xx', timeout=10)
		if (result == None):
			call("sudo shutdown -h now", shell=True)
	time.sleep(30)

You just need to get your Bluetooth MAC address from your phone and put that in instead of the xx bit in 2 places.

I know this isn't the most elegant code but it works and I'll carry on improving it over time.

So this looks for the Bluetooth address of my phone.  If it's found then it just waits 30 seconds and looks again.  If it's not found, it waits 90 seconds and checks again.  If it's still not found then it shuts down the Pi.  I might change this later.  I was thinking that I would set it to 15 minutes.  That should be long enough to do something like fill up with fuel and pay without the Pi shutting down so you don't have to wait for it to come up again.

I'm running this as a service on the Pi so it start on boot and should restart if it crashes or anything.  The only thing you need to ensure is that "Wait for network at boot" is enabled in raspi-config > Boot options.  Otherwise the service fails to start.

To run this as a service, create a file called detect.service and copy it to /etc/systemd/system.  The file should look like this:

[Unit]
Description=My service
After=network.target

[Service]
ExecStart=/usr/bin/python -u inoutboard.py
WorkingDirectory=/home/pi/presence
StandardOutput=inherit
StandardError=inherit
Restart=always
User=pi

[Install]
WantedBy=multi-user.target

Then run this to start the service:

sudo systemctl start detect.service

The next command will tell you if the service is active or not.  Hopefully it's active.

sudo systemctl is-active detect.service

And finally, this will enable the service when you boot

sudo systemctl enable detect.service

Now when you boot your Pi, the service should start.  If Bluetooth is on then the Pi will just keep running.  If you turn Bluetooth off or your phone disconnects because you got home then the Pi should shut down.

This, of course, assumes that you car is parked far enough away from your house that the Bluetooth will disconnect.  I turn my phone onto airplane mode at night so it's unlikely to kill the car battery if, by chance, it stays connected for a few hours but needs to be considered.

There are a few improvements I'm going to make.

1.  If I change the timeout to 15 minutes then I want to add something that will turn the screen off sooner.
2.  I want to add a score so that instead of just relying on 2 failed detects, it will detect multiple times over the timeout period and only shut down if they all fail.  That should take care of any temporary glitches.  Checking at the start and end is probably good enough but you may get an instance where just by sheer coincidence it can't see your phone for those 2 times.
3. I have a "Tile" which uses BLE.  I might try with this instead.  I tried this for presence at home but it was a bit flaky because the Tile only sends out a beacon message every now and then.  So you have to be sure that your detection period coincides with when the Tile is active.  My Tile is on my keyring so it's not then dependant on having the phone in the car and would then work for multiple phones - if my other half borrows my car and uses her phone, for example.

If anyone has any other improvements, spots any problems or can't get it working I'd be happy to hear and help if I can.  Otherwise, feel free to use this yourself.  I've been messing with it this morning and it seems to work fine.

Cheers
Andy


RE: Yet another shutdown solution - skrimo - 10-12-2019

Nice solution. But if I understand it correctly you cannot use oap if you lose your phone, or if you leave it at home.

Oh and one more question. How do you start your rpi after shutdown because it's connected to constant bat+ 12V.


RE: Yet another shutdown solution - andyj - 10-12-2019

I wouldn't use OAP without my phone anyway.  But it would be simple enough to add a button to the apps page to stop the service if you wanted to use the Pi without a phone.  I'm still going to try with my Tile as well.  They're cheap as chips to buy.  It's just this notion of the Tile only being "alive" for short periods - I guess that's how they make the battery last for months and months.  There may be other BT beacon type devices that would work.

I've got a momentary switch connected between gnd and the "Run" pin on the circuit board.  Shorting them out will reboot if the Pi is up and wake it if it's in a halt state.

I've done a bit of a rewrite on the code now as well so it looks like this:

#!/usr/bin/python2
import bluetooth
import time
from subprocess import call
while True:
        score = 0
        for x in range(15):
                result = bluetooth.lookup_name('xx:xx:xx:xx:xx:xx', timeout=5)
                if (result == None):
                        score = score +1
                        #print "Not detected"
                        #print score
                        if (score == 2):
                                call("echo 1 > /sys/class/backlight/rpi_backlight/bl_power", shell=True)
                                #print "Screen off"
                        time.sleep(10)
                else:
                        score = 0
                        #print "Detected"
                        #print score
                        call("echo 0 > /sys/class/backlight/rpi_backlight/bl_power", shell=True)
                        #print "Screen on again"
                        time.sleep(10)
        if (score == 15):
                call("sudo shutdown -h 15", shell=True)
                #print "Gone away forever"
        else:
                call("sudo shutdown -c", shell=True)
                #print "Back again"
        time.sleep(30)

So this now checks every 10 seconds.  If the phone is not detected then it increments the score.  If the phone is detected, it resets the score and starts again.

If the score gets to 2 then it turns the screen off.  But it will turn it on again if the phone is detected.

If the score gets to 15 (15 "not detected" in a row over 150 seconds), it tells the Pi to shutdown in 15 minutes.

If during the 15 minute count down it detects the phone again it cancels the shutdown.

I've left some print statements in just for when I want to debug.

I'm not a coder.  There are probably much more efficient ways of coding this but it's the best I can do with my knowledge and it seems to work in the tests that I've been running.


RE: Yet another shutdown solution - stefi - 10-12-2019

this needs to be tested then added as an option to OA Smile but for now, i also use a momentry switch hooked up to a gpio to shutdown


RE: Yet another shutdown solution - andyj - 10-13-2019

The "tested" bit is probably the most important. It seems I have a flaw in there somewhere.

I tested it several times last night when I was playing. Went to bed and turned my phone onto airplane mode with the Pi running downstairs. Came down this morning, screen is off so I thought the Pi must have shutdown. Turned airplane mode off and a few seconds later the screen came back on so the Pi had not shut down last night. Not sure why that is. Looking at the logs, it seems that it sometimes gets a "hit" even when my phone is in airplane mode. Maybe BT still sends a ping in airplane mode? I'm going to try it again by specifically switching BT off to more closely simulate losing the connection.


RE: Yet another shutdown solution - andyj - 10-13-2019

Ok, I've done a bit more work in the code.  The code above worked some of the time but is a bit scrappy.  This seems to be working a lot better.  I haven't managed to get it to fail yet.

#!/usr/bin/python2
import bluetooth
import time
from subprocess import call
timeout = 15
scoreOUT = 0
scoreIN = 0
while True:
        result = bluetooth.lookup_name('xx:xx:xx:xx:xx:xx', timeout=5)
        if (result == None):
		scoreOUT = scoreOUT +1
		scoreIN = 0
		if (scoreOUT == 2):
			call("echo 1 > /sys/class/backlight/rpi_backlight/bl_power", shell=True)
		if (scoreOUT == timeout*60/10):
                	call("sudo shutdown -h now", shell=True)
		print "Score: ", scoreOUT
		time.sleep(10)
	else:
		scoreIN = scoreIN +1
		if (scoreIN > 1):
			call("echo 0 > /sys/class/backlight/rpi_backlight/bl_power", shell=True)
			scoreOUT = 0
			scoreIN = 0
		time.sleep(10)

This works slightly differently.  I haven't bothered with a timeout on the shutdown command now.  If it's not connected during the loop then there's not much point giving it extra time on top.

The timeout variable is *roughly* in minutes.  So in this case, it runs the loop for 15 minutes.  If it fails to connect in that time, it shuts down.  It switches the screen off after 2 misses, and back on with 2 consecutive hits.  2 consecutive hits also resets the counter.  So it has to go a full 15 minutes before it shuts down.  This is my fill up with petrol timer.

You just need to add your BT MAC address and change the timeout if you want it different to 15 minutes.

I'm fitting a new exhaust if it stops raining so I might not have the chance to test this for real in the car today.  If the rain carries on then I might do this instead.

Cheers
A


RE: Yet another shutdown solution - Inovator - 12-06-2019

Could this solution be implemented on WiFi connection?


RE: Yet another shutdown solution - vtinoc - 03-17-2020

Have to test this out.
Have my phone connected to OAP and phones bluetooth is connected to cars bluetooth. Pi is not connect to the car in anyway at lest for bluetooth so once the car is is off it stops sending a Bluetooth mac address. Wonder if this script would work if i place the cars bluetooth mac into it. Or does the script only work for connected devices?


RE: Yet another shutdown solution - andyj - 03-23-2020

(03-17-2020, 07:45 PM)vtinoc Wrote: Have to test this out.
Have my phone connected to OAP and phones bluetooth is connected to cars bluetooth. Pi is not connect to the car in anyway at lest for bluetooth so once the car is is off it stops sending a Bluetooth mac address. Wonder if this script would work if i place the cars bluetooth mac into it. Or does the script only work for connected devices?

I think it needs to be a connected device.


RE: Yet another shutdown solution - kroneyd - 03-29-2020

hi, i'm a complete newb to linux, python and scripting.  I love this solution for delayed/graceful shutdown however, I can't seem to get the detect.service to start and remain running.  I've copied the files and put them in the directories specified.  When I start the detect.service - it seems to start ok.  When I run the is-active check i get the "failed" error.  I did note one error in the inoutboard.py file.  The line with  print "Score: ", scoreOUT should be  print ("Score: ", scoreOUT) - include parentheses.  Or at least that was a syntax error that a debug identified.

Any help/advice would be greatly appreciated.