ctucx.git: smartie-pwa

[js] smarthome web-gui

commit 61932b21de4e9e55e8f4f177285f03d50a6ac6b4
parent a5749f61beb532f02141fc3cdeff8395ca816476
Author: Milan Pässler <me@pbb.lc>
Date: Tue, 18 Jun 2019 02:25:44 +0200

power meter tabs
7 files changed, 383 insertions(+), 362 deletions(-)
M
src/departures.js
|
23
-----------------------
M
src/layout.js
|
5
++---
D
src/power-meter-history.js
|
208
-------------------------------------------------------------------------------
D
src/power-meter.js
|
128
-------------------------------------------------------------------------------
A
src/power-meter/history.js
|
186
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
src/power-meter/index.js
|
68
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
src/power-meter/live.js
|
127
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/src/departures.js b/src/departures.js
@@ -76,24 +76,6 @@ class Departures extends LitElement {
 				--mdc-theme-on-secondary: white;
 				--mdc-theme-secondary: #616161;
 			}
-			#connection-status mwc-icon {
-				padding-right: .5em;
-			}
-			#connection-status {
-				display: flex;
-				flex-direction: column;
-				justify-content: center;
-				align-items: center;
-			}
-			#connection-status>p {
-				display: flex;
-				flex-direction: row;
-				justify-content: center;
-				align-items: center;
-			}
-			#connection-status>p.lastupdate {
-				font-size: 1em;
-			}
 			.table {
 				display: flex;
 				flex-direction: row;

@@ -114,11 +96,6 @@ class Departures extends LitElement {
 			.table-column {
 				background-color: #ddd;
 			}
-			@media (min-width: 600px) {
-				#connection-status {
-					margin-top: 20px;
-				}
-			}
 			.line-column {
 				width: 20%;
 			}
diff --git a/src/layout.js b/src/layout.js
@@ -9,8 +9,7 @@ import "@authentic/mwc-icon";
 import "@authentic/mwc-drawer";
 
 import "./lights.js";
-import "./power-meter.js";
-import "./power-meter-history.js";
+import "./power-meter/index.js";
 import "./departures.js";
 import "./settings.js";
 import "./spinner.js";

@@ -21,7 +20,7 @@ netdataRedirect.innerHTML = "window.location = `http://${window.location.host}/n
 
 const pages = {
 	"#/lights": { name: "Lights", content: html`<smarthome-lights></smarthome-lights>`, icon: "lightbulb" },
-	"#/powermeter": { name: "Power Meter", content: html`<smarthome-power-meter></smarthome-power-meter><smarthome-power-meter-history></smarthome-power-meter-history>`, icon: "power" },
+	"#/powermeter": { name: "Power Meter", content: html`<smarthome-power-meter></smarthome-power-meter>`, icon: "power" },
 	"#/departures": { name: "Departures", content: html`<smarthome-departures></smarthome-departures>`, icon: "departure_board" },
 	"#/netdata": { name: "netdata", content: html`<smarthome-spinner></smarthome-spinner> ${netdataRedirect}`, icon: "show_chart" },
 	"#/settings": { name: "Settings", content: html`<smarthome-settings></smarthome-settings>`, icon: "settings" },
diff --git a/src/power-meter-history.js b/src/power-meter-history.js
@@ -1,208 +0,0 @@
-"use strict";
-
-import { LitElement, html, css } from "lit-element";
-import { state } from "./state.js";
-import { pad, round, weekdays, months, get } from "./util.js";
-import { archive } from "./archive.js";
-
-import "@authentic/mwc-circular-progress";
-import "@authentic/mwc-icon";
-import "@authentic/mwc-select";
-import "@authentic/mwc-menu";
-import "@authentic/mwc-list";
-import "./card.js";
-import "./spinner.js";
-
-const formatName = (type, name) => {
-	if (type == "day") {
-		const date = new Date(`${name.substr(0, 4)}-${name.substr(4, 2)}-${name.substr(6, 2)}`);
-		return `${weekdays[date.getDay()]} ${date.getDate()}th`;
-	} else if (type == "week") {
-		let res = "";
-		const date = new Date(name.substr(0, 4), 0, 1 + 7 * (Number(name.substr(4, 2)) - 1));
-		date.setDate(date.getDate() + 1 - date.getDay());
-		res += `${date.getDate()}.${date.getMonth()+1}.`;
-		date.setDate(date.getDate() + 7 - date.getDay());
-		res += ` - ${date.getDate()}.${date.getMonth()+1}.`;
-		return res;
-	} else if (type == "month") {
-		const date = new Date(`${name.substr(0, 4)}-${name.substr(4, 2)}-01`);
-		return months[date.getMonth()];
-	}
-};
-
-class PowerMeterHistory extends LitElement {
-	constructor() {
-		super(...arguments);
-		this.type = "day";
-		const now = new Date();
-		this.year = now.getFullYear();
-		this.month = pad(now.getMonth() + 1, 2);
-
-		state.subscribe(this.loadData.bind(this));
-		archive.subscribe(this.loadData.bind(this));
-	}
-
-	async loadData(e) {
-		const d = {};
-
-		this.sel = this.year;
-		if (this.type === "day") this.sel += "_" + this.month;
-
-		await Promise.all(Object.entries(state.data.powermeter).map(async ([id, p]) => {
-			const data = await archive.load(`${this.type}/${id}_${this.sel}`);
-			if(!data) return;
-			for (let day of Object.keys(data)) {
-				if (!d[day]) d[day] = {};
-				d[day][id] = data[day].imported;
-			}
-		}));
-		this.data = d;
-
-		this.requestUpdate();
-	}
-
-	handleSelected(field) {
-		return (evt) => {
-			this[field] = evt.detail.item.value;
-			this.loadData();
-		};
-	}
-
-	render() {
-		const now = new Date();
-		return html`
-			<div id="selection" class="${state.data.powermeter && state.connected ? "" : "hidden"}">
-				<mwc-select label="Type">
-					<mwc-menu slot="menu" class="type-sel" @MDCMenu:selected=${this.handleSelected("type")}>
-						<mwc-list>
-							<mwc-list-item value="day">Days</mwc-list-item>
-							<mwc-list-item value="week">Weeks</mwc-list-item>
-							<mwc-list-item value="month">Months</mwc-list-item>
-						</mwc-list>
-					</mwc-menu>
-				</mwc-select>
-				<mwc-select label="Year">
-					<mwc-menu slot="menu" class="year-sel" @MDCMenu:selected=${this.handleSelected("year")}>
-						<mwc-list>
-							${Object.keys(get(archive.load("metadata"), [ "availableData" ], {})).map(m => html`<mwc-list-item value="${m}">${m}</mwc-list-item>`)}
-						</mwc-list>
-					</mwc-menu>
-				</mwc-select>
-				<mwc-select label="Month" class="${this.type == "day" ? "" : "hidden"}">
-					<mwc-menu slot="menu" class="month-sel" @MDCMenu:selected=${this.handleSelected("month")}>
-						<mwc-list>
-							${get(archive.load("metadata"), [ "availableData", this.year ], []).map(m => html`<mwc-list-item value="${m}">${Number(m)}</mwc-list-item>`)}
-						</mwc-list>
-					</mwc-menu>
-				</mwc-select>
-			</div>
-			${state.data.powermeter && state.connected ? html`
-				<smarthome-card>
-					<div class="table">
-						<div class="table-row table-head">
-							<div class="table-column">Name</div>
-							${Object.keys(this.data).reverse().map((day) => html`
-								<div class="table-column">${formatName(this.type, day)}</table-column>
-							`)}
-						</div>
-						${Object.entries(state.data.powermeter).map(([id, d]) => html`
-							<div class="table-row">
-								<div class="table-column">${d.name}</div>
-								${Object.entries(this.data).reverse().map(([day, d]) => html`
-									<div class="table-column">${d[id] ? round(d[id], 2) + " kWh" : "-"}</div>
-								`)}
-							</div>
-						`)}
-					</div>
-				</smarthome-card>
-			` : html``}
-		`;
-	}
-
-	static get styles() {
-		return css`
-			:host {
-				display: flex;
-				flex-direction: column;
-				--mdc-theme-on-primary: white;
-				--mdc-theme-primary: #43a047;
-				--mdc-theme-on-secondary: white;
-				--mdc-theme-secondary: #616161;
-			}
-			#connection-status mwc-icon {
-				padding-right: .5em;
-			}
-			#connection-status {
-				display: flex;
-				flex-direction: column;
-				justify-content: center;
-				align-items: center;
-			}
-			#connection-status>p {
-				display: flex;
-				flex-direction: row;
-				justify-content: center;
-				align-items: center;
-			}
-			#connection-status>p.lastupdate {
-				font-size: 1em;
-			}
-			.table {
-				display: flex;
-				flex-direction: row;
-			}
-			.table-row {
-				display: flex;
-				flex-direction: column;
-				width: 100%;
-			}
-			.table-column {
-				padding: 1em;
-				height: 1em;
-				display: flex;
-				flex-direction: column;
-				justify-content: center;
-			}
-
-			.table-column {
-				background-color: #ddd;
-			}
-			.table-column:nth-child(2n) {
-				background-color: #fff;
-			}
-
-			.hidden {
-				display: none;
-			}
-			#selection {
-				justify-content: center;
-				display: flex;
-				flex-wrap: wrap;
-				flex-direction: row;
-				width: 450px;
-				max-width: 100%;
-				margin-left: auto;
-				margin-right: auto;
-				margin-top: 40px;
-				margin-bottom: 0px;
-				/*justify-content: space-between;*/
-			}
-			mwc-select {
-				width: 100px;
-				margin-right: 10px;
-				margin-left: 10px;
-			}
-			@media (min-width: 600px) {
-				#connection-status {
-					margin-top: 20px;
-				}
-				#selection {
-					margin-bottom: -20px;
-				}
-			}
-		`;
-	}
-}
-
-customElements.define("smarthome-power-meter-history", PowerMeterHistory);
diff --git a/src/power-meter.js b/src/power-meter.js
@@ -1,128 +0,0 @@
-"use strict";
-
-import { LitElement, html, css } from "lit-element";
-import { state } from "./state.js";
-import { pad, formatDate, round, get } from "./util.js";
-import { archive } from "./archive.js";
-
-import "@authentic/mwc-circular-progress";
-import "@authentic/mwc-icon";
-import "./card.js";
-import "./spinner.js";
-
-class PowerMeter extends LitElement {
-	constructor() {
-		super(...arguments);
-		state.subscribe(this.requestUpdate.bind(this));
-		archive.subscribe(this.requestUpdate.bind(this));
-	}
-
-	getImport(id) {
-		const now = new Date();
-		const file = archive.load(`day/${id}_${now.getFullYear()}_${pad(now.getMonth() + 1, 2)}`);
-		const value = get(file, [ `${now.getFullYear()}${pad(now.getMonth() + 1, 2)}${pad(now.getDate(), 2)}`, "imported" ]);
-		return value ? round(value, 2) + "kWh" : "-";
-	}
-
-	render() {
-		return html`
-			${state.data.powermeter ? html`
-				<div id="connection-status">
-					${state.connected ? html`
-						<p><mwc-icon>cloud_queue</mwc-icon> Connected</p>
-					` : html`
-						<p><mwc-icon>cloud_off</mwc-icon> Disconnected</p>
-						<p class="lastupdate">last updated ${formatDate(state.data.lastUpdated)}</p>
-					`}
-				</div>
-				<smarthome-card>
-					<div class="table">
-						<div class="table-row table-head">
-							<div class="table-column">Name</div>
-							<div class="table-column">Voltage</div>
-							<div class="table-column">Power</div>
-							<div class="table-column">Power Factor</div>
-							<div class="table-column">Frequency</div>
-							<div class="table-column">Total Import</div>
-							<div class="table-column">Import</div>
-						</div>
-						${Object.entries(state.data.powermeter).map(([id, d]) => html`
-							<div class="table-row">
-								<div class="table-column">${d.name}</div>
-								<div class="table-column">${d.values.voltage} V</div>
-								<div class="table-column">${d.values.power} W</div>
-								<div class="table-column">${d.values.cosphi}</div>
-								<div class="table-column">${d.values.frequency}</div>
-								<div class="table-column">${d.values.import} kWh</div>
-								<div class="table-column">${this.getImport(id)}</div>
-							</div>
-						`)}
-					</div>
-				</smarthome-card>
-			` : html`
-				<smarthome-spinner></smarthome-spinner>
-			`}
-		`;
-	}
-
-	static get styles() {
-		return css`
-			:host {
-				display: flex;
-				flex-direction: column;
-				--mdc-theme-on-primary: white;
-				--mdc-theme-primary: #43a047;
-				--mdc-theme-on-secondary: white;
-				--mdc-theme-secondary: #616161;
-			}
-			#connection-status mwc-icon {
-				padding-right: .5em;
-			}
-			#connection-status {
-				display: flex;
-				flex-direction: column;
-				justify-content: center;
-				align-items: center;
-			}
-			#connection-status>p {
-				display: flex;
-				flex-direction: row;
-				justify-content: center;
-				align-items: center;
-			}
-			#connection-status>p.lastupdate {
-				font-size: 1em;
-			}
-			.table {
-				display: flex;
-				flex-direction: row;
-			}
-			.table-row {
-				display: flex;
-				flex-direction: column;
-				width: 100%;
-			}
-			.table-column {
-				padding: 1em;
-				height: 1em;
-				display: flex;
-				flex-direction: column;
-				justify-content: center;
-			}
-
-			.table-column {
-				background-color: #ddd;
-			}
-			.table-column:nth-child(2n) {
-				background-color: #fff;
-			}
-			@media (min-width: 600px) {
-				#connection-status {
-					margin-top: 20px;
-				}
-			}
-		`;
-	}
-}
-
-customElements.define("smarthome-power-meter", PowerMeter);
diff --git a/src/power-meter/history.js b/src/power-meter/history.js
@@ -0,0 +1,186 @@
+"use strict";
+
+import { LitElement, html, css } from "lit-element";
+import { state } from "../state.js";
+import { pad, round, weekdays, months, get } from "../util.js";
+import { archive } from "../archive.js";
+
+import "@authentic/mwc-icon";
+import "@authentic/mwc-select";
+import "@authentic/mwc-menu";
+import "@authentic/mwc-list";
+import "../card.js";
+import "../spinner.js";
+
+const formatName = (type, name) => {
+	if (type == "day") {
+		const date = new Date(`${name.substr(0, 4)}-${name.substr(4, 2)}-${name.substr(6, 2)}`);
+		return `${weekdays[date.getDay()]} ${date.getDate()}th`;
+	} else if (type == "week") {
+		let res = "";
+		const date = new Date(name.substr(0, 4), 0, 1 + 7 * (Number(name.substr(4, 2)) - 1));
+		date.setDate(date.getDate() + 1 - date.getDay());
+		res += `${date.getDate()}.${date.getMonth()+1}.`;
+		date.setDate(date.getDate() + 7 - date.getDay());
+		res += ` - ${date.getDate()}.${date.getMonth()+1}.`;
+		return res;
+	} else if (type == "month") {
+		const date = new Date(`${name.substr(0, 4)}-${name.substr(4, 2)}-01`);
+		return months[date.getMonth()];
+	}
+};
+
+class PowerMeterHistory extends LitElement {
+	constructor() {
+		super(...arguments);
+		this.type = "day";
+		const now = new Date();
+		this.year = now.getFullYear();
+		this.month = pad(now.getMonth() + 1, 2);
+
+		state.subscribe(this.loadData.bind(this));
+		archive.subscribe(this.loadData.bind(this));
+	}
+
+	async loadData(e) {
+		const d = {};
+
+		this.sel = this.year;
+		if (this.type === "day") this.sel += "_" + this.month;
+
+		await Promise.all(Object.entries(state.data.powermeter).map(async ([id, p]) => {
+			const data = await archive.load(`${this.type}/${id}_${this.sel}`);
+			if(!data) return;
+			for (let day of Object.keys(data)) {
+				if (!d[day]) d[day] = {};
+				d[day][id] = data[day].imported;
+			}
+		}));
+		this.data = d;
+
+		this.requestUpdate();
+	}
+
+	handleSelected(field) {
+		return (evt) => {
+			this[field] = evt.detail.item.value;
+			this.loadData();
+		};
+	}
+
+	render() {
+		const now = new Date();
+		return html`
+			<div id="selection" class="${state.data.powermeter && state.connected ? "" : "hidden"}">
+				<mwc-select label="Type">
+					<mwc-menu slot="menu" class="type-sel" @MDCMenu:selected=${this.handleSelected("type")}>
+						<mwc-list>
+							<mwc-list-item value="day">Days</mwc-list-item>
+							<mwc-list-item value="week">Weeks</mwc-list-item>
+							<mwc-list-item value="month">Months</mwc-list-item>
+						</mwc-list>
+					</mwc-menu>
+				</mwc-select>
+				<mwc-select label="Year">
+					<mwc-menu slot="menu" class="year-sel" @MDCMenu:selected=${this.handleSelected("year")}>
+						<mwc-list>
+							${Object.keys(get(archive.load("metadata"), [ "availableData" ], {})).map(m => html`<mwc-list-item value="${m}">${m}</mwc-list-item>`)}
+						</mwc-list>
+					</mwc-menu>
+				</mwc-select>
+				<mwc-select label="Month" class="${this.type == "day" ? "" : "hidden"}">
+					<mwc-menu slot="menu" class="month-sel" @MDCMenu:selected=${this.handleSelected("month")}>
+						<mwc-list>
+							${get(archive.load("metadata"), [ "availableData", this.year ], []).map(m => html`<mwc-list-item value="${m}">${Number(m)}</mwc-list-item>`)}
+						</mwc-list>
+					</mwc-menu>
+				</mwc-select>
+			</div>
+			${state.data.powermeter && state.connected ? html`
+				<smarthome-card>
+					<div class="table">
+						<div class="table-row table-head">
+							<div class="table-column">Name</div>
+							${Object.keys(this.data).reverse().map((day) => html`
+								<div class="table-column">${formatName(this.type, day)}</table-column>
+							`)}
+						</div>
+						${Object.entries(state.data.powermeter).map(([id, d]) => html`
+							<div class="table-row">
+								<div class="table-column">${d.name}</div>
+								${Object.entries(this.data).reverse().map(([day, d]) => html`
+									<div class="table-column">${d[id] ? round(d[id], 2) + " kWh" : "-"}</div>
+								`)}
+							</div>
+						`)}
+					</div>
+				</smarthome-card>
+			` : html``}
+		`;
+	}
+
+	static get styles() {
+		return css`
+			:host {
+				display: flex;
+				flex-direction: column;
+				--mdc-theme-on-primary: white;
+				--mdc-theme-primary: #43a047;
+				--mdc-theme-on-secondary: white;
+				--mdc-theme-secondary: #616161;
+			}
+			.table {
+				display: flex;
+				flex-direction: row;
+			}
+			.table-row {
+				display: flex;
+				flex-direction: column;
+				width: 100%;
+			}
+			.table-column {
+				padding: 1em;
+				height: 1em;
+				display: flex;
+				flex-direction: column;
+				justify-content: center;
+			}
+
+			.table-column {
+				background-color: #ddd;
+			}
+			.table-column:nth-child(2n) {
+				background-color: #fff;
+			}
+
+			.hidden {
+				display: none;
+			}
+			#selection {
+				justify-content: center;
+				display: flex;
+				flex-wrap: wrap;
+				flex-direction: row;
+				width: 450px;
+				max-width: 100%;
+				margin-left: auto;
+				margin-right: auto;
+				margin-top: 40px;
+				margin-bottom: 0px;
+				/*justify-content: space-between;*/
+			}
+			mwc-select {
+				width: 100px;
+				margin-right: 10px;
+				margin-left: 10px;
+			}
+			@media (min-width: 600px) {
+				#selection {
+					margin-bottom: -20px;
+				}
+			}
+		`;
+	}
+}
+
+customElements.define("smarthome-power-meter-history", PowerMeterHistory);
diff --git a/src/power-meter/index.js b/src/power-meter/index.js
@@ -0,0 +1,68 @@
+"use strict";
+
+import { LitElement, html, css } from "lit-element";
+
+import "./history.js";
+import "./live.js";
+
+const pages = {
+	"live": { name: "Live", content: html`<smarthome-power-meter-live></smarthome-power-meter-live>` },
+	"history": { name: "History", content: html`<smarthome-power-meter-history></smarthome-power-meter-history>` },
+};
+
+class PowerMeter extends LitElement {
+	constructor() {
+		super(...arguments);
+		this.activePage = pages["live"];
+	}
+
+	_setPage(path) {
+		return () => {
+			this.activePage = pages[path];
+			this.requestUpdate();
+		};
+	}
+
+	render() {
+		return html`
+			<div id="pages">
+				${Object.entries(pages).map(([path, page]) => html`
+					<a href="#/powermeter" class="page-link ${this.activePage == page ? "active" : "inactive"}" @click=${this._setPage(path)}>
+						${page.name}
+					</a>
+				`)}
+			</div>
+			${this.activePage.content}
+		`;
+	}
+
+	static get styles() {
+		return css`
+			:host {
+				display: flex;
+				flex-direction: column;
+				--mdc-theme-on-primary: white;
+				--mdc-theme-primary: #43a047;
+				--mdc-theme-on-secondary: white;
+				--mdc-theme-secondary: #616161;
+			}
+
+			#pages {
+				display: flex;
+				flex-direction: row;
+				justify-content: center;
+			}
+			.page-link {
+				padding: .5em;
+				margin: .5em;
+				color: black;
+				text-decoration: none;
+			}
+			.page-link.active {
+				border-bottom: 4px solid #43a047;
+			}
+		`;
+	}
+}
+
+customElements.define("smarthome-power-meter", PowerMeter);
diff --git a/src/power-meter/live.js b/src/power-meter/live.js
@@ -0,0 +1,127 @@
+"use strict";
+
+import { LitElement, html, css } from "lit-element";
+import { state } from "../state.js";
+import { pad, formatDate, round, get } from "../util.js";
+import { archive } from "../archive.js";
+
+import "@authentic/mwc-icon";
+import "../card.js";
+import "../spinner.js";
+
+class PowerMeterLive extends LitElement {
+	constructor() {
+		super(...arguments);
+		state.subscribe(this.requestUpdate.bind(this));
+		archive.subscribe(this.requestUpdate.bind(this));
+	}
+
+	getImport(id) {
+		const now = new Date();
+		const file = archive.load(`day/${id}_${now.getFullYear()}_${pad(now.getMonth() + 1, 2)}`);
+		const value = get(file, [ `${now.getFullYear()}${pad(now.getMonth() + 1, 2)}${pad(now.getDate(), 2)}`, "imported" ]);
+		return value ? round(value, 2) + " kWh" : "-";
+	}
+
+	render() {
+		return html`
+			${state.data.powermeter ? html`
+				<div id="connection-status">
+					${state.connected ? html`
+						<p><mwc-icon>cloud_queue</mwc-icon> Connected</p>
+					` : html`
+						<p><mwc-icon>cloud_off</mwc-icon> Disconnected</p>
+						<p class="lastupdate">last updated ${formatDate(state.data.lastUpdated)}</p>
+					`}
+				</div>
+				<smarthome-card>
+					<div class="table">
+						<div class="table-row table-head">
+							<div class="table-column">Name</div>
+							<div class="table-column">Voltage</div>
+							<div class="table-column">Power</div>
+							<div class="table-column">Power Factor</div>
+							<div class="table-column">Frequency</div>
+							<div class="table-column">Total Import</div>
+							<div class="table-column">Import</div>
+						</div>
+						${Object.entries(state.data.powermeter).map(([id, d]) => html`
+							<div class="table-row">
+								<div class="table-column">${d.name}</div>
+								<div class="table-column">${d.values.voltage} V</div>
+								<div class="table-column">${d.values.power} W</div>
+								<div class="table-column">${d.values.cosphi}</div>
+								<div class="table-column">${d.values.frequency}</div>
+								<div class="table-column">${d.values.import} kWh</div>
+								<div class="table-column">${this.getImport(id)}</div>
+							</div>
+						`)}
+					</div>
+				</smarthome-card>
+			` : html`
+				<smarthome-spinner></smarthome-spinner>
+			`}
+		`;
+	}
+
+	static get styles() {
+		return css`
+			:host {
+				display: flex;
+				flex-direction: column;
+				--mdc-theme-on-primary: white;
+				--mdc-theme-primary: #43a047;
+				--mdc-theme-on-secondary: white;
+				--mdc-theme-secondary: #616161;
+			}
+			#connection-status mwc-icon {
+				padding-right: .5em;
+			}
+			#connection-status {
+				display: flex;
+				flex-direction: column;
+				justify-content: center;
+				align-items: center;
+			}
+			#connection-status>p {
+				display: flex;
+				flex-direction: row;
+				justify-content: center;
+				align-items: center;
+			}
+			#connection-status>p.lastupdate {
+				font-size: 1em;
+			}
+			.table {
+				display: flex;
+				flex-direction: row;
+			}
+			.table-row {
+				display: flex;
+				flex-direction: column;
+				width: 100%;
+			}
+			.table-column {
+				padding: 1em;
+				height: 1em;
+				display: flex;
+				flex-direction: column;
+				justify-content: center;
+			}
+
+			.table-column {
+				background-color: #ddd;
+			}
+			.table-column:nth-child(2n) {
+				background-color: #fff;
+			}
+			@media (min-width: 600px) {
+				#connection-status {
+					margin-top: 20px;
+				}
+			}
+		`;
+	}
+}
+
+customElements.define("smarthome-power-meter-live", PowerMeterLive);