Mercurial > code > home > repos > homeauto
changeset 675:9ae34280218b
kind of running with lit-element and polymer together. lots of data missing from table still
Ignore-this: db24e7b633929b01430b0794c1a065dc
author | drewp@bigasterisk.com |
---|---|
date | Sun, 05 Jan 2020 23:18:27 -0800 |
parents | 2b9865bf1737 |
children | 4bd77a9548d6 |
files | service/wifi/index.html service/wifi/package-lock.json service/wifi/package.json service/wifi/src/index.ts service/wifi/src/style.ts service/wifi/src/wifi-table.ts service/wifi/tsconfig.json |
diffstat | 7 files changed, 479 insertions(+), 116 deletions(-) [+] |
line wrap: on
line diff
--- a/service/wifi/index.html Thu Jan 02 00:23:36 2020 -0800 +++ b/service/wifi/index.html Sun Jan 05 23:18:27 2020 -0800 @@ -9,7 +9,6 @@ </head> <link rel="stylesheet" href="/rdf/streamed-graph.css" /> <body class="rdfBrowsePage"> - <hr /> <dom-bind> <template> <style> @@ -25,10 +24,8 @@ n="network" static="['demo.n3']" graph="{{graph}}" - expanded="{{e}}" ></streamed-graph> - g={{graph.version}} e={{e}} - <wifi-display graph="{{graph}}" show-groups="true"></wifi-display> + <wifi-display graph="[[g2]]" show-groups="true"></wifi-display> </template> </dom-bind> <form method="POST" action="remoteSuspend">
--- a/service/wifi/package-lock.json Thu Jan 02 00:23:36 2020 -0800 +++ b/service/wifi/package-lock.json Sun Jan 05 23:18:27 2020 -0800 @@ -5863,6 +5863,14 @@ "type-check": "~0.3.2" } }, + "lit-element": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-2.2.1.tgz", + "integrity": "sha512-ipDcgQ1EpW6Va2Z6dWm79jYdimVepO5GL0eYkZrFvdr0OD/1N260Q9DH+K5HXHFrRoC7dOg+ZpED2XE0TgGdXw==", + "requires": { + "lit-html": "^1.0.0" + } + }, "lit-html": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-1.1.2.tgz",
--- a/service/wifi/package.json Thu Jan 02 00:23:36 2020 -0800 +++ b/service/wifi/package.json Sun Jan 05 23:18:27 2020 -0800 @@ -16,6 +16,7 @@ "@polymer/decorators": "^3.0.0", "@polymer/polymer": "^3.3.1", "@types/n3": "^1.1.1", + "lit-element": "^2.2.1", "lit-html": "^1.1.2", "n3": "^1.3.5", "streamed-graph": "file:/my/proj/streamed-graph"
--- a/service/wifi/src/index.ts Thu Jan 02 00:23:36 2020 -0800 +++ b/service/wifi/src/index.ts Sun Jan 05 23:18:27 2020 -0800 @@ -1,37 +1,281 @@ -import { PolymerElement, html } from "@polymer/polymer"; -import { - customElement, - property, - computed, - observe, -} from "@polymer/decorators"; -import { N3Store } from "n3"; -//import {* as wt} from './wifi-table'; -import { VersionedGraph, StreamedGraph } from "streamed-graph"; +// for the web page export { DomBind } from "@polymer/polymer/lib/elements/dom-bind.js"; -console.log("here is a real dependency on ", StreamedGraph.name); +import { LitElement, property, html, customElement } from "lit-element"; + +import { Literal, Term, N3Store, Util } from "n3"; +import { NamedNode, DataFactory } from "n3"; +const { literal, quad, namedNode } = DataFactory; + +import { VersionedGraph } from "streamed-graph"; +export { StreamedGraph } from "streamed-graph"; +import { style } from "./style"; + +interface DevGroup { + connectedToAp: NamedNode; + wifiBand: NamedNode; + devs: Array<Dev>; +} +interface Dev { + agoMin: number | undefined; + ipAddress: Literal; + dhcpHostname: string; + macAddress: Literal; + packetsPerSec: string; //number; todo + bytesPerSec: string; //number; +} + +// workaround for uris that don't have good labels in the graph +function labelFromUri( + uri: NamedNode, + prefix: string, + tailsToLabels: any, + defaultLabel: string +) { + let label = defaultLabel === undefined ? uri.value : defaultLabel; + Object.entries(tailsToLabels).forEach(([tail, useLabel]) => { + if (uri.equals(namedNode(prefix + tail))) { + label = useLabel as string; + } + }); + return label; +} @customElement("wifi-display") -class WifiDisplay extends PolymerElement { - @property({ type: Object, observer: WifiDisplay.prototype.onGraphChanged}) +class WifiDisplay extends LitElement { + static get styles() { + return [style]; + } + + @property({ + type: Object, + // observer: WifiDisplay.prototype.onGraphChanged, + }) graph!: VersionedGraph; + connectedCallback() { + super.connectedCallback(); + console.log("wifidisplay connected"); + const sg = this.ownerDocument!.querySelector("streamed-graph"); + sg?.addEventListener("graph-changed", ((ev: CustomEvent) => { + this.graph = ev.detail!.value as VersionedGraph; + console.log("wifidisplay got new graph", this.graph); + }) as EventListener); + } - onGraphChanged() { - console.log("new graph", this.graph); + static get observers() { + return ["onGraphChanged(graph)"]; + } + + @property({ type: Object }) //no longer a prop? + grouped: Map<string, DevGroup> = new Map(); + + render() { + const grouped = this.graphView(this.graph.store!, false); + + return html` + <div class="report"> + report at graph version ${this.graph.version} grouped: + ${Array.from(grouped.entries()).length} + <table> + ${Array.from(grouped.entries()).map((row: [string, DevGroup]) => { + return this.renderGroup(row[0], row[1]); + })} + </table> + </div> + `; } - ready() { - super.ready(); + onGraphChanged(val: VersionedGraph, old: VersionedGraph) { + console.log("new graph value", this.graph); + this.grouped = this.graphView((val as VersionedGraph).store!, false); + } + + renderDevice(dev: Dev) { + let agoReport = ""; + if (dev.agoMin === undefined) { + agoReport = "unknown"; + } else { + const glow = Math.max(0, 1 - dev.agoMin! / 60); + agoReport = + dev.agoMin! < 360 + ? ` (${Math.ceil(dev.agoMin! * 10) / 10} minutes ago)` + : ""; + } + const glow = ""; //todo + return html` + <div class="dev" style="background: rgba(185, 5, 138, ${glow});"> + <span class="mac">${dev.macAddress && dev.macAddress.value}</span> + <span class="ip" + ><a href="http://${dev.ipAddress && dev.ipAddress.value}/" + >${dev.ipAddress && dev.ipAddress.value}</a + ></span + > + <span class="packets">${dev.packetsPerSec}</span> + <span class="bytes">${dev.bytesPerSec}</span> + <span class="hostname">${dev.dhcpHostname}</span> + <span class="ago">${agoReport}</span> + <span class="links"> + <a + href="https://bigasterisk.com/ntop/lua/host_details.lua?ifid=17&host=${dev.ipAddress && + dev.ipAddress.value}&page=flows" + >[flows]</a + > + </span> + </div> + `; } - // redraw() { - // wt.render(this.graph.graph); - // } - static get template() { + renderGroup(key: string, group: DevGroup) { + let label; + if (key != "all") { + label = labelFromUri( + group.connectedToAp, + "http://bigasterisk.com/mac/", + { + "a0:40:a0:6f:96:d5": "Main router (d5)", + "8c:3b:ad:c4:8d:ce": "Downstairs satellite (ce)", + "a0:40:a0:6f:aa:f8": "Upstairs satellite (f8)", + }, + "unknown" + ); + + label += labelFromUri( + group.wifiBand, + "http://projects.bigasterisk.com/room/wifiBand/", + { + "5G": " 5G", + "2.4G": " 2.4G", + }, + "unknown" + ); + } + + const devs = group.devs; + function padIp(ip: string) { + return ip.replace(/(\d+)/g, m => ("00" + m).slice(-3)); + } + devs.sort((a, b) => { + return 0; //todo + return padIp(a.ipAddress.value) > padIp(b.ipAddress.value) ? 1 : -1; + }); return html` - here + <tr> + <th>${label}</th> + <td> + <div>Devices:</div> + ${devs.map(d => { + return this.renderDevice(d); + })} + </td> + </tr> `; } + + graphView(store: N3Store, showGroups: boolean): Map<string, DevGroup> { + const grouped: Map<string, DevGroup> = new Map(); + const room = "http://projects.bigasterisk.com/room/"; + store.forEach( + q => { + const devUri: NamedNode = q.subject as NamedNode; + + const graphLiteral = ( + store: N3Store, + devUri: NamedNode, + pred: string, + notFoundResult?: string + ): Literal => { + const keep: Array<Literal> = []; + store.forEach( + q => { + if (!Util.isLiteral(q.object)) { + throw new Error("non literal found"); + } + keep.push(q.object as Literal); + }, + devUri, + namedNode(pred), + null, + null + ); + if (keep.length == 0) { + return literal(notFoundResult || "(missing)"); + } + if (keep.length == 1) { + return keep[0]; + } + throw new Error("found multiple matches for pred"); + }; + + const getAgoMin = ( + connected: Literal | undefined + ): number | undefined => { + if (connected) { + const t = new Date(connected.value); + const agoMs = Date.now() - t.valueOf(); + return agoMs / 1000 / 60; + } + return undefined; + }; + + const asString = (x: Literal | undefined): string => { + if (x && x.value) { + return x.value; + } + return "(unknown)"; + }; + const row: Dev = { + agoMin: getAgoMin( + literal("2020-01-01") // graphLiteral(store, devUri, room + "connectedToAp") + ), + ipAddress: graphLiteral( + store, + devUri, + room + "ipAddress", + "(unknown)" + ), + dhcpHostname: asString( + graphLiteral(store, devUri, room + "dhcpHostname") + ), + macAddress: graphLiteral(store, devUri, room + "macAddress"), + packetsPerSec: + graphLiteral(store, devUri, room + "packetsPerSec", "? ").value + + " P/s", //number; todo + bytesPerSec: + graphLiteral(store, devUri, room + "bytesPerSec", "? ").value + + "B/s", //number; + }; + if (row.dhcpHostname && (row.dhcpHostname as any).value) { + row.dhcpHostname = (row.dhcpHostname as any).value; + } + if (!showGroups || (row as any).connectedToAp) { + const key = showGroups + ? `${(row as any).connectedToAp.toNT()}-${(row as any).wifiBand.toNT()}` + : "all"; + if (!grouped.has(key)) { + grouped.set(key, { + connectedToAp: (row as any).connectedToAp, + wifiBand: (row as any).wifiBand, + devs: [], + }); + } + grouped.get(key)!.devs.push(row); + } else { + console.log("lost row", row); + } + + if (row.bytesPerSec) { + row.bytesPerSec = row.bytesPerSec.valueOf() + " B/s"; + } + if (row.packetsPerSec) { + row.packetsPerSec = row.packetsPerSec.valueOf() + " p/s"; + } + }, + null, + namedNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), + namedNode(room + "NetworkedDevice"), + null + ); + return grouped; + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/service/wifi/src/style.ts Sun Jan 05 23:18:27 2020 -0800 @@ -0,0 +1,51 @@ +import { css } from "lit-element"; + +export const style = css` + .report { + font-family: sans-serif; + } + section { + margin-left: 1em; + } + .dev { + margin-bottom: 2px; + } + .ip, + .mac, + .packets, + .bytes { + display: inline-block; + font-family: monospace; + } + .packets, + .bytes { + text-align: right; + padding-right: 1em; + } + .mac { + color: #ccffcc; + width: 11em; + } + .ip { + color: #b5b5d4; + width: 6em; + } + .packets { + color: #2da1a5; + width: 6em; + } + .bytes { + color: #a5912d; + width: 9em; + } + th, + td { + vertical-align: top; + } + th { + background: #333; + } + td { + background: #252525; + } +`;
--- a/service/wifi/src/wifi-table.ts Thu Jan 02 00:23:36 2020 -0800 +++ b/service/wifi/src/wifi-table.ts Sun Jan 05 23:18:27 2020 -0800 @@ -1,49 +1,51 @@ -import { html } from 'lit-html'; -import { NamedNode, DataFactory } from 'n3'; +import { html } from "lit-html"; +import { NamedNode, DataFactory } from "n3"; const { literal, quad, namedNode } = DataFactory; -import * as sgmod from 'streamed-graph'; -import { Literal, Term, N3Store } from 'n3'; +import * as sgmod from "streamed-graph"; +import { Literal, Term, N3Store } from "n3"; interface DevGroup { - connectedToAp: NamedNode, - wifiBand: NamedNode, - devs: Array<Dev> + connectedToAp: NamedNode; + wifiBand: NamedNode; + devs: Array<Dev>; } interface Dev { - agoMin: number, - ipAddress: Literal, - dhcpHostname: string, - macAddress: Literal, - packetsPerSec: number, - bytesPerSec: number + agoMin: number; + ipAddress: Literal; + dhcpHostname: string; + macAddress: Literal; + packetsPerSec: number; + bytesPerSec: number; } -console.log('got', sgmod); +console.log("got", sgmod); const NS: any = { - room: 'http://projects.bigasterisk.com/room/' -} + room: "http://projects.bigasterisk.com/room/", +}; // from rdf-uri.html const BigastUri = { // not well defined for uri prefixes that are string prefixes of each other - compactUri: function (uri: string) { + compactUri: function(uri: string) { if (uri === undefined) { return uri; } - if (typeof (uri) == "object") { throw new Error("type"); } + if (typeof uri == "object") { + throw new Error("type"); + } if (uri == "http://www.w3.org/1999/02/22-rdf-syntax-ns#type") { return "a"; } for (var short of Object.keys(NS as any)) { var prefix = NS[short]; if (uri.indexOf(prefix) == 0) { - return short + ':' + uri.substr(prefix.length); + return short + ":" + uri.substr(prefix.length); } } return uri; }, - expandUri: function (s: string) { + expandUri: function(s: string) { for (var short of Object.keys(NS)) { var prefix = NS[short]; if (s.indexOf(short + ":") == 0) { @@ -55,22 +57,39 @@ }; // workaround for uris that don't have good labels in the graph -function labelFromUri(uri: NamedNode, prefix: string, tailsToLabels: any, defaultLabel: string) { +function labelFromUri( + uri: NamedNode, + prefix: string, + tailsToLabels: any, + defaultLabel: string +) { let label = defaultLabel === undefined ? uri.value : defaultLabel; Object.entries(tailsToLabels).forEach(([tail, useLabel]) => { if (uri.equals(namedNode(prefix + tail))) { label = useLabel as string; } }); - return label + return label; } // set out[suffix] = graph.get(subj, predPrefix+suffix) for all suffixes -function getProperties(store: N3Store, out: any, subject: Term, predPrefix: string, predSuffixes: Array<string>) { - predSuffixes.forEach((term) => { - store.forEach((q) => { - out[term] = q.object; - }, subject, namedNode(predPrefix + term), null, null); +function getProperties( + store: N3Store, + out: any, + subject: Term, + predPrefix: string, + predSuffixes: Array<string> +) { + predSuffixes.forEach(term => { + store.forEach( + q => { + out[term] = q.object; + }, + subject, + namedNode(predPrefix + term), + null, + null + ); return out; }); @@ -78,84 +97,127 @@ function graphView(store: N3Store, showGroups: boolean): void { const grouped: Map<string, DevGroup> = new Map(); - store.forEach((q) => { - const row: any = { uri: q.subject }; + store.forEach( + q => { + const row: any = { uri: q.subject }; - getProperties(store, row, row.uri, 'room:', - ['dhcpHostname', 'ipAddress', 'macAddress', 'connectedToAp', 'wifiBand', 'connected', 'bytesPerSec', 'packetsPerSec']); - if (row.dhcpHostname && row.dhcpHostname.value) { - row.dhcpHostname = row.dhcpHostname.value; - } - if (!showGroups || row.connectedToAp) { - const key = (showGroups ? `${row.connectedToAp.toNT()}-${row.wifiBand.toNT()}` : 'all'); - if (!grouped.has(key)) { - grouped.set(key, { connectedToAp: row.connectedToAp, wifiBand: row.wifiBand, devs: [] }); + getProperties(store, row, row.uri, "room:", [ + "dhcpHostname", + "ipAddress", + "macAddress", + "connectedToAp", + "wifiBand", + "connected", + "bytesPerSec", + "packetsPerSec", + ]); + if (row.dhcpHostname && row.dhcpHostname.value) { + row.dhcpHostname = row.dhcpHostname.value; } - grouped.get(key)!.devs.push(row); - } else { - console.log('lost row', row); - } - if (row.connected) { - const t = new Date(row.connected.value); - const agoMs = (Date.now() as number) - (t as unknown as number); - row.agoMin = agoMs / 1000 / 60; - } - if (row.bytesPerSec) { row.bytesPerSec = row.bytesPerSec.valueOf() + ' B/s'; } - if (row.packetsPerSec) { row.packetsPerSec = row.packetsPerSec.valueOf() + ' p/s'; } - }, null, namedNode('rdf:type'), namedNode('room:NetworkedDevice'), null); + if (!showGroups || row.connectedToAp) { + const key = showGroups + ? `${row.connectedToAp.toNT()}-${row.wifiBand.toNT()}` + : "all"; + if (!grouped.has(key)) { + grouped.set(key, { + connectedToAp: row.connectedToAp, + wifiBand: row.wifiBand, + devs: [], + }); + } + grouped.get(key)!.devs.push(row); + } else { + console.log("lost row", row); + } + if (row.connected) { + const t = new Date(row.connected.value); + const agoMs = (Date.now() as number) - ((t as unknown) as number); + row.agoMin = agoMs / 1000 / 60; + } + if (row.bytesPerSec) { + row.bytesPerSec = row.bytesPerSec.valueOf() + " B/s"; + } + if (row.packetsPerSec) { + row.packetsPerSec = row.packetsPerSec.valueOf() + " p/s"; + } + }, + null, + namedNode("rdf:type"), + namedNode("room:NetworkedDevice"), + null + ); } const renderDevice = (dev: Dev) => { const glow = Math.max(0, 1 - dev.agoMin / 60); - const agoReport = dev.agoMin < 360 ? ` (${Math.ceil(dev.agoMin * 10) / 10} minutes ago)` : ''; + const agoReport = + dev.agoMin < 360 ? ` (${Math.ceil(dev.agoMin * 10) / 10} minutes ago)` : ""; return html` - <div class="dev" style="background: rgba(185, 5, 138, ${glow});"> - <span class="mac">${dev.macAddress.value}</span> - <span class="ip"><a href="http://${dev.ipAddress.value}/">${dev.ipAddress.value}</a></span> - <span class="packets">${dev.packetsPerSec}</span> - <span class="bytes">${dev.bytesPerSec}</span> - <span class="hostname">${dev.dhcpHostname}</span> - <span class="ago">${agoReport}</span> - <span class="links"> - <a href="https://bigasterisk.com/ntop/lua/host_details.lua?ifid=17&host=${dev.ipAddress.value}&page=flows">[flows]</a> - </span> - </div> - `; + <div class="dev" style="background: rgba(185, 5, 138, ${glow});"> + <span class="mac">${dev.macAddress.value}</span> + <span class="ip" + ><a href="http://${dev.ipAddress.value}/" + >${dev.ipAddress.value}</a + ></span + > + <span class="packets">${dev.packetsPerSec}</span> + <span class="bytes">${dev.bytesPerSec}</span> + <span class="hostname">${dev.dhcpHostname}</span> + <span class="ago">${agoReport}</span> + <span class="links"> + <a + href="https://bigasterisk.com/ntop/lua/host_details.lua?ifid=17&host=${dev + .ipAddress.value}&page=flows" + >[flows]</a + > + </span> + </div> + `; }; const renderGroup = (key: string, group: DevGroup) => { let label; - if (key != 'all') { - label = labelFromUri(group.connectedToAp, - 'http://bigasterisk.com/mac/', + if (key != "all") { + label = labelFromUri( + group.connectedToAp, + "http://bigasterisk.com/mac/", { - 'a0:40:a0:6f:96:d5': "Main router (d5)", - '8c:3b:ad:c4:8d:ce': "Downstairs satellite (ce)", - 'a0:40:a0:6f:aa:f8': "Upstairs satellite (f8)", + "a0:40:a0:6f:96:d5": "Main router (d5)", + "8c:3b:ad:c4:8d:ce": "Downstairs satellite (ce)", + "a0:40:a0:6f:aa:f8": "Upstairs satellite (f8)", }, - "unknown"); + "unknown" + ); - label += labelFromUri(group.wifiBand, - 'http://projects.bigasterisk.com/room/wifiBand/', + label += labelFromUri( + group.wifiBand, + "http://projects.bigasterisk.com/room/wifiBand/", { - '5G': ' 5G', - '2.4G': ' 2.4G', + "5G": " 5G", + "2.4G": " 2.4G", }, - "unknown"); + "unknown" + ); } const devs = group.devs; - function padIp(ip: string) { return ip.replace(/(\d+)/g, (m) => ('00' + m).slice(-3)); } - devs.sort((a, b) => { return padIp(a.ipAddress.value) > padIp(b.ipAddress.value) ? 1 : -1; }); + function padIp(ip: string) { + return ip.replace(/(\d+)/g, m => ("00" + m).slice(-3)); + } + devs.sort((a, b) => { + return padIp(a.ipAddress.value) > padIp(b.ipAddress.value) ? 1 : -1; + }); return html` - <tr> - <th>${label}</th> - <td> - <div>Devices:</div> - ${devs.map((d) => { return renderDevice(d); })} - </td> - </tr> - `; + <tr> + <th>${label}</th> + <td> + <div>Devices:</div> + ${devs.map(d => { + return renderDevice(d); + })} + </td> + </tr> + `; /* let groups=['?']; const out = html` @@ -189,5 +251,5 @@ </div> `; return out;*/ -} -export { graphView } +}; +export { graphView };
--- a/service/wifi/tsconfig.json Thu Jan 02 00:23:36 2020 -0800 +++ b/service/wifi/tsconfig.json Sun Jan 05 23:18:27 2020 -0800 @@ -25,10 +25,10 @@ // "outDir": "./build", "baseUrl": ".", // "emitDecoratorMetadata": true, - // "lib": [ "es6", "dom" ], + // "lib": [ "dom" ], - "diagnostics": true, - "traceResolution": true + // "diagnostics": true, + // "traceResolution": true }, "include": ["src/**/*.ts"],