Infrared Ballotbot

by mbaldassaro in Circuits > Sensors

2665 Views, 26 Favorites, 0 Comments

Infrared Ballotbot

57a0e37945bceb6047001796.jpeg
cover - action.JPG

A "smart" polling station equipped with sensors that provide data on voter participation can help to detect - and deter - election fraud. Data collected from a sensor placed in a door jamb that counts and timestamps when voters enter polling stations should correlate with data from an ultrasonic ballotbot in a ballot box that counts and timestamps votes cast. Collecting this data in real time enables “virtual monitoring” of polling stations that increases confidence in the process and allows for action to be taken where suspicious activity occurs.

For the purposes of counting voters, a simple passive infrared (PIR) sensor should be sufficient. A PIR sensor detects light energy radiating from objects that emit energy (e.g. people). When a person passes in front of a PIR sensor, a positive change in infrared levels is detected triggering a digital pulse. Durable and cost-effective, PIR sensors are commonly used as motion detectors for automatic faucets, commercial security systems, and energy-saving lights.

In this tutorial, we’ll use a “mini” PIR sensor with a good detection range (3 meters) and draws minimal current. To create our infrared ballotbot, we’ll connect the sensor to a compact board called the Huzzah ESP8266 Feather developed by Adafruit. The centerpiece of the board is the ESP8266 microcontroller which can be programmed using the Arduino IDE and set up to communicate via internet (making it a real Internet of Things “thing”).

We’re going to enable the device to communicate via internet using MQTT, a lightweight protocol based on the publish-subscribe paradigm (check out these blog posts from HiveMQ for an introduction to MQTT). For this tutorial, we’re going to be using an MQTT broker called Shiftr to publish the sensor data.

To allow for continuous data collection and timestamping in case the internet connection is interrupted, we’re going to use the Adalogger FeatherWing with real-time clock (RTC) and SD card storage capability. And to make the infrared ballotbot portable, we’re going to use a rechargeable lithium polymer battery.

What You Need

whatyouneed.JPG

Set Up the Huzzah ESP8266 Feather

setup.jpeg

To be able to use the Huzzah ESP8266 with the Arduino IDE, PIR Mini Sensor, and the Adalogger FeatherWing, you’ll need to do a bit of setup work including:

1. Solder socket headers onto ESP8266 Feather

2. Download and install the CP210x USB to UART Driver

3. Install the ESP8266 Board in the Arduino IDE

4. Install the Arduino MQTT library by Joel Gaehwiller

First, you’ll need to solder socket headers to be able to connect the PIR Mini Sensor for testing and the Adalogger FeatherWing for the prototype (see photo).

Second, the Huzzah ESP8266 Feathers uses the CP2104 USB-UART chip. You’ll need to download and install the CP210x USB-UART driver on your computer to enable your Serial port to “see” the board.

Third, you’ll need to install the ESP8266 Board Package on the Arduino IDE (make sure you are using Arduino IDE v1.6.6 or a more recently updated version. If not, download the latest version). Follow the steps in the tutorial on the Adafruit blog to install the ESP8266 Board Package.

Finally, you’ll need to install an MQTT library. In the Arduino IDE menu bar, go to Sketch > Include Library > Manage Libraries. When you click on Manage Libraries, a dialogue box should appear. Search for “MQTT” then select and install the latest version of the MQTT library by Joel Gaehwiller. Once the library is installed, you can close the dialogue box. Note: Alternatively, you can download the MQTT library from GitHub and install it manually.

Note: for this tutorial, I am using Arduino IDE v1.6.9, ESP8266 board package v2.1,and MQTT library v1.10.1.

Build the Circuit (sensor, No FeatherWing)

Circuit_no_wing.JPG

Let’s build the circuit with just the ESP8266 Feather and the PIR Mini Sensor to make sure it works.

The SimplyTronics PIR Mini Sensor has three connector pins:

1) VDD (power)

2) OUT (input)

3) GND (ground)

Connect the ESP8266 Feather and the PIR Mini Sensor using your male-female jumper wires. Use the photo as reference.

Connect the ESP8266 Feather 3V pin to the PIR Mini Sensor VDD pin

Connect the ESP8266 Feather GND pin to the PIR Mini Sensor GND pin

Connect the ESP8266 Feather pin 16 to the PIR Mini Sensor OUT pin

Upload the Code (sensor, No FeatherWing)

code+shiftr.png

Connect the ESP8266 Feather to your computer via the USB Serial port. Open the Arduino IDE and enter the following code in a new sketch. Alternatively, you can download the file from the ballotbots GitHub repo.

#include <ESP8266WiFi.h>
#include <MQTTClient.h>

const char* ssid     = "your_wifi_network_id";
const char* password = "your_wifi_network_password";
const char* host =     "www.boxpop.me";
String url = "/test.html";

WiFiClient net;
const int httpPort = 80;
MQTTClient client;

int calibrationTime = 30;  
long unsigned int lowIn;        
long unsigned int pause = 100;  
boolean takeLowTime;  
int i = 1;
int pirPin = 16;    
void connect();     

void setup() {
  Serial.begin(115200);
  pinMode(pirPin, INPUT);
  delay(100);

//initialize WIFI 
  WiFi.begin(ssid, password);


//initialize MQTT 
  client.begin("broker.shiftr.io", net);
  connect();

Serial.println("calibrating sensor ");   
    for(int i = 0; i < calibrationTime; i++){
      Serial.print(".");
      delay(1000);
      }
      Serial.println(" done");
      Serial.println("SENSOR ACTIVE");
      delay(50);
}

void connect() {
  Serial.print("trying to connect to ");
  Serial.println(ssid);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.print("successfully connected to ");  
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

if (!net.connect(host, httpPort)) {
    Serial.println("could not connect :(");
    return;
  }
  
  net.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" + 
               "Connection: close\r\n\r\n");
  delay(500);
  
  while(net.available()){
    String line = net.readStringUntil('\r');
    Serial.print(line);
  }
  
  while(!client.connect("minipir", "try", "try")) {  
    Serial.print(".");
    delay(1000);
  }
}
   
void loop() {
  client.loop();
 
  if(digitalRead(pirPin) == HIGH) {
      if(lockLow) {      
        lockLow = false;
        Serial.print(i++);
        Serial.print(", ");
        Serial.println("motion detected");
        client.publish("/ballotbots", "motion detected");
      }
    }
    
  if(digitalRead(pirPin) == LOW) {    
      if(takeLowTime) {
        lowIn = millis();     
        takeLowTime = false;  
      } 
      
      if(!lockLow && millis() - lowIn > pause) { 
        lockLow = true;
      }
    }
}

void messageReceived(String topic, String payload, char * bytes, unsigned int length) {
    Serial.print("incoming: ");
    Serial.print(topic);
    Serial.print(" - ");
    Serial.print(payload);
    Serial.println();
}

In the code, make sure you update the following values to reflect your actual wifi network name and password:

const char* ssid = “your_wifi_network_id”
const char* password = “your_wifi_network_password” 

After you’ve updated these values, verify, save, and upload the sketch to the ESP8266 Feather (make sure you’re communicating on the right port).

Once it’s done uploading, open the Serial Monitor (make sure the baud rate is set to 115200). You should see a message indicating that the ESP8266 Feather is “trying to connect to [your_wifi_network_id]”. A number of decimals will appear followed by a message indicated that you have “successfully connected to [your_wifi_network_id]”, your network IP address, some meta content from an HTML file served by Github, followed by a “hello world!” message.

While the ESP8266 Feather is connecting to the internet, the sensor will begin settling. Once it has connected to the wifi You’ll see a messaging indicating that it is “calibrating” followed by more decimals and a “done” message. When you see “SENSOR ACTIVE” the PIR Mini Sensor will be ready. If you wave your hand in front of the aperture, you should get a reading of “[#], motion detected”. Once the sensor has stopped detecting motion, it will wait a few seconds and reset.

Once the ESP8266 has established an internet connection, it will connect to the MQTT broker. If you visit https://shiftr.io/try you’ll see your client (“minipir”) ready to publish data to a topic (“ballotbots”) via the Shiftr MQTT broker. When the sensor is active and motion is detected, you should see the data transfer from the “minipir” client through the broker to the “ballotbots” topic. The payload of the transfer (“motion detected”) will appear in the upper left-hand corner of the screen with a timestamp marking the last payload received. Try it and see for yourself!

Set Up the Adalogger FeatherWing

setup featherwing.JPG

To be able to use the Adalogger FeatherWing, you need to do a bit of set up work including:

1. Soldering headers onto the Adalogger FeatherWing

2. Downloading libraries to use the FeatherWing

3. Calibrating the real-time clock

4. Formatting the SD card (if it is not pre-formatted)

First, you solder headers onto the Adalogger FeatherWing to be able to connect it to the ESP8266 Feather (see photo).

Second, you need to download the Adafruit real-time clock (RTC) and SD card libraries. You will need these libraries to enable the FeatherWing to communicate with the Feather.

Download Adafruit RTC Library

Download Adafruit SD Card Library

Once you have downloaded the RTC library, unzip the zip file, rename the unzipped folder “RTClib”, and install it in your Arduino directory. Follow the same process for the SD Card library and rename the unzipped folder “SD”. If you haven’t installed a library before, this Adafruit tutorial shows you how on Linux, OSX and Windows. Once you have installed the libraries, you will need to restart the Arduino IDE.

Third, you need to calibrate the real-time clock. To calibrate the clock, insert the CR1220 3V coin cell battery into the battery holder. Put the Adalogger FeatherWing on the ESP8266 Feather, connect the Feather to your computer via USB cable, and open up the Arduino IDE. In the Arduino IDE, open the pcf8523.ino sketch (go to File > Examples > RTClib > pcf8253) and upload the sketch to the Feather. Once the sketch is uploaded, open the Serial monitor (make sure the baud is set to 57600) and you should see the current time displayed (and the time a week from now in the future).

Finally, if you are not using a pre-formatted SD card, you will need to format it before you can use it. If so, insert the SD card into your computer, download the SD card formatter for your operating system and follow the instruction manual.

Build the Circuit (sensor and FeatherWing)

circuit w battery.JPG

First, desolder the right-angle male headers that are connected the PIR Mini Sensor pads using a solder sucker (if you have never desoldered headers before, watch this video from the Adafruit blog). Note: alternatively, you can use wire cutters to trim the ends of the right-angle headers if you don't want to desolder.

Then, solder jumper wires from the PIR Mini Sensor to the pads on the Adalogger FeatherWing:

Solder the Adalogger FeatherWing 3V pad to PIR Mini Sensor VDD pad

Solder the Adalogger FeatherWing GND pad to the PIR Mini Sensor GND pad

Solder the Adalogger FeatherWing pin 16 pad to the PIR Mini Sensor OUT pad

Upload the Code (sensor and FeatherWing)

code + wing + shiftr.png

Put the Adalogger FeatherWing with the soldered PIR Mini Sensor on the ESP8266 Feather. Make sure the coin cell battery and micro SD card are inserted in the Adalogger FeatherWing.

Connect the ESP8266 Feather to your computer via the USB Serial port and open up a new sketch in the Arduino IDE. Paste the following code in the new sketch. You can also download the file from the ballotbots Github repo.

<p>#include <ESP8266 WiFi.h><br>#include <MQTTClient.h>
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <RTClib.h></p><p>const char* ssid     =      "your_wifi_network_id";
const char* password = "your_wifi_network_password";
const char* host =          "www.boxpop.me";
String url = "/test.html";</p><p>WiFiClient net;
const int httpPort = 80;
MQTTClient client;</p><p>int calibrationTime = 30;  
long unsigned int lowIn;           
long unsigned int pause = 100;  
boolean lockLow = true;
boolean takeLowTime;  
int i = 1;
int x = 1;          
const int pirPin = 16;    
</p><p>RTC_PCF8523 rtc; 
DateTime now;
void connect();</p><p>void setup(){
  Serial.begin(115200);
  pinMode(pirPin, INPUT);
  delay(100);  </p><p>  #ifndef ESP8266
    while (!Serial); 
  #endif</p><p>//initialize WIFI 
  WiFi.begin(ssid, password);
  client.begin("broker.shiftr.io", net);  </p><p>//initialize MQTT 
  connect();</p><p>//START RTC
  Wire.begin();
  rtc.begin();
  //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));    
  now = rtc.now();
  
  if(!rtc.begin()) {
   Serial.println("RTC Fail");
   return;
  }</p><p>  Serial.println("calibrating sensor ");     
    for(int i = 0; i < calibrationTime; i++){
      Serial.print(".");
      delay(1000);
      }
      Serial.println(" done");
      Serial.println("SENSOR ACTIVE");
      delay(50);
  
  //START SD
  if(!SD.begin()) {
    Serial.println("SD Card Fail");
    return;
  }
  
  //OPEN SD CARD
  File logFile = SD.open("motion.csv", FILE_WRITE);
    if(logFile) {
      String header = "value, reading, date, time, label";
      logFile.println(header);
      logFile.close();  
      Serial.println(header);
  }
  else {
     Serial.println("Not logging!");
  }
}</p><p>void connect() {
  Serial.print("trying to connect to ");
  Serial.println(ssid);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }</p><p>  Serial.print("successfully connected to ");  
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());</p><p>  if (!net.connect(host, httpPort)) {
    Serial.println("could not connect :(");
    return;
  }
  
  net.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" + 
               "Connection: close\r\n\r\n");
  delay(500);
  
  while(net.available()){
    String line = net.readStringUntil('\r');
    Serial.print(line);
  }
  
  while(!client.connect("minipir", "try", "try")) {   
    Serial.print(".");
    delay(1000);
  }
}
 
void loop() {
  client.loop();
  now = rtc.now();
  
             
  if(digitalRead(pirPin) == HIGH) {
      if(lockLow) {      
          lockLow = false;
          Serial.print(i++);
          Serial.print(", ");
          Serial.print("motion detected");
          Serial.print(", ");
          Serial.print(now.month(), DEC);
          Serial.print("/");
          Serial.print(now.day(), DEC);
          Serial.print("/");
          Serial.print(now.year(), DEC);
          Serial.print(", ");
          Serial.print(now.hour(), DEC);
          Serial.print(":");
          Serial.print(now.minute(), DEC);
          Serial.print(":");
          Serial.print(now.second(), DEC);
          Serial.print(", ");
          Serial.println(now.unixtime());
          logData();
          client.publish("/ballotbots", "motion detected");
        }
      }</p><p>  if(digitalRead(pirPin) == LOW) {    
      if(takeLowTime) {
        lowIn = millis();    
        takeLowTime = false;  
      } 
      
      if(!lockLow && millis() - lowIn > pause) { 
        lockLow = true;
      }
    }
}</p><p>void logData() {
  File logFile = SD.open("motion.csv", FILE_WRITE);
    if(logFile) {
          logFile.print(x++);
          logFile.print(", ");
          logFile.print("motion detected");
          logFile.print(", "); 
          logFile.print(now.month(), DEC);
          logFile.print("/");
          logFile.print(now.day(), DEC);
          logFile.print("/");
          logFile.print(now.year(), DEC);
          logFile.print(", ");
          logFile.print(now.hour(), DEC);
          logFile.print(":");
          logFile.print(now.minute(), DEC);
          logFile.print(":");
          logFile.print(now.second(), DEC);
          logFile.print(", ");
          logFile.println(now.unixtime());
          logFile.close();  
       }
}</p><p>void messageReceived(String topic, String payload, char * bytes, unsigned int length) {
    Serial.print("incoming: ");
    Serial.print(topic);
    Serial.print(" - ");
    Serial.print(payload);
    Serial.println();
}</p>

In the code, make sure you update the following values to reflect your actual wifi network name and password:

const char* ssid = “your_wifi_network_name” 
const char* password = “your_wifi_network_password” 

After you’ve updated these values, verify, save, and upload the sketch to the ESP8266 Feather (make sure you’re communicating on the right port).

Once it’s done uploading, open the Serial Monitor (make sure the baud rate is set to 115200). You should see the same messages as before indicating that the ESP8266 Feather a message indicating that you have connected to your wifi network, some meta content from an HTML file followed by a “hello world!” message, and a message indicating that the sensor it is “calibrating” followed by a “SENSOR ACTIVE” message.

You'll also get a header message with the text "value, reading, date, time, label" which is the same header that will appear on the newly-created "motion.csv" file on your SD card. Now if you wave your hand in front of the aperture, you'll get a reading of “[#], motion detected, [date], [time], [unixtime]”. The reading that you see in the Serial Monitor is simultaneously being written to the SD card "motion.csv" file.

If you visit https://shiftr.io/try, you’ll should again see the “minipir” client publish data to the “ballotbots” topic in the upper left-hand corner of the screen.

Test the Prototype

testprotoype.JPG

Now that your infrared ballotbot is a working prototype, it's time to test it in a door jamb.

Use sticky back velcro strips to affix the lithium polymer battery to the back of the ESP8266 Feather. Connect the battery to the battery jack on the Feather and affix the ballotbot to the doorjamb using more velcro strips.

Note: make sure your lithium polymer battery is charged. If you connect the battery to the Feather while the feather is connect to your computer via USB, the battery will charge. While the battery is charging, a yellow charging light will be on. When the light goes off, the battery is fully charged.

Once you've got a secure velcro connection, you are ready to start collecting and transmitting data on voters entering the polling station in real-time via internet! Go to https://shiftr.io/try and wait for someone to enter. When someone enters, you should see a timestamped "motion detected" reading on the screen.

Welcome to the internet of things!