Motion Sensor

Motivation

To create a sensor that detects motion and stores data online.

Motion is detected using an Arduino Nano with a PIR sensor. The Arduino Nano has an Ethernet shield and is connected to the internet where it stores data on a thingspeak server. Everything is nicely placed within a 3D printed case.

3D Printed Casing

The arduino and ethernet shield is placed inside a 3D printed box with easy access to the PIR sensor adjustments. These being sensitivity/time to keep motion detection and range.

Prototyping

First trials used an arduino nano and a motion sensor. The LED lights up, while motion is being detected.

Then a few prototypes were made, connecting the Arduino Nano with ethernet shields

Data Entries

I have had a motionsensor constantly logging data for every 20 seconds, and it has been running constantly for a few years now. I recently did reset my log and last time I checked there were: ~447.063 entries / data points available. This corresponds to ~100 days of data, logging every 20th second.

When data are stored online, they can easily be retrieved using APIs etc. You can follow another project I made logging weather pressure data, which all data are logged and available here.

Data on the phone

The nice thing about thingspeak, is the ease of getting an app for the phone. I use a Thingspeak Widget to retrieve data from all my individual sensors. Then I can always follow the temperature in my workshop or near my 3D printer, humidity, pressure, light level and motion in my workshop. PIR is the motion widget, because it is showing 0: no motion is present.

I recall buying a household plant for my workshop. I asked the usual question of how much light it did need, and he said - how many lux do you have where it is being placed .. It was really great to pick up the phone and show him graphs of light levels, temperatures, humidity etc. He sure didn’t expect that !

Data Processing

The data retrieved from the module is just a simple ‘0’ (no motion) or ‘1’ (motion). But it is really interesting how much you can extract from that sort of data.

These types of data are like a fingerprint! It is scary how much information you get, when did go to bed and when did I got up in the morning. When I started working in the workshop and how the activity (motion) level increased during the day. All, this from simple binary numbers, scary - but also really cool.

Because data is given for every 20th second, it is easy to average over a period of time, for example 30 minutes. Then a plot can be made showing the motion activity level between 0 and 1, for a given time in my workshop

IRL Testing

We actually did place a few at my work. And using only motion data like this, you can see which person they actually monitored ! Like a personal fingerprint. Think about it. Most people have routines, when do they usually meet, when they go to launch etc. Simple data points like a ‘0’ and a ‘1’ can give so much information. Data like this, can really be useful or misused. Simple binary data points can give you a lot of information - you just need enough of them.

Complete code

The complete code can be seen here. There are also libraries available to connect arduino with thingspeak which I recommend. The code is assembled from a lot of different sources, and has been mixed a lot. It will be almost impossible now to mention all the sources used - but it is possible to use some of the many guides online.

#include <UIPEthernet.h>


// **** SENSOR SETUP ****
const int inputPin = 2;               // PIR Sensor InputPin
bool mv = 0;

// **** THINGSPEAK SETTINGS ****
String apiKey = "PLACE YOUR API KEY HERE";
const char* server = "api.thingspeak.com";
unsigned long UpdateThingSpeak = 20000;      // Time interval in milliseconds to update ThingSpeak (>16 s)
unsigned long lastConnectionTime = 0;

// **** VARIABLE SETUP ****
boolean lastConnected = false;
int failedCounter = 0;

// **** ETHERNET SETTINGS ****
byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x78, 0xEE  }; # MAKE YOUR OWN MAC ADDRESS HERE
// IPAddress ip(XXX, XXX, XXX, XXX); // SET YOUR STATIC IP ADRESS HERE
EthernetClient client; // Initialize Arduino Ethernet Client

void setup() {
  Serial.begin(9600); // Start Serial for debugging on serial monitor
  delay(10);  // allow time for sensors to start up

  // Start Ethernet on Arduino
  Ethernet.begin(mac);  // Dynamic IP
  // Ethernet.begin(mac, ip);  // Fixed IP
}

void loop() {
  // Print Update Response to Serial Monitor
  if (client.available())
  {
    char c = client.read();
    Serial.print(c);
  }
  
  // Disconnect from ThingSpeak
  if (!client.connected() && lastConnected)
  {
    Serial.println("...disconnected");
    Serial.println();
    client.stop();
  }

  // Update ThingSpeak
  if(!client.connected() && ((unsigned long)(millis() - lastConnectionTime) >= UpdateThingSpeak))
  {
    mv = digitalRead(inputPin); // PIR
    Serial.println("mv = ");
    Serial.println(mv);
    updateThingSpeak("field1="+String(mv));
  }

  // Check if Arduino Ethernet needs to be restarted
  if (failedCounter > 3 ) {startEthernet();}
  
  lastConnected = client.connected();
}

void updateThingSpeak(String tsData)
{
  if (client.connect(server, 80))
  {
    client.print("POST /update HTTP/1.1\n");
    client.print("Host: api.thingspeak.com\n");
    client.print("Connection: close\n");
    client.print("X-THINGSPEAKAPIKEY: "+apiKey+"\n");
    client.print("Content-Type: application/x-www-form-urlencoded\n");
    client.print("Content-Length: ");
    client.print(tsData.length());
    client.print("\n\n");
    client.print(tsData);
    
    lastConnectionTime = millis();
    
    if (client.connected())
    {
      Serial.println("Connecting to ThingSpeak...");
      Serial.println();
      failedCounter = 0;
    }

    else
    {
      failedCounter++;
      Serial.println("Connection to ThingSpeak failed ("+String(failedCounter, DEC)+")");
      Serial.println();
    }
  }

  else
  {
    failedCounter++;
    Serial.println("Connection to ThingSpeak Failed ("+String(failedCounter, DEC)+")");
    Serial.println();
    lastConnectionTime = millis();
  }
}

void startEthernet()
{
  client.stop();
  Serial.println("Connecting Arduino to network...");
  Serial.println();
  delay(1000);
  
  // Connect to network amd obtain an IP address using DHCP
  if (Ethernet.begin(mac) == 0)
  {
    Serial.println("DHCP Failed, reset Arduino to try again");
    Serial.println();
  }
  
  else
  {
    Serial.println("Arduino connected to network using DHCP");
    Serial.println();
  }
  delay(1000);
}