diff service/tomatoWifi/wifi.py @ 980:2f1cb8b5950a

rewrites for better graph export, removal of dhcp reader Ignore-this: ecc5280b15d66020412f82ad84862074 darcs-hash:20150504002120-312f9-85bcb342f5bdae78d7b6d9083929944d4a467001
author drewp <drewp@bigasterisk.com>
date Sun, 03 May 2015 17:21:20 -0700
parents d9bc9a82dcca
children 7faf642438bc
line wrap: on
line diff
--- a/service/tomatoWifi/wifi.py	Sat May 02 18:52:15 2015 -0700
+++ b/service/tomatoWifi/wifi.py	Sun May 03 17:21:20 2015 -0700
@@ -1,8 +1,8 @@
-import re, ast, logging, socket
+import re, ast, logging, socket, json
 import lxml.html.soupparser
 from twisted.internet.defer import inlineCallbacks, returnValue
 from cyclone.httpclient import fetch
-from rdflib import Literal, Graph
+from rdflib import Literal, Graph, RDFS, URIRef
 
 log = logging.getLogger()
 
@@ -13,32 +13,31 @@
 class Wifi(object):
     """
     gather the users of wifi from the tomato routers
-
-    with host names from /var/lib/dhcp/dhcpd.leases
     """
-    def __init__(self, tomatoConfig="/my/site/magma/tomato_config.js",
-                 accessN3="/my/proj/openid_proxy/access.n3"):
+    def __init__(self, accessN3="/my/proj/openid_proxy/access.n3"):
+        self.graph = Graph()
+        self.graph.parse('config.n3', format='n3')
 
-        # ideally this would all be in the same rdf store, with int and
-        # ext versions of urls
-
-        txt = open(tomatoConfig).read().replace('\n', '')
-        self.knownMacAddr = jsValue(txt, 'knownMacAddr')
-        tomatoUrl = jsValue(txt, 'tomatoUrl')
-
+        #self._loadRouters(accessN3, tomatoUrl)
+        
+    def _loadRouters(self, accessN3, tomatoUrl):
         g = Graph()
         g.parse(accessN3, format="n3")
-        repl = {'/tomato1/' : None, '/tomato2/' : None}
+        repl = {
+            '/wifiRouter1/' : None,
+            #'/tomato2/' : None
+        }
         for k in repl:
             rows = list(g.query('''
             PREFIX p: <http://bigasterisk.com/openid_proxy#>
             SELECT ?prefix WHERE {
-              [
+              ?site
                 p:requestPrefix ?public;
                 p:proxyUrlPrefix ?prefix
-                ]
+                .
             }''', initBindings={"public" : Literal(k)}))
             repl[k] = str(rows[0][0])
+        log.debug('repl %r', repl)
 
         self.routers = []
         for url in tomatoUrl:
@@ -51,12 +50,24 @@
 	    userPass, tail = tail.split("@", 1)
             r.url = http + '//' + tail
             r.headers = {'Authorization': ['Basic %s' % userPass.encode('base64').strip()]}
-            r.name = {'tomato1' : 'bigasterisk5',
+            r.name = {'wifiRouter1' : 'bigasterisk5',
                       'tomato2' : 'bigasterisk4'}[name.split('/')[1]]
             self.routers.append(r)
 
     @inlineCallbacks
     def getPresentMacAddrs(self):
+        rows = yield loadUvaData()
+        for row in rows:
+            if 'clientHostname' in row:
+                row['name'] = row['clientHostname']
+            mac = URIRef('http://bigasterisk.com/mac/%s' % row['mac'].lower())
+            label = self.graph.value(mac, RDFS.label)
+            if label:
+                row['name'] = label
+        returnValue(rows)
+            
+    @inlineCallbacks
+    def getPresentMacAddrs_multirouter(self):
         rows = []
         
         for router in self.routers:
@@ -70,10 +81,10 @@
             data = resp.body
             if 'Wireless -- Authenticated Stations' in data:
                 # zyxel 'Station Info' page
-                rows.extend(self.parseZyxel(data, router.name))
+                rows.extend(self._parseZyxel(data, router.name))
             else:
                 # tomato page
-                rows.extend(self.parseTomato(data, router.name))
+                rows.extend(self._parseTomato(data, router.name))
 
         for r in rows:
             try:
@@ -83,7 +94,7 @@
                 
         returnValue(rows)
         
-    def parseZyxel(self, data, routerName):
+    def _parseZyxel(self, data, routerName):
         root = lxml.html.soupparser.fromstring(data)
         for tr in root.cssselect('tr'):
             mac, assoc, uth, ssid, iface = [td.text_content().strip() for td in tr.getchildren()]
@@ -92,10 +103,35 @@
             assoc = assoc.lower() == 'yes'
             yield dict(router=routerName, mac=mac, assoc=assoc, connected=assoc)
 
-    def parseTomato(self, data, routerName):
+    def _parseTomato(self, data, routerName):
         for iface, mac, signal in jsValue(data, 'wldev'):
             yield dict(router=routerName, mac=mac, signal=signal, connected=bool(signal))
+
+
+@inlineCallbacks
+def loadUvaData():
+    config = json.load(open("/my/proj/homeauto/service/tomatoWifi/priv-uva.json"))
+    headers = {'Authorization': ['Basic %s' % config['userPass'].encode('base64').strip()]}
+    resp = yield fetch('http://10.2.0.2/wlstationlist.cmd', headers=headers)
+    root = lxml.html.soupparser.fromstring(resp.body)
+    byMac = {}
+    for tr in root.cssselect('tr'):
+        mac, connected, auth, ssid, iface = [td.text_content().strip() for td in tr.getchildren()]
+        if mac == "MAC":
+            continue
+        connected = connected.lower() == 'yes'
+        byMac[mac] = dict(mac=mac, connected=connected, auth=auth == 'Yes', ssid=ssid, iface=iface)
         
+    resp = yield fetch('http://10.2.0.2/DHCPTable.asp', headers=headers)
+    for row in re.findall(r'new AAA\((.*)\)', resp.body):
+        clientHostname, ipaddr, mac, expires, iface = [s.strip("'") for s in row.rsplit(',', 4)]
+        if clientHostname == 'wlanadv.none':
+            continue
+        byMac.setdefault(mac, {}).update(dict(
+            clientHostname=clientHostname, connection=iface, ipaddr=ipaddr, dhcpExpires=expires))
+    
+    returnValue(sorted(byMac.values()))
+    
             
 def jsValue(js, variableName):
     # using literal_eval instead of json parser to handle the trailing commas