Announcement

Collapse
No announcement yet.

Occupancy check .py script using arp and fpring

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Occupancy check .py script using arp and fpring

    Hi guys,
    Another script I've hacked up today from a few sources.

    It's run from a linux machine (won't work on Windows) and uses arp (mac address layer 2 and fping) to look for a device and updates the devicce in homeseer via a json call. I have a separate linux server and I run it on that..but could be a rasberryPi or on a linux machine running Homeseer linux.

    You may need to install these two packages (ie. sudo apt-get install fping).

    It's command line parameter driven. So just run it with "-h" and it will show you the help info.

    For fping, you can put an ip range ie 192.168.0.0/24 to scan the whole lan segment. or you can leave out the -f switch and it will not run fping.

    It's working pretty well for me.

    Code:
    $ ./check_devices_online_arp.py -h
    usage: check_devices_online_arp.py [-h] [-s HOMESEERIP] -m DEVICEMAC -r
                                       DEVICEREF [-i INTERVAL] [-c COOLDOWNPERIOD]
                                       [-f FPINGIP] [-n FPINGINTERVAL] [-d] [-l]
    
    Checks the presence of the given device on the network by checking your router
    by ARP Table and reports back to HomeSeer
    
    optional arguments:
      -h, --help            show this help message and exit
      -s HOMESEERIP, --homeseerip HOMESEERIP
                            ip address of homeseer system
      -m DEVICEMAC, --devicemac DEVICEMAC
                            device mac address
      -r DEVICEREF, --deviceref DEVICEREF
                            Homeseer device reference number
      -i INTERVAL, --interval INTERVAL
                            Interval (seconds) to check for device
      -c COOLDOWNPERIOD, --cooldownperiod COOLDOWNPERIOD
                            Secondsto wait before deciding that a device is
                            offline. Aimed at reducing false positive with brief
                            dropouts
      -f FPINGIP, --fpingip FPINGIP
                            IP address or range to ping with fping
      -n FPINGINTERVAL, --fpinginterval FPINGINTERVAL
                            Interval (seconds) to run fping. Keep this fairly long
      -d, --debug           print debug messages
      -l, --log             log to the file _.log
    It has a debug mode so you can check what's happening.

    Code:
    $ ./check_devices_online_arp.py -m 10:41:7f:2f:25:23 -r 290 -f 192.168.0.39 -d
    26/11 23:02:56 - pid file exists
    26/11 23:02:56 - Seems to be an old file, ignoring.
    26/11 23:02:56 - script started.
    26/11 23:02:56 - http://192.168.0.11/JSON?request=getstatus&ref=290
    26/11 23:02:56 - according to HomeSeer, 10:41:7f:2f:25:23 is offline
    26/11 23:02:56 - Current State: 0
    26/11 23:02:56 - HSstatus :0
    26/11 23:02:56 - fpinginterval : 120
    26/11 23:02:56 - time diff. : 86400.034329
    26/11 23:02:56 - fping  -g 192.168.0.39 -c 1 -r 1 -t 100 -q > /dev/null 2>&1
    26/11 23:02:56 - http://192.168.0.11/JSON?request=getstatus&ref=290
    26/11 23:02:56 - 10:41:7f:2f:25:23 offline, but HomeSeer already knew
    26/11 23:02:56 - Current State:0- Sleeping now
    26/11 23:03:26 - http://192.168.0.11/JSON?request=getstatus&ref=290
    26/11 23:03:26 - according to HomeSeer, 10:41:7f:2f:25:23 is offline
    26/11 23:03:26 - Current State: 0
    26/11 23:03:26 - HSstatus :0
    26/11 23:03:26 - http://192.168.0.11/JSON?request=getstatus&ref=290
    26/11 23:03:26 - 10:41:7f:2f:25:23 offline, but HomeSeer already knew
    26/11 23:03:26 - Current State:0- Sleeping now
    26/11 23:03:57 - http://192.168.0.11/JSON?request=getstatus&ref=290
    26/11 23:03:57 - according to HomeSeer, 10:41:7f:2f:25:23 is offline
    26/11 23:03:57 - Current State: 0
    26/11 23:03:57 - HSstatus :0
    26/11 23:03:57 - http://192.168.0.11/JSON?request=getstatus&ref=290
    26/11 23:03:57 - 10:41:7f:2f:25:23 offline, but HomeSeer already knew
    26/11 23:03:57 - Current State:0- Sleeping now
    Code:
    #!/usr/bin/python
    #   Title: check_device_online_arp.py
    #   Original author: Chopper_Rob
    #   Modified for ARP by    : Siewert308SW
    #   Date: 27-02-2016
    #   Info: Checks the presence of the given device on the network by checking your router by ARP Table and reports back to HomeSeer
    #   Version : 1.0
     
    import sys
    import datetime
    import time
    import os
    import subprocess
    import urllib2
    import json
    import base64
    import socket
    import string
    import asynchat
    import asyncore
    import argparse
    
    debug = False
    
    def log(message):
      if debug == True:
         print datetime.datetime.now().strftime("%e/%m %H:%M:%S") + " - " + message
      if log_to_file == True:
        logfile = open(sys.argv[0] + '_' + sys.argv[1] + '.log', "a")
        logfile.write(message + "\n")
        logfile.close()
    
    def get_args():
        '''This function parses and return arguments passed in'''
        # Assign description to the help doc
        parser = argparse.ArgumentParser(
            description='Checks the presence of the given device on the network by checking your router by ARP Table and reports back to HomeSeer')
        # Add arguments
        parser.add_argument('-s', '--homeseerip', type=str, help='ip address of homeseer system', required=False, default="192.168.0.11")
        parser.add_argument('-m', '--devicemac', type=str, help='device mac address', required=True)
        parser.add_argument('-r', '--deviceref', type=str, help='Homeseer device reference number', required=True)
        parser.add_argument('-i', '--interval', type=str, help='Interval (seconds) to check for device', required=False, default="30")
        parser.add_argument('-c', '--cooldownperiod', type=str, help='Secondsto wait before deciding that a device is offline. Aimed at reducing false positive with brief dropouts', required=False, default="120")
        parser.add_argument('-f', '--fpingip', type=str, help='IP address or range to ping with fping', required=False, default=None)
        parser.add_argument('-n', '--fpinginterval', type=str, help='Interval (seconds) to run fping. Keep this fairly long', required=False, default="120")
        parser.add_argument('-d', '--debug', action='store_true', help='print debug messages')
        parser.add_argument('-l', '--log', action='store_true', help='log to the file _.log')
        # Array for all arguments passed to script
        args = parser.parse_args()
        # Assign args to variables
        homeseerip = args.homeseerip
        devicemac = args.devicemac
        deviceref = args.deviceref
        interval = args.interval
        cooldownperiod = args.cooldownperiod
        fpingip = args.fpingip
        fpinginterval = args.fpinginterval
        debug = args.debug
        log_to_file = args.log
    
        # Return all variable values
        return homeseerip, devicemac, deviceref, interval, cooldownperiod, fpingip, fpinginterval, debug, log_to_file
    
    # The script supports two types to check if another instance of the script is running.
    # One will use the ps command, but this does not work on all machine (Synology has problems)
    # The other option is to create a pid file named _.pid. The script will update the timestamp
    # every interval. If a new instance of the script spawns it will check the age of the pid file.
    # If the file doesn't exist or it is older then 3 * Interval it will keep running, otherwise is stops.
    # Please chose the option you want to use "ps" or "pid", if this option is kept empty it will not check and just run.
    check_for_instances = "pid"
     
    # Match return values from get_arguments()
    # and assign to their respective variables
    homeseerip, devicemac, deviceref, interval, cooldownperiod, fpingip, fpinginterval, debug, log_to_file = get_args()
    
    lastseenOn=datetime.datetime.now()
    lastfping=datetime.datetime.now() + datetime.timedelta(days=-1)
    HSstatus=-1
    HomeSeerurl = 'http://' + homeseerip + '/JSON?request=getstatus&ref='+deviceref
    
    if check_for_instances.lower() == "pid":
      pidfile = sys.argv[0] + '_' + devicemac + '.pid'
      if os.path.isfile( pidfile ):
        log("pid file exists")
        if (time.time() - os.path.getmtime(pidfile)) < (float(interval) * 3):
          log("Script seems to be still running, exiting")
          log("If this is not correct, please delete file " + pidfile)
          sys.exit(0)
        else:
          log("Seems to be an old file, ignoring.")
      else:
        open(pidfile, 'w').close()
     
    if check_for_instances.lower() == "ps":
      if int(subprocess.check_output('ps x | grep \'' + sys.argv[0] + ' ' + sys.argv[1] + '\' | grep -cv grep', shell=True)) > 2 :
        log("Script already running. exiting.")
        sys.exit(0)
    
    def HomeSeerstatus ():
      json_object = json.loads(HomeSeerrequest(HomeSeerurl))
      status = 0
      if json_object['Devices'][0]['status'] == "On":
         status = 1
      if json_object['Devices'][0]['status'] == "Off":
         status = 0
      return status
     
    def HomeSeerrequest (url):
      request = urllib2.Request(url)
      log(url)
      response = urllib2.urlopen(request)
      return response.read()
     
    log ("script started.")
     
    
    while 1==1:
      HSstatus = HomeSeerstatus()
      if HSstatus == 1 :
        log ("according to HomeSeer, " + devicemac + " is online")
      if HSstatus == 0 :
        log ("according to HomeSeer, " + devicemac + " is offline")
     
      currentstate = (subprocess.call('sudo arp -n | grep -o "' + devicemac + '" > /dev/null', shell=True)-1)*-1
    
      log ("Current State: " + str(currentstate))
      log ("HSstatus :" + str(HSstatus))
    
      if fpingip != None and (datetime.datetime.now()-lastfping).total_seconds() > float(fpinginterval) :
         log ("fpinginterval : " +  str(fpinginterval) )
         log ("time diff. : " +  str((datetime.datetime.now()-lastfping).total_seconds()) )
         log ('fping  -g ' + fpingip + ' -c 1 -r 1 -t 100 -q > /dev/null 2>&1' )
         subprocess.call('fping  -g ' + fpingip + ' -c 1 -r 1 -t 100 -q > /dev/null 2>&1',shell=True)
         lastfping=datetime.datetime.now()  
    
      if currentstate == 1 : lastseenOn=datetime.datetime.now()
    
      if currentstate == 0 and HSstatus == 1 and (datetime.datetime.now()-lastseenOn).total_seconds() < float(cooldownperiod) :
        log (datetime.datetime.now().strftime("%H:%M:%S") + "- " + devicemac + " offline, waiting for it to come back")
      else:
         if currentstate == 0:
            if HomeSeerstatus() == 1 :
               log (devicemac + " offline, tell HomeSeer it's gone")
               HomeSeerrequest("http://" + homeseerip + "/JSON?request=controldevicebylabel&ref=" + deviceref + "&label=off")
            else:
               log (devicemac + " offline, but HomeSeer already knew")
         else:
            if HomeSeerstatus() == 0 :
               log (devicemac + " online, tell HomeSeer it's back")
               HomeSeerrequest("http://" + homeseerip + "/JSON?request=controldevicebylabel&ref=" + deviceref + "&label=on")
            else:
               log (devicemac + " online, but HomeSeer already knew")
    
    
      log ("Current State:" + str(currentstate) + "- Sleeping now")
      time.sleep (float(interval))
     
      if check_for_instances.lower() == "pid": open(pidfile, 'w').close()

  • #2
    Cool :-).

    Comment


    • #3
      Pleasure.

      I'll also be adding the ability to enter multiple devices as well as l2ping to ping bluetooth devices - which aparently is more reliable for iPhones that go to sleep

      Just awaiting my bluetooth dongle from evilbay and then hacking it to add a 30cm aerial to extend the range.

      Feel free to hack and reissue as you see fit.

      Comment


      • #4
        any update for this?

        Comment

        Working...
        X