├── dictionary.csv ├── README.md └── presence_detector.py /dictionary.csv: -------------------------------------------------------------------------------- 1 | Jeniffer,e8:99:c4:81:cd:8c 2 | Caty,60:d9:c7:16:81:63 3 | John,cc:3a:61:62:6e:54 4 | Louis,28:9a:fa:50:8f:02 5 | Daniel,f0:27:65:36:3e:9a 6 | Erika,e4:ce:8f:c6:8b:74 7 | Chris,8c:3a:e3:4f:e3:b0 8 | William,cc:3a:61:cc:e5:40 9 | Edwin,f0:25:b7:0d:fb:77 10 | Stephany,bc:e5:9f:58:b1:90 11 | Ipad2,88:cb:87:a6:f2:df 12 | Pablo,cc:c3:ea:7a:04:6e 13 | Kate,8c:c5:e1:aa:ec:27 14 | Javier,cc:3a:61:a1:9b:13 15 | Stuart,30:17:c8:3e:40:1a 16 | Diego,f4:09:d8:5f:70:d9 17 | Juan,44:d8:84:50:e3:22 18 | George,54:26:96:b3:9d:8f 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wifi-presence-detector 2 | A Python script that sniffs ARP packets in the local network to detect presence of WiFi users, then updates the presence status in Ubidots. 3 | 4 | You may run this script from a Linux box in the same network as your WiFi, such as a Raspberry Pi or an existing Linux server inside your office. These instructions are for a Raspberry Pi using Wheezy: 5 | 6 | 1. Setup your Pi 7 | ================ 8 | 9 | Make sure to start with a fresh and working Raspberry Pi with Internet access. You can find a setup guide here: http://ubidots.com/docs/devices/raspberrypi.html#setup-your-raspberry-pi 10 | 11 | We strongly recommend using Wicd to manage the wifi connection. 12 | 13 | 2. Install the required libraries 14 | ================================= 15 | 16 | sudo apt-get install python-setuptools 17 | 18 | sudo easy_install pip 19 | 20 | sudo pip install scapy 21 | 22 | sudo pip install ubidots 23 | 24 | 3. Code the program! 25 | ==================== 26 | 27 | pi@raspberrypi ~ $ mkdir presence_detector 28 | 29 | pi@raspberrypi ~ $ cd presence_detector/ 30 | 31 | pi@raspberrypi ~/access_control $ nano presence_detector.py 32 | 33 | Paste the code into the file. 34 | 35 | 4. Create a dictionary with your user names 36 | =========================================== 37 | 38 | This script reads the entries in the file "dictionary.csv" which should be placed in the same directory as the .py script. This file relates people's names to MAC addresses of their devices. Refer to the above sample file to get familiar with its structure, which is: 39 | 40 | User Name, 41 | 42 | 5. Create an account in Ubidots 43 | ================================ 44 | 45 | Go to http://app.ubidots.com/accounts/signup/ and create an account. Then go to your profile inside Ubidots and copy your API Key. 46 | 47 | Put this API Key into the code (line ~73). 48 | 49 | 6. Done! 50 | ======== 51 | 52 | The script will automatically create a Datasource with the value of the variable "office" in the Python script. Then it will create a variable for each new device that is detected in the network AND that is also listed in "dictionary.csv". 53 | 54 | Once you see this data, go to your Ubidots dashboard and create "Indicator" widgets to see if a person is inside or outside the office! 55 | -------------------------------------------------------------------------------- /presence_detector.py: -------------------------------------------------------------------------------- 1 | from multiprocessing import Process, Manager 2 | from scapy.all import * 3 | import ubidots 4 | import csv 5 | import time 6 | 7 | # Declare variables 8 | 9 | users = {} 10 | office = "Boston" 11 | MAX_RETRIES = 25 12 | SUB_NET = "192.168.0.0/24" 13 | 14 | # Functions 15 | 16 | def check_incoming_users(users_ip): 17 | while(True): 18 | sniff(prn = arp_count, filter = "arp", count = 10) 19 | 20 | 21 | def check_outgoing_users(users_ip): 22 | conf.verb = 0 23 | timeout_counters = {} 24 | while(True): 25 | # Issue ARP Ping to all network 26 | ans,unans=srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=SUB_NET),timeout=2) 27 | for user,ip in users_ip.items(): 28 | for snd,rcv in ans: 29 | if ip == rcv.sprintf("%ARP.psrc%"): 30 | print "ARP ping reply from " + user 31 | timeout_counters[user] = 0 32 | try: 33 | var = get_var_by_name(user, ds) 34 | var.save_value({"value": 1,"context":{"type":"ARP Ping"}}) 35 | break 36 | except: 37 | break 38 | else: 39 | print user + " not replying to ARP ping." 40 | timeout_counters[user] = timeout_counters.get(user, 0) + 1 41 | if timeout_counters[user] > MAX_RETRIES: 42 | print "Reporting user as gone..." 43 | timeout_counters[user] = 0 44 | try: 45 | var = get_var_by_name(user, ds) 46 | var.save_value({"value": 0}) 47 | except: 48 | continue 49 | 50 | def arp_count(pkt): 51 | 52 | try: 53 | if pkt[ARP].hwsrc in users: 54 | device = users[pkt[ARP].hwsrc] 55 | users_ip[device] = pkt[ARP].psrc 56 | print "ARP request received from " + device 57 | var = get_var_by_name(device, ds) 58 | var.save_value({"value": 1,"context":{"type":"ARP Request"}}) 59 | return 60 | else: 61 | #print "Scapy running - HW address not found" 62 | return 63 | except: 64 | return 65 | 66 | def get_var_by_name(var_name, ds): 67 | 68 | # Search for a variable in a datasource. If found, returns the variable. If not found, returns None 69 | try: 70 | for var in ds.get_variables(): 71 | 72 | if var.name == var_name: 73 | return var 74 | 75 | var = ds.create_variable({"name": var_name, "unit": "."}) 76 | return var 77 | except: 78 | print "Couldn't get variables from DS" 79 | return 80 | 81 | if __name__ == '__main__': 82 | 83 | # Create Ubidots connection 84 | 85 | api = ubidots.ApiClient("YOUR-UBIDOTS-API-KEY") 86 | 87 | # Search for a data source with name matching this. If it doesn't exist, create it. 88 | 89 | ds = None 90 | 91 | try: 92 | for cur_ds in api.get_datasources(): 93 | if cur_ds.name == office: 94 | ds = cur_ds 95 | break 96 | 97 | if ds is None: 98 | ds = api.create_datasource({"name": office}) 99 | print "Connected to Ubidots, will send data to Ubidots data source called: " + ds.name 100 | 101 | except: 102 | print "Ds not found nor created" 103 | 104 | # Load dictionary from CSV file 105 | 106 | with open('/root/dictionary.csv','rb') as f: 107 | reader = csv.reader(f) 108 | for row in reader: 109 | users[row[1]] = row[0] 110 | var = get_var_by_name(row[0], ds) 111 | var.save_value({"value": 0}) 112 | 113 | print "List of users loaded." 114 | 115 | # Launch Processes 116 | manager = Manager() 117 | users_ip = manager.dict() 118 | 119 | p = Process(target=check_incoming_users, args=(users_ip,)) 120 | p.start() 121 | 122 | check_outgoing_users(users_ip) 123 | --------------------------------------------------------------------------------