Mercurial > code > home > repos > homeauto
changeset 1729:41394bc1d1b0
scrape satellites too, since they reveal what devs are connected to them
author | drewp@bigasterisk.com |
---|---|
date | Fri, 30 Jun 2023 22:04:36 -0700 |
parents | 81aa0873b48d |
children | 5d7ce02fa8b2 |
files | service/wifi/scrape.py |
diffstat | 1 files changed, 64 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- a/service/wifi/scrape.py Fri Jun 30 22:03:55 2023 -0700 +++ b/service/wifi/scrape.py Fri Jun 30 22:04:36 2023 -0700 @@ -3,10 +3,10 @@ import logging import re import time -from typing import Awaitable, Callable, Iterable, List +from typing import Awaitable, Callable, Iterable, List, cast -from cyclone.httpclient import fetch -from rdflib import Graph, Literal, Namespace, RDF, RDFS, URIRef +import aiohttp +from rdflib import RDF, RDFS, Graph, Literal, Namespace, URIRef log = logging.getLogger() ROOM = Namespace("http://projects.bigasterisk.com/room/") @@ -46,22 +46,66 @@ raise NotImplementedError(cls) -async def loadOrbiData(config: Graph) -> List[SeenNode]: - user = config.value(ROOM['wifiScraper'], ROOM['user']) - passwd = config.value(ROOM['wifiScraper'], ROOM['password']) +async def fetch(url, user, passwd) -> str: basicAuth = '%s:%s' % (user, passwd) headers = { - b'Authorization': [b'Basic %s' % base64.encodebytes(basicAuth.encode('utf8')).strip()], + 'Authorization': 'Basic %s' % base64.encodebytes(basicAuth.encode('ascii')).strip().decode('ascii'), } - uri = config.value(ROOM['wifiScraper'], ROOM['deviceInfoPage']) - resp = await fetch(f"{uri}?ts={time.time()}".encode('utf8'), method=b'GET', headers=headers) + async with aiohttp.ClientSession() as session: + async with session.get(url, headers=headers) as response: + if response.status != 200: + raise ValueError(f'{response.status=}') + + return await response.text() + + +async def loadConnectedMacsFromSatellites(satIp, user, passwd): + body = await fetch(f'http://{satIp}/refresh_dev.aspx', user, passwd) + j = json.loads(body) + out = [] + for row in j['device']: + out.append({'mac': row['mac'], 'type': row['type']}) + return out + + +def findSatellites(satMacs, jrows): + satIps = [] + for row in jrows: + mac = row['mac'].lower() + for label, satMac in satMacs: + if mac == satMac: + satIps.append((label, row['ip'])) + return satIps + - if not resp.body.startswith((b'device=', b'device_changed=0\ndevice=', b'device_changed=1\ndevice=')): - raise ValueError(resp.body) +async def loadOrbiData(config: Graph) -> List[SeenNode]: + + def confStr(s, p) -> str: + return cast(Literal, config.value(s, p)).toPython() + + user = confStr(ROOM['wifiScraper'], ROOM['user']) + passwd = confStr(ROOM['wifiScraper'], ROOM['password']) + uri = confStr(ROOM['wifiScraper'], ROOM['deviceInfoPage']) + satelliteNamesAndMacs = [ + (confStr(s, RDFS.label), confStr(s, ROOM['mac'])) # + for s in config.objects(ROOM['wifiScraper'], ROOM['satellite']) + ] + body = await fetch(f"{uri}?ts={time.time()}", user, passwd) - - rows = [] - for rowNum, row in enumerate(json.loads(resp.body.split(b'device=', 1)[-1])): + if not body.startswith(('device=', 'device_changed=0\ndevice=', 'device_changed=1\ndevice=')): + raise ValueError(body) + + outNodes = [] + + orbiReportRows = json.loads(body.split('device=', 1)[-1]) + satelliteNamesAndIps = findSatellites(satelliteNamesAndMacs, orbiReportRows) + + satNameForMac = {} + for sat, satIp in satelliteNamesAndIps: + for row in await loadConnectedMacsFromSatellites(satIp, user, passwd): + satNameForMac[row['mac'].lower()] = ROOM[sat] + + for rowNum, row in enumerate(orbiReportRows): log.debug('response row [%d] %r', rowNum, row) if not re.match(r'\w\w:\w\w:\w\w:\w\w:\w\w:\w\w', row['mac']): raise ValueError(f"corrupt response: mac was {row['mac']!r}") @@ -71,7 +115,7 @@ if row['contype'] in ['2.4G', '5G']: orbi = macUri(row['conn_orbi_mac']) ct = ROOM['wifiBand/%s' % row['contype']] - triples.add((uri, ROOM['connectedToAp'], orbi)) + # triples.add((uri, ROOM['connectedToAp'], orbi)) # always reports the RBR50, i think triples.add((uri, ROOM['wifiBand'], ct)) triples.add((orbi, RDF.type, ROOM['AccessPoint'])) triples.add((orbi, ROOM['wifiBand'], ct)) @@ -85,10 +129,12 @@ pass else: pass - triples.add((uri, ROOM['connectedToNet'], ROOM['HouseOpenNet'])) + triples.add((uri, ROOM['connectedToNet'], ROOM['HouseNet'])) + if sat := satNameForMac.get(row['mac'].lower()): + triples.add((uri, ROOM['connectedToAp'], sat)) if row['model'] != 'Unknown': triples.add((uri, ROOM['networkModel'], Literal(row['model']))) - rows.append(SeenNode(uri=uri, mac=row['mac'].lower(), ip=row['ip'], stmts=triples)) - return rows + outNodes.append(SeenNode(uri=uri, mac=row['mac'].lower(), ip=row['ip'], stmts=triples)) + return outNodes