Ivy Tech Community College | Lawrence Library's raspberry pi gate counter project
Disclaimer: I am not a programmer by trade; I am a librarian with some web dev skills. There are probably better ways to accomplish this task, but this is how I did it with the tools and skills available to me. The following code/instructions are an amalgamation of google/stack overflow copy pasta and some basic javascript.
Would you rather run this in docker? Check out my other repo: Gate counter, now with more containerization docker-people-counter
table of contents
Ivy Tech has lots of libraries and no money. We want to be able to compare data across all 30ish libraries, but some don't have the funds for a gate counter. A raspberry pi is cheap, and with some coding magic and a little help from google's free tools, we can put gate counters in all of our libraries.
links to amazon
- raspberry pi 3, model b ($35)
- case ($7)
- power supply ($10)
- samsung 32gb evo plus microSD card with adapter ($13)
- PIR sensor ($14)
- jumper wires, female-female ($6)
total: $85
Alternatively, it might be easier to skip the first three and get the CanaKit (which includes raspi, case, and power supply) for ~$50
If, like me, you experience false triggers, you might also want to get some 3mm ferrite beads ($7 for 10 on amazon). I placed one on each end of the jumper wires to block the wifi signal that was causing interference.
You'll also need some way to connect to the pi. I used an HDMI-connected TV, extra mouse/keyboard, and ethernet cable for initial setup, then used VNC viewer from my work computer to connect headlessly via SSH.
See Raspberry Pi docs for all kinds of detail on how to get started.
At the moment, the PIR sensor portion of the raspi is taped to the inside of a kleenex box. I hope to move it to a less obvious-looking pvc pipe or something when I set it up in the library. The sensor is pretty sensitive (ha), and having it contained seems to keep the IR beam isolated enough to negate false positive reads.
My very fancy, extremely sophisticated setup in our break room.
There are many options for selecting and installing an OS. I'm using Raspbian. Installation documentation can help you choose and get started.
Note: One of the npm packages I use, raspi-io, only runs on Raspbian Jessie and newer.
I'm currently running the raspi on the staff wifi in my building. This is not an ideal setup. Getting the college to run an extra data drop is not very likely to happen, so I'm going to have to work with IT on a better wireless solution.
Getting the wifi set up correctly was challenging because of the network security or something. It took some googling, but I eventually found some raspi forum where a student had figured out what to include in the wpa config file to get on the university wifi, and this bit of network code ended up working for me at my institution (ymmv):
-
Open the wpa-supplicant file using nano:
sudo nano /etc/wpa_supplicant/wpa_supplicant.conf
-
Paste this in (REMOVE COMMENTS):
network={
ssid="network name" //mine is IVYStaff
key_mgmt=WPA-EAP
eap=PEAP
identity="[email protected]" //school username
password="password" //school password
phase2="auth=MSCHAPv2"
}
sudo reboot
I'm not familiar with networking, so I don't actually understand what most of this means. You're on your own to figure your system out!
Raspberry Pi wifi configuration docs
Now for the fun stuff!
The sensor has three pins on the back and you will use all three. Plug three jumper wires to those pins. The first time I tried this, I thought I needed to be super gentle, but these things are not all that fragile, so make sure you get a snug connection!
Hook up the other end of the wires to the following GPIO pins on the raspi motherboard (you can find the labels of PIR pins on the back next to where to pins connect to the sensor):
Ground (GND) --> Ground (pin 06)
V+ (VCC) --> 3.3v (pin 01)
Signal (OUT) --> GPIO 07 (pin 26)
Use this diagram for visual of where to plug things in:
You can always choose a different pin for the output, but you'll need to update the code on line 41 where it says GPIO7
.
The first time I set this up, I used the 5v power instead of 3.3v and it was giving me a false reading every minute at the same second. After reading in some forum that it might be the voltage, I set it to 3.3v. I still sometimes get false positives, but a reboot of the pi usually fixes that. Update: If you're getting false triggers every minute on the same second, you are probably experiencing wifi interference from the Pi 3's built-in wifi. You might benefit from adding ferrite beads to the jumper wires (see equipment list above).
You can collect the data however you want, but I'd rather all those numbers go to a spreadsheet in the cloud. Google Sheets to the rescue!
Create a new Google Form.
My form collects six pieces of input data as well as the timestamp. Because my team plans on using this program/device in multiple libraries, LOCATION
and DOOR
are important pieces of data for us. You might only have one location and one door. Feel free to remove those and any associated code.
The most important data is COUNT
. The code runs a cron job that submits the count every 10 minutes. Again, feel free to change this in the code if that is too frequent.
The last three inputs are all time-related. If the timestamp is sufficient for your needs, feel free to remove these from the code. MONTH
is helpful to divide the form data into different spreadsheets by month without too much trouble in the spreadsheet logic department. DATE
is similarly helpful and is useful when summing the daily count. TIME
is useful for counting which hours have the most traffic.
I'm sure all of this can be done using only the timestamp, but this was easier for me.
Once you've added your fields in the Questions pane, switch to the Reponses pane and click the green spreadsheet icon to create a new Google Sheet for the form responses.
During a previous project, I realized you can send data to google form without ever needing to see or use the ugly form page. Each form input has a unique entry ID, and when those IDs and corresponding responses are appended to the form's URL string, google posts that information to the form responses. These can then go straight into a spreadsheet.
Use your browser's handy-dandy inspector tools on each input of your form to find the unique ID number (it will look like entry.039480298
). Swap out the URL of the form (everything except the /viewform
bit at the end) and entry variables in gate-counter.js
and you should be good to go!
What the form URL should look like:
Where to find entry ID number in inspector:
You can test your URL by taking the URL from the cron job section of the code and sub in all the variables (both IDs and their respective values) and popping it into your address bar. If you get the google form submission page saying you submitted a form, you win!
In case you are interested in embedding google forms in your site without inserting the ugly form itself, there's a really neat tool that can build out the html of a custom google form for you: Google Forms HTML Exporter
My spreadsheet has some logic and math built in to separate the data from the form by month and count it up in different ways. This is by no means an elegant solution, but it is free and it works. Feel free to make a copy! File > Make a copy
Most of the examples of IR sensor people counters I found via google were built with python. I'm a javascript girl. For the sake of the raspi, I attempted to learn python, but I struggled to debug in a new language, so I switched to javascript. See the further reading section below to see what other raspi-ers accomplished using python.
The best (only?) way to use javascript on a raspberry pi is with node.js. I used these two guides for installing node on my raspi:
- Beginner’s Guide to Installing Node.js on a Raspberry Pi
- adafruit - Node.js Embedded Development on the Raspberry Pi
npm packages and modules do the heavy code lifting for us. This project would not be possible without them. If you've never heard of npm, check it out and come back: What is npm?
The Johnny Five platform makes coding javascript/node robotics and internet-of-things projects super easy. I wandered the internet and npm for a solid week before discovering this wonderful platform, and this essentially solved all my problems.
The API has tons of useful components, but we only need one for this project: motion. The sensor I used is the first in the list of supported sensors, so I knew I was on the right track! You can dabble with the different events, but I've found there's not much of a difference between motionstart
and motionend
, and change
was too much activity.
Johnny Five is written to be used with an arduino. Since we're using a raspi, we'll need to install a plugin that converts the bread board info to the raspi's GPIOs. raspi-io is just the thing.
Request makes http calls. In other words, it's what sends our form URL to google. It doesn't get any easier than those six lines of code.
Moment.js is the easy way to deal with time in javascript. Fun fact: javascript counts time as how many milliseconds have passed since midnight of January 1, 1970! How fun is it to calculate 1510774793166 ms
into a recognizable date format? Not a whole lot, actually. Moment.js takes care of all of that for us!
If you've decided to remove the month, date, and time variables from your form/code, you don't need moment.js. There is no need to install the module and delete it from the required modules at the top of the file.
The easiest way to schedule our program to send our form data at a specific intervals is to set up a cron job. The best scheduler I've found for node is node-schedule.
There are lots of timing options, so if you don't want your cron job to run every 10 minutes, just change the time intervals.
Open gate-counter.js
and replace all the variables with the appropriate values from your google form. Here's where you can tinker with what data you want to send, how often your cron job runs, etc.
My plan is to eventually create an npm package that will do all of this, but I haven't gotten that far. Until then, this should work as long as you replace the google form URL and entry IDs with your form info.
In your project's working directory, run:
npm install --save request moment node-schedule raspi-io johnny-five
This could take a few minutes.
Then:
sudo node gate-counter.js
If your PIR sensor is hooked up correctly and you have no syntax errors in your gate-counter.js
file, you should get something looking like this in your console:
pi@raspberrypi:~/gate-counter $ sudo node gate-counter.js
1510773792422 Available RaspberryPi-IO
1510773792696 Connected RaspberryPi-IO
1510773792706 Repl Initialized
>> calibrated November 15, 2017 14:23:14
If so, your pi is calibrated and ready to start counting!
As with most of my coding projects, I couldn't have gotten here without the previous work of fellow raspi enthusiasts. Here's a list of articles/blog posts/stack overflow responses I found to be the most helpful during my quest.
My first google after thinking "I bet I could do this with a raspi..." turned up some interesting stuff.
- Building a People Counter with Raspberry Pi and Ubidots
- Building a People Counter with a PIR sensor
- Footfall
When I encountered a problem, these articles helped me over a hurdle.
- When I struggled for months with false positives from the PIR sensor, I finally came across Magic Mirror with a Motion Detector, which gave me the idea to use ferrite beads on the jumper wires to negate wifi interference. It worked!
- Before I found the magic mirror article, I was going to try a workaround: write a shell script that disables wifi at bootup, then every hour or so (maybe nightly?) turn on the wifi to send the data, then turn it off again. Turning off the wifi on the device using
sudo ifconfig wlan0 down
cleared up false positives immediately, which is how I determined that my false postivies problems was indeed due to wifi interference. A raspberry pi stack exchange question/answers 'Disable wifi wlan0 on pi 3' helped me figure out what to put in my shell script.