Mercurial > code > home > repos > homeauto
comparison service/tomatoWifi/wifi.py @ 62:f8cc3d1baa85
redo wifi scraper to work with zyxel router report page too. add last connected time (from mongo) to web table
Ignore-this: 18bade72e14d40532bd019791d03fa7d
author | drewp@bigasterisk.com |
---|---|
date | Sat, 06 Apr 2013 17:08:19 -0700 |
parents | 875a37be1228 |
children | c81a451f9b26 |
comparison
equal
deleted
inserted
replaced
61:1afb0564636d | 62:f8cc3d1baa85 |
---|---|
1 import re, ast, logging, socket | 1 import re, ast, logging, socket |
2 import lxml.html.soupparser | |
2 from twisted.internet.defer import inlineCallbacks, returnValue | 3 from twisted.internet.defer import inlineCallbacks, returnValue |
3 from cyclone.httpclient import fetch | 4 from cyclone.httpclient import fetch |
4 from rdflib import Literal, Graph | 5 from rdflib import Literal, Graph |
5 | 6 |
6 log = logging.getLogger() | 7 log = logging.getLogger() |
10 return repr(self.__dict__) | 11 return repr(self.__dict__) |
11 | 12 |
12 class Wifi(object): | 13 class Wifi(object): |
13 """ | 14 """ |
14 gather the users of wifi from the tomato routers | 15 gather the users of wifi from the tomato routers |
16 | |
17 with host names from /var/lib/dhcp/dhcpd.leases | |
15 """ | 18 """ |
16 def __init__(self, tomatoConfig="/my/site/magma/tomato_config.js", | 19 def __init__(self, tomatoConfig="/my/site/magma/tomato_config.js", |
17 accessN3="/my/proj/openid_proxy/access.n3"): | 20 accessN3="/my/proj/openid_proxy/access.n3"): |
18 | 21 |
19 # ideally this would all be in the same rdf store, with int and | 22 # ideally this would all be in the same rdf store, with int and |
46 r = Router() | 49 r = Router() |
47 http, tail = url.split('//', 1) | 50 http, tail = url.split('//', 1) |
48 userPass, tail = tail.split("@", 1) | 51 userPass, tail = tail.split("@", 1) |
49 r.url = http + '//' + tail | 52 r.url = http + '//' + tail |
50 r.headers = {'Authorization': ['Basic %s' % userPass.encode('base64').strip()]} | 53 r.headers = {'Authorization': ['Basic %s' % userPass.encode('base64').strip()]} |
51 r.name = {'tomato1' : 'bigasterisk3', | 54 r.name = {'tomato1' : 'bigasterisk5', |
52 'tomato2' : 'bigasterisk4'}[name.split('/')[1]] | 55 'tomato2' : 'bigasterisk4'}[name.split('/')[1]] |
53 self.routers.append(r) | 56 self.routers.append(r) |
54 | 57 |
55 @inlineCallbacks | 58 @inlineCallbacks |
56 def getPresentMacAddrs(self): | 59 def getPresentMacAddrs(self): |
57 aboutIp = {} | 60 rows = [] |
58 byMac = {} # mac : [ip] | 61 |
59 | |
60 for router in self.routers: | 62 for router in self.routers: |
61 log.debug("GET %s", router) | 63 log.debug("GET %s", router) |
62 try: | 64 try: |
63 resp = yield fetch(router.url, headers=router.headers, | 65 resp = yield fetch(router.url, headers=router.headers, |
64 timeout=2) | 66 timeout=2) |
65 except socket.error: | 67 except socket.error: |
66 log.warn("get on %s failed" % router) | 68 log.warn("get on %s failed" % router) |
67 continue | 69 continue |
68 data = resp.body | 70 data = resp.body |
71 if 'Wireless -- Authenticated Stations' in data: | |
72 # zyxel 'Station Info' page | |
73 rows.extend(self.parseZyxel(data, router.name)) | |
74 else: | |
75 # tomato page | |
76 rows.extend(self.parseTomato(data, router.name)) | |
69 | 77 |
70 for (ip, mac, iface) in jsValue(data, 'arplist'): | 78 for r in rows: |
71 aboutIp.setdefault(ip, {}).update(dict( | 79 try: |
72 ip=ip, | 80 r['name'] = self.knownMacAddr[r['mac']] |
73 router=router.name, | 81 except KeyError: |
74 mac=mac, | 82 pass |
75 iface=iface, | 83 |
76 )) | 84 returnValue(rows) |
85 | |
86 def parseZyxel(self, data, routerName): | |
87 root = lxml.html.soupparser.fromstring(data) | |
88 for tr in root.cssselect('tr'): | |
89 mac, assoc, uth, ssid, iface = [td.text_content().strip() for td in tr.getchildren()] | |
90 if mac == "MAC": | |
91 continue | |
92 assoc = assoc.lower() == 'yes' | |
93 yield dict(router=routerName, mac=mac, assoc=assoc, connected=assoc) | |
77 | 94 |
78 byMac.setdefault(mac, set()).add(ip) | 95 def parseTomato(self, data, routerName): |
79 | 96 for iface, mac, signal in jsValue(data, 'wldev'): |
80 for (name, ip, mac, lease) in jsValue(data, 'dhcpd_lease'): | 97 yield dict(router=routerName, mac=mac, signal=signal, connected=bool(signal)) |
81 if lease.startswith('0 days, '): | 98 |
82 lease = lease[len('0 days, '):] | 99 |
83 aboutIp.setdefault(ip, {}).update(dict( | |
84 router=router.name, | |
85 rawName=name, | |
86 mac=mac, | |
87 lease=lease | |
88 )) | |
89 | |
90 byMac.setdefault(mac, set()).add(ip) | |
91 | |
92 for iface, mac, signal in jsValue(data, 'wldev'): | |
93 matched = False | |
94 for addr in aboutIp.values(): | |
95 if (addr['router'], addr['mac']) == (router.name, mac): | |
96 addr.update(dict(signal=signal, iface=iface)) | |
97 matched = True | |
98 if not matched: | |
99 aboutIp["mac-%s-%s" % (router, mac)] = dict( | |
100 router=router.name, | |
101 mac=mac, | |
102 signal=signal, | |
103 ) | |
104 | |
105 ret = [] | |
106 for addr in aboutIp.values(): | |
107 if addr.get('ip') in ['192.168.1.1', '192.168.1.2', '192.168.0.2']: | |
108 continue | |
109 try: | |
110 addr['name'] = self.knownMacAddr[addr['mac']] | |
111 except KeyError: | |
112 addr['name'] = addr.get('rawName') | |
113 if addr['name'] in [None, '*']: | |
114 addr['name'] = 'unknown' | |
115 ret.append(addr) | |
116 | |
117 returnValue(ret) | |
118 | |
119 | |
120 def jsValue(js, variableName): | 100 def jsValue(js, variableName): |
121 # using literal_eval instead of json parser to handle the trailing commas | 101 # using literal_eval instead of json parser to handle the trailing commas |
122 val = re.search(variableName + r'\s*=\s*(.*?);', js, re.DOTALL).group(1) | 102 val = re.search(variableName + r'\s*=\s*(.*?);', js, re.DOTALL).group(1) |
123 return ast.literal_eval(val) | 103 return ast.literal_eval(val) |