Introduction: Arduino Ping Colleague Proximity

This is an Arduino Colleague Proximity notifier.

Function:

It pings IP-addresses for which the response is displayed with LEDs. If a reply is received, a corresponding LED switches on. It can also ping mobile wifi connected devices, or any other object with ip (such as a server) to check for status.

The environment this was designed is a university with a corporate wifi network. As every colleague works on laptops (wirelessly), this is in effect a notifier for colleagues being at work. The campus is quite large, so there's no more useless trips to the 9th floor to see if someone is in. Or whether a spontaneous excursion to the coffee machine to meet someone specific is worthwhile.. Additionally, by pinging mobile devices with liberal wifi settings, this Arduino setup tells you if that device is in range of the network. Note that DHCP client lease times can be an issue in the environment: this project relies on relatively stable IPs assigned to specific devices.

This project is a variation on the Arduino news notifier, both now combined on one breadboard. It was designed to work with Mac OSX. (https://www.instructables.com/id/Arduino-news-feed-...

An expansion planned for the future is to timestamp responses received to display last known ack on the LCD. Another project planned is to use trace route rather than pings, and resolve the location by ip for display on the LCD.

Step 1: Required Parts

All parts used are included in the basic Arduino starter kit.

  • Arduino board
  • Breadboard
  • LEDs
  • Servo (basic servo used here: SM-S2309S)
  • (>12) Breadboard cables
  • Optional: 16x2 Character LCD display, compatible with the LiquidCrystal library (works with larger LCD's with tweaking)
  • Potentiometer, preferably 10K ohms.
  • USB to USB-B cable (standard USB-to-Arduino cable)

Step 2: Wiring

Wiring as shown on the photo. If in demand, I'll make a schematic for the setup.

Step 3: Software and Libraries

Aside from the basic Arduino UI, the software and Libraries/Extensions required for this project are as follows.

The first piece of software you will need is Python. Python is an easy to learn programming language for the PC, Linux, or Mac. It is available for free here:http://www.python.org/. The final thing you need is the extension that will let the Python computer program work with the Arduino itself, via the serial cable. The required extension is Pyserial, available here: http://pyserial.sourceforge.net/. This setup is designed to work with Python 3.1 and later, with Pyserial 2.7.

Optionally, you can add a LCD display, for which you would need a second library called LiquidCrystal440. It is available here: http://code.google.com/p/liquidcrystal440/. It is an updated version of the LiquidCrystal library, and helps deal with some issues when it comes to addressing memory.

Step 4: Arduino Code

// This is the Arduino code for a Colleague Proximity Scan by Sander van Haperen

// It was updated last in August 2014. // It is originally based on a code for the Arduino RSS feed project, by Fritter

int startstring = 0; // recognition of beginning of new string int charcount = 0; // keeps track of total chars on screen

const int ledPin = 6; // the pin that the LED is attached to int incomingByte; // a variable to read incoming serial data into

#include String readString, incPinInit, incPin1, incPin2, incPin3, incPin4, incPin5, incPin6;

Servo myservo; // create servo object to control a servo // a maximum of eight servo objects can be created

#include // import the LiquidCrystal Library LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

void setup() { Serial.begin(9600); // opens serial port, sets data rate to 9600 bps lcd.begin(16,2); // Initialize the LCD size 16x2. Change if using a larger LCD lcd.setCursor(0,0); // Set cursor position to top left corner

myservo.attach(6); // attaches the servo on pin 9 to the servo object for (int thisPin = 2; thisPin < 13; thisPin++) { //init pins 2 thru 6 as output pinMode(thisPin, OUTPUT); } }

void loop() { char c = 0; // for incoming serial data while (Serial.available()) { delay(5); //delay to allow buffer to fill

if (Serial.available() >0) {

char c = Serial.read(); //gets one byte from serial buffer readString += c; //makes the string readString }

Serial.println(readString);

if (readString.length() >0) {

digitalWrite(13, HIGH); // set LED pin 13 as indicator of receiving serial data // expect a string like 07002100 containing the pin states incPinInit = readString.substring(0, 1); //get the first character to check for init symbol

//Serial.println(readString); //see what was received if (incPinInit == "*") { //check for marker/'header' that signifies ping states incPin1 = readString.substring(2, 3); //get the next character incPin2 = readString.substring(4, 5); //get the next character incPin3 = readString.substring(6, 7); //get the next character incPin4 = readString.substring(8, 9); //get the next character incPin5 = readString.substring(10, 11); //get the next character incPin6 = readString.substring(12, 13); //get the next character

int n1 = incPin1.toInt(); int n2 = incPin2.toInt(); int n3 = incPin3.toInt(); int n4 = incPin4.toInt(); int n5 = incPin5.toInt(); int n6 = incPin6.toInt(); for (int thisPin = 2; thisPin < 13; thisPin++) { //reset default state for all pins LOW digitalWrite(thisPin, LOW); }

// now check all 6 pin states and write HIGH if ping state is positive if (n1 == 1) { digitalWrite(10, HIGH); } if (n2 == 1) { digitalWrite(9, HIGH); } if (n3 == 1) { digitalWrite(8, HIGH); } if (n4 == 1) { digitalWrite(7, HIGH); } if (n5 == 1) { digitalWrite(5, HIGH); } if (n6 == 1) { digitalWrite(1, HIGH); }

} if (incPinInit == "~") { //check for marker/'header' that signifies ping states startstring = 0; // Set the printing to off delay(5000); // Wait 5 seconds lcd.clear(); // Wipe the screen charcount = 0; // reset the character count to 0 lcd.setCursor(0,0); // reset the cursor to 0,0 if (startstring == 1){ // check if the string has begun if first '~' has been read if (charcount <= 30){ // check if charcount is under or equal to 30 lcd.print(incomingByte); // Print the current byte in the serial Serial.print(incomingByte); charcount = charcount++; // Increment the charcount by 1 yes I know it's awkward } } if (charcount == 31){ // if the charcount is equal to 31 aka the screen is full delay(500); lcd.clear(); // clear the screen lcd.setCursor(0,0); // set cursor to 0,0 lcd.print(incomingByte); // continue printing data charcount = 1; // set charcount back to 1 } if (incomingByte == '~'){ // Check if byte is marker ~ to start the printing startstring = 1; // start printing } } digitalWrite(13, LOW); int pos = 90; // variable to store the servo position myservo.write(pos); // tell servo to go to position in variable 'pos' delay(10);

}

} readString=""; }

Step 5: Python Code

#import library to do http requests:

import urllib.request #import pyserial Library import serial #import time library for delays import time

import subprocess import os

#import xml parser called minidom: from xml.dom.minidom import parseString

datamem = "0" datamem2 = "0"

#Initialize the Serial connection in COM3 or whatever port your arduino uses at 9600 baud rate ser = serial.Serial("/dev/tty.usbmodem1411", 9600)

i = 1 #delay for stability while connection is achieved time.sleep(5) while i == 1:

strMarkerPing = ''

#if ( a == a ): # check if host is alive using PING

strPingStates = '*,'

with open(os.devnull, "wb") as limbo: result=subprocess.Popen(["ping", "-c", "1", "-n", "-W", "2", "146.50.1.XXX"], stdout=limbo, stderr=limbo).wait() if result: strPingStates = strPingStates + '0,' else: strPingStates = strPingStates + '1,'

with open(os.devnull, "wb") as limbo: result=subprocess.Popen(["ping", "-c", "1", "-n", "-W", "2", "145.18.1.XXX"], stdout=limbo, stderr=limbo).wait() if result: strPingStates = strPingStates + '0,' else: strPingStates = strPingStates + '1,'

with open(os.devnull, "wb") as limbo: result=subprocess.Popen(["ping", "-c", "1", "-n", "-W", "2", "145.109.1.XXX"], stdout=limbo, stderr=limbo).wait() if result: strPingStates = strPingStates + '0,' else: strPingStates = strPingStates + '1,'

with open(os.devnull, "wb") as limbo: result=subprocess.Popen(["ping", "-c", "1", "-n", "-W", "2", "145.18.1.XXX"], stdout=limbo, stderr=limbo).wait() if result: strPingStates = strPingStates + '0,' else: strPingStates = strPingStates + '1,'

with open(os.devnull, "wb") as limbo: result=subprocess.Popen(["ping", "-c", "1", "-n", "-W", "2", ""], stdout=limbo, stderr=limbo).wait() if result: strPingStates = strPingStates + '0,' else: strPingStates = strPingStates + '1,'

with open(os.devnull, "wb") as limbo: result=subprocess.Popen(["ping", "-c", "1", "-n", "-W", "2", ""], stdout=limbo, stderr=limbo).wait() if result: strPingStates = strPingStates + '0,' else: strPingStates = strPingStates + '1,'

ser.write(bytes(strPingStates +'\n', 'UTF-8'))

#if ( a == a ):

#download the rss file feel free to put your own rss url in here file = urllib.request.urlopen('http://www.nu.nl/feeds/rss/algemeen.rss') #convert to string data = file.read() #close the file file.close()

#parse the xml from the string dom = parseString(data)

#retrieve the first xml tag (data) that the parser finds with name tagName change tags to get different data xmlTag = dom.getElementsByTagName('title')[1].toxml() # the [2] indicates the 3rd title tag it finds will be parsed, counting starts at 0

if xmlTag != datamem:

#strip off the tag (data ---> data) xmlData=xmlTag.replace('

','') #write the marker ~ to serial ser.write(bytes("~" +'\n', 'UTF-8')) time.sleep(5) #split the string into individual words nums = xmlData.split(' ') #loop until all words in string have been printed for num in nums: #write 1 word ser.write(bytes(num, 'UTF-8'))

# write 1 space ser.write(bytes(' ', 'UTF-8'))

# THE DELAY IS NECESSARY. It prevents overflow of the arduino buffer. time.sleep(2) # write ~ to close the string and tell arduino information sending is finished ser.write(bytes("~" +'\n', 'UTF-8')) # wait 5 minutes before rechecking RSS and resending data to Arduino

datamem = xmlTag time.sleep(10) else: time.sleep(10)

#download the rss file feel free to put your own rss url in here file2 = urllib.request.urlopen('https://www.facebook.com/feeds/notifications.php?id=XXX&viewer=XXX&key=XXX&format=rss20') #convert to string data2 = file2.read() #close the file file2.close()

#parse the xml from the string dom2 = parseString(data2)

#retrieve the first xml tag (data) that the parser finds with name tagName change tags to get different data xmlTag2 = dom2.getElementsByTagName('title')[1].toxml() # the [2] indicates the 3rd title tag it finds will be parsed, counting starts at 0

if xmlTag2 != datamem2:

#strip off the tag (data ---> data) xmlData2=xmlTag2.replace('

','') #write the marker ~ to serial ser.write(b"~") time.sleep(5) #split the string into individual words nums = xmlData2.split(' ') #loop until all words in string have been printed for num in nums: #write 1 word ser.write(bytes(num, 'UTF-8'))

# write 1 space ser.write(bytes(' ', 'UTF-8'))

# THE DELAY IS NECESSARY. It prevents overflow of the arduino buffer. time.sleep(2) # write ~ to close the string and tell arduino information sending is finished ser.write(b"~") # wait 5 minutes before rechecking RSS and resending data to Arduino

datamem2 = xmlTag2 time.sleep(10) else: time.sleep(10)

Step 6: Getting It to Work

Upload the Arduino Code to the Arduino itself. Put the Python code into a .py file. If all goes according to plan, if you run the .py file, there's a small delay in response.

If it doesn't work: Check the port in the python file. Your Arduino may be labeled differently or be numbered differently. Check that the RSS feed doesn't have a ~ in the data. That will throw things out of whack. Try running the .py file from the command line as an administrator. Sometimes the script doesn't have proper permissions to access the COM ports