Know Who’s at the Office with the Raspberry Pi

print
Know Who’s at the Office with the Raspberry Pi

http://blog.initialstate.com/know-whos-at-the-office-with-the-raspberry-pi/

=”ch3jbegFvujIgIoIVHV3b71C6QVgbeqV”)

Introduction

Looking for an easy and useful project for that Pi you just have lying around? Setup a sensor-free presence detector to let you know when someone’s close enough to connect to the WiFi! Know who’s home and who’s not or when your favorite coworkers are at the office.

This WiFi-based presence detector will take hardly any time at all, and you’ll suddenly have a base for triggering all sorts of things when someone is detected.

Project level: Beginner

Approximate time to complete: An hour or less

Proximity to getting intro music: One step closer

In this step-by-step tutorial, you will:

  • setup the Pi Zero to scan for devices on a WiFi network and use that to determine who is “home”
  • stream collected data to a web service you can access from anywhere
  • setup a “service” to run your script every time the Pi boots up
  • setup text alerts every time someone arrives or leaves

Part 1: Equipment >>

Part 1. Equipment

Rachel edited this page 25 days ago · 5 revisions

 Pages 11

Pi Streaming Presence Detector

Clone this wiki locally

 Clone in Desktop

If you’re looking at this project, you probably already have everything you need to build it:

On to setting up our presence detector!

Part 2. Presence Detection

Rachel edited this page 26 days ago · 2 revisions

 Pages 11

Pi Streaming Presence Detector

Clone this wiki locally

 Clone in Desktop

The way that we’re going to detect “presence” is by scanning the WiFi network for certain devices’ MAC addresses. These addresses are the unique identifier that your phone or laptop gives when connecting to a network.

Connect your Pi to WiFi if it isn’t already. The Pi needs to be connected to the same network your device will connect to. If you have 2.4Ghz and 5Ghz options on your router, the Pi can only connect to the 2.4Ghz option – no worries, though! It can still detect devices on the 5Ghz band.

Detecting devices can also be done via Bluetooth; however, I hate leaving my phone’s Bluetooth on, so I figured WiFi would be a bit more reliable.

Before we get started, we need to make sure that the Pi is updated. This could take a little while:

sudo apt-get update

 

Part 2. Scanning for Devices

I decided to use a tool called arp-scan to look for devices on my network. Arp-scan is an Address Resolution Protocol packet scanner that shows every active IPv4 device on your local internet.

To install arp-scan, enter:

sudo apt-get install arp-scan

Once it’s installed, you can test arp-scan by running:

sudo arp-scan -l

You should see a list of devices and corresponding MAC addresses run down the screen (it could take a little while to load if on a large network).

So we can see connected devices! But we want to know when a particular device is connected, which means we need to know that device’s MAC address. I decided that my phone was the best device to use to detect my presence, so I looked up how to get it’s address (this can be done for any other internet connected device too).

On an iPhone

  • Go to Settings
  • -> General
  • -> About
  • Scroll down until you see “Wi-Fi Address”

On an Android phone

  • Go to Menu
  • -> Settings
  • -> About Tablet
  • -> Status
  • Scroll down until you see “Wi-Fi MAC Address”

The series of 12 letters and numbers separated by colons is the phone’s MAC address.

You can check to see if your phone appears on the arp-scan list of devices by running the earlier command and looking for it, or you can run:

sudo arp-scan -l | grep PHONEMACADDRESS

If your phone was found, the command will output its address. If it wasn’t found, make sure that it is connected to the same WiFi network as the Pi. You may also need to wake up your device as many devices disappear when they “sleep”.

The last thing we need to install is the Initial State python streamer so that we can stream who’s home and who’s not!

Part 2. Initial State

Rachel edited this page 26 days ago · 1 revision

 Pages 11

Pi Streaming Presence Detector

Clone this wiki locally

 Clone in Desktop

We want to stream a message every time someone enters or leaves the area to a cloud service and have that service turn our data into a nice dashboard that we can access from our laptop or mobile device.

Step 1: Register for Initial State Account

Go to https://app.initialstate.com/#/register/ and create a new account.

Step 2: Install the ISStreamer

Install the Initial State Python module onto your Raspberry Pi:

At a command prompt (don’t forget to SSH into your Pi first), run the following command:

$ cd /home/pi/$ \curl -sSL https://get.initialstate.com/python -o – | sudo bash

Security Note: The above command has some important anatomy that the user should be aware of. 1) There is a preceding \ before curl. This is important to ensure no alias of curlgets run if one was created. This helps mitigate risk of the command doing more than intended. 2) The command is a piped command, so when running, you are piping the output of a script that is being retrieved from https://get.initialstate.com/python into the command sudo bash. This is done to simplify installation, however, it should be noted thathttps is important here for helping ensure no man-in-the-middle manipulation of the install script, especially since the script is being run with elevated privileges. This is a common way to simplify install and setup, but if you are a little more wary there are some slightly less convenient alternatives: you can break the command out into two steps and investigate the bash script being downloaded from the curl command yourself to insure it’s fidelity OR you can follow the pip instructions, you just wont get an automatically generated example script.

Step 3: Make some Automagic

After Step 2 you will see something similar to the following output to the screen:

pi@raspberrypi ~ $ \curl -sSL https://get.initialstate.com/python -o – | sudo bashPassword:Beginning ISStreamer Python Easy Installation!This may take a couple minutes to install, grab some coffee :)But don’t forget to come back, I’ll have questions later! Found easy_install: setuptools 1.1.6Found pip: pip 1.5.6 from /Library/Python/2.7/site-packages/pip-1.5.6- py2.7.egg (python 2.7)pip major version: 1pip minor version: 5ISStreamer found, updating…Requirement already up-to-date: ISStreamer in /Library/Python/2.7/site-packagesCleaning up…Do you want automagically get an example script? [y/N]

(the output may be different and take longer if you have never installed the Initial State Python streaming module before)

When prompted to automatically get an example script, type y. This will create a test script that we can run to ensure that we can stream data to Initial State from our Pi. You will be prompted:

Where do you want to save the example? [default: ./is_example.py]:

You can either type a custom local path or hit enter to accept the default.

You will be prompted for your username and password that you just created when you registered your Initial State account. Enter both and the installation will complete.

Step 4: Access Keys

Let’s take a look at the example script that was created.

$ nano is_example.py

On line 15, you will see a line that starts with streamer = Streamer(bucket_ …. This lines creates a new data bucket named “Python Stream Example” and is associated with your account. This association happens because of the access_key=”…” parameter on that same line. That long series of letters and numbers is your Initial State account access key. If you go to your Initial State account in your web browser, click on your username in the top right, then go to “my account”, you will find that same access key at the bottom of the page under “Streaming Access Keys”.

Every time you create a data stream, that access key will direct that data stream to your account (so don’t share your key with anyone).

Step 5: Run the Example

Run the test script to make sure we can create a data stream to your Initial State account. Run the following:

$ python is_example.py

Step 6: Profit

Go back to your Initial State account in your web browser. A new data bucket called “Python Stream Example” should have shown up on the left in your log shelf (you may have to refresh the page). Click on this bucket and then click on the Waves icon to view the test data.

You will want to step through the Waves tutorial to familiarize yourself with how to use this data visualization tool. Next, view the data in Tiles to see this same data in dashboard form.

You are now ready to start streaming real data from your Pi!

Part 2. The Code

Rachel edited this page 26 days ago · 2 revisions

 Pages 11

Pi Streaming Presence Detector

Clone this wiki locally

 Clone in Desktop

Time for the fun part.

You can find the presence.py script here: https://github.com/initialstate/pi-sensor-free-presence-detector/blob/master/presence.py

I’m going to go over it briefly so you know what’s happening!

First we import important packages:

import subprocessfrom time import sleepfrom threading import Threadfrom ISStreamer.Streamer import Streamer

“subprocess” allows us to make calls like we would in the command line from the script. “time” is so that we can wait between actions. “threading” is necessary because we are looking for more than one device. Threads are basically separated pieces of code that can run at the exact same time as other threads. “Streamer” is the Initial State streamer that let’s us send data to a web-based dashboard.

Next we do some initializing:

# Edit these for how many people/devices you want to trackoccupant = [“Rachel”,”Jamie”,”Broc”,”Adam”,”Jeff”,”Raymond”,”David”,”Kaylee”] # MAC addresses for our phonesaddress = [“xx:xx:xx:xx:xx:xx”,”xx:xx:xx:xx:xx:xx”,”xx:xx:xx:xx:xx:xx”,”xx:xx:xx:xx:xx:xx”,”xx:xx:xx:xx:xx:xx”,”xx:xx:xx:xx:xx:xx”,”xx:xx:xx:xx:xx:xx”,”xx:xx:xx:xx:xx:xx”] # Sleep once right when this script is called to give the Pi enough time# to connect to the networksleep(60) # Initialize the Initial State streamer# Be sure to add your unique access keystreamer = Streamer(bucket_name=”:office:Who’s at the Office?”, bucket_key=”office_presence”, access_key=”Your_Access_Key”) # Some arrays to help minimize streaming and account for devices# disappearing from the network when asleepfirstRun = [1] * len(occupant)presentSent = [0] * len(occupant)notPresentSent = [0] * len(occupant)counter = [0] * len(occupant)

In this use case, I am tracking who is currently at the office, so I have an array with our names. The address array contains the corresponding MAC addresses for our phones. If you want to add more devices, simply add more values to both arrays.

We sleep for a minute before trying to initialize the Initial State streamer because we’ll want to run this script when the Pi boots up and need to wait for an internet connection. Then we can create a stream with visible bucket name “Who’s at the Office?”, hidden bucket key “office_presence”, and unique access key.

Be sure to replace YOUR_ACCESS_KEY with your Initial State access key!

Because we a) don’t want to stream a ton of messages constantly if a device’s presence hasn’t changed and b) want to wait a reasonable amount of time before declaring a device absent since some phone’s disappear when their screen goes black, we create some arrays to handle when something should be streamed.

Now for the meat of our code:

# Function that checks for device presencedef whosHere(i):     # 30 second pause to allow main thread to finish arp-scan and populate output    sleep(30)     # Loop through checking for devices and counting if they’re not present    while True:         # Exits thread if Keyboard Interrupt occurs        if stop == True:            print “Exiting Thread”            exit()        else:            pass         # If a listed device address is present print and stream        if address[i] in output:            print(occupant[i] + “‘s device is connected to your network”)            if presentSent[i] == 0:                # Stream that device is present                streamer.log(occupant[i],”:office:”)                streamer.flush()                print(occupant[i] + ” present streamed”)                # Reset counters so another stream isn’t sent if the device                # is still present                firstRun[i] = 0                presentSent[i] = 1                notPresentSent[i] = 0                counter[i] = 0                sleep(900)            else:                # If a stream’s already been sent, just wait for 15 minutes                counter[i] = 0                sleep(900)

The function “whosHere()” is where we check for the device and steam if it’s present or not. “output” is the result of the main thread calling arp-scan like before and looing for the device address. If it’s there, the following if statement is called. We check to see if “device present” has been streamed and either wait 15 minutes if it has or stream it!

# If a listed device address is not present, print and stream        else:            print(occupant[i] + “‘s device is not present”)            # Only consider a device offline if it’s counter has reached 30            # This is the same as 15 minutes passing            if counter[i] == 30 or firstRun[i] == 1:                firstRun[i] = 0                if notPresentSent[i] == 0:                    # Stream that device is not present                    streamer.log(occupant[i],”:no_entry_sign::office:”)                    streamer.flush()                    print(occupant[i] + ” not present streamed”)                    # Reset counters so another stream isn’t sent if the device                    # is still present                    notPresentSent[i] = 1                    presentSent[i] = 0                    counter[i] = 0                else:                    # If a stream’s already been sent, wait 30 seconds                    counter[i] = 0                    sleep(30)            # Count how many 30 second intervals have happened since the device             # disappeared from the network            else:                counter[i] = counter[i] + 1                print(occupant[i] + “‘s counter at ” + str(counter[i]))                sleep(30)

If the device’s address isn’t present, the else statement is called. Like above, we check to see if “device not present” has been streamed, but only if the device hasn’t shown up on the network in a 15 minute period. This way your device will hopefully be picked up even if it’s been sleeping for a little bit.

# Main thread try:     # Initialize a variable to trigger threads to exit when True    global stop    stop = False     # Start the thread(s)    # It will start as many threads as there are values in the occupant array    for i in range(len(occupant)):        t = Thread(target=whosHere, args=(i,))        t.start()     while True:        # Make output global so the threads can see it        global output        # Assign list of devices on the network to “output”        output = subprocess.check_output(“sudo arp-scan -l”, shell=True)        # Wait 30 seconds between scans        sleep(30) except KeyboardInterrupt:    # On a keyboard interrupt signal threads to exit    stop = True    exit()

Because we have multiple devices, we create a thread for each one here. Some logic is added to signal threads to exit on a Keyboard Interrupt. Arp-scan is called on line 109 and refreshed every 30 seconds.

Now run the script with:

sudo python presence.py

Watch what prints to the terminal to make sure your devices are being detected and that streaming is working. Head over to Initial State to checkout your streams!

<< Part 2: Initial State – Part 2: Your Personal Dashboard >>

Part 2. Your Personal Dashboard

Rachel edited this page 25 days ago · 2 revisions

 Pages 11

Pi Streaming Presence Detector

Clone this wiki locally

 Clone in Desktop

After you’ve confirmed your script is working, go check out your dashboard! You should see some tiles with a large emoji office building or “no” sign and then an office building.

The dashboard offers a quick way to see who’s at work, but adding other things like a temperature/humidity reading or the current weather would be both easy and interesting. I’ll also go over how to trigger text alerts based on when someone arrives or leaves later.

The main reason I wanted to do this project was as a proof of concept for triggering some sort of action when a certain device was detected – like playing specific theme music when someone enters the office! If I get that working, I’ll be sure to add it here.

It’s fine and dandy to run all of this while you’re SSH’d into the Pi, but we want it to work reliably when we’re not around. Keep reading for how to make this setup stick!

Part 3. Run the Script from Boot

Rachel edited this page 26 days ago · 2 revisions

 Pages 11

Pi Streaming Presence Detector

Clone this wiki locally

 Clone in Desktop

Running a script from boot on the Pi is pretty straightforward. We’re going to use a service calledcrontab:

sudo crontab -e

Pick your favorite text editor (I like nano) and at the bottom of the file (under all of the comments), add @reboot nohup sudo /usr/bin/python /home/pi/presence.py &. If you named your script something else or put it in a different directory, replace /home/pi/presence.py with the correct path. The path in my example is just the main Pi directory.

Save the file! You need to reboot for it to take effect, but we are going to add another task to our crontab in this next step.

Part 3. Reboot on Network Loss

Rachel edited this page 26 days ago · 1 revision

 Pages 11

Pi Streaming Presence Detector

Clone this wiki locally

 Clone in Desktop

To fix the network dropping issue, I decided to just implement a way for the Pi to detect a network connection and reboot if it’s not there.

First we need to create a script to check the WiFi and then trigger shutdown:

sudo nano /usr/local/bin/checkwifi.sh

Place the following inside of the file, being sure to replace the IP address with the IP address of your router:

ping -c4 IP_ADDRESS > /dev/null if [ $? != 0 ]then  sudo /sbin/shutdown -r nowfi

The ping check for a connection. If it returns with a non-zero exit code, the script sends the shutdown command. Save and exit out of the script. Now make sure its permissions are in order:

sudo chmod 775 /usr/local/bin/checkwifi.sh

Just like our presence.py script, we are going to add this script to crontab:

sudo crontab -e

Place */5 * * * * /usr/bin/sudo -H /usr/local/bin/checkwifi.sh >> /dev/null 2>&1 underneath the line we added earlier. This will run our checkwifi script every 5 minutes.

Now exit crontab and reboot the Pi:

sudo reboot

Everything should be setup and working!

Part 4. (Bonus) Text Alerts

Rachel edited this page 25 days ago · 7 revisions

 Pages 11

Pi Streaming Presence Detector

Clone this wiki locally

 Clone in Desktop

If you want a text or email alert every time someone’s device leaves or arrives, you can easily set it up inside of Initial State!

Note: You will need to be on the Pro plan to use triggers

We are going to follow the Trigger notification setup process outlined at here.

Just click on the shelf icon (in the top tray to the left of the Initial State logo) if it’s not already open, and click on “settings” beneath your “Who’s at the Office?” bucket name. Click on the “Triggers” tab in the settings menu.

You’ll want to set up your triggers like mine on the left. Select the data stream to trigger on (you can use the drop-down list to select from existing streams once a data bucket has loaded or you can type in the stream name/key manually; *note Safari does not support HTML5 dropdown lists). In my example screenshot, I selected “Adam”.

Select the conditional operator, in this case ‘=’, and set it equal to either present (which I symbolized with the emoji  , aka “office”) or whatever you used for not present (in my case ???? ???? ).

Click the ‘+’ button to add the Trigger condition and choose either email or SMS. Click the ‘+’ button to add the action. You’ll need to input any verification code if adding a new phone number or email to complete setup. Click done to return to the main screen.

Your trigger is now live and will fire when the condition is met!

I set mine up to text me when Adam, the hardest worker at Initial State, finally left the office:

 

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.