commit 76de8ad99924bbbe7735f47c76f2e17283b89640
parent 097408bccd45cd920dc8c3dd65eb67796e6a5ff4
Author: Milan Pässler <me@pbb.lc>
Date: Sun, 9 Jun 2019 19:00:50 +0200
parent 097408bccd45cd920dc8c3dd65eb67796e6a5ff4
Author: Milan Pässler <me@pbb.lc>
Date: Sun, 9 Jun 2019 19:00:50 +0200
power meter history
2 files changed, 278 insertions(+), 0 deletions(-)
A
|
210
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/src/connection-status.js b/src/connection-status.js @@ -0,0 +1,68 @@ +"use strict"; + +import { LitElement, html, css } from "lit-element"; +import { state } from "./state.js"; + +import "@authentic/mwc-icon"; + +const pad = (string, amount) => Array(amount).join('0').substr(0, amount - String(string).length) + string; + +const formatDate = (date) => ( + '' + + date.getFullYear() + + '/' + + pad(date.getMonth() + 1, 2) + + '/' + + pad(date.getDate(), 2) + + ' ' + + date.getHours() + + ':' + + pad(date.getMinutes(), 2) +); + +class ConnectionStatus extends LitElement { + constructor() { + super(...arguments); + state.subscribe(this.requestUpdate.bind(this)); + } + + render() { + return html` + ${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> + `} + `; + } + + 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; + justify-content: center; + align-items: center; + } + mwc-icon { + padding-right: .5em; + } + p { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + } + p.lastupdate { + font-size: 1em; + } + `; + } +} + +customElements.define("smarthome-connection-status", ConnectionStatus);
diff --git a/src/power-meter-history.js b/src/power-meter-history.js @@ -0,0 +1,210 @@ +"use strict"; + +import { LitElement, html, css } from "lit-element"; +import { state } from "./state.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 round = (num, places) => { + const factor = Math.pow(10, places); + return Math.round(num * factor) / factor; +}; + +const pad = (string, amount) => Array(amount).join('0').substr(0, amount - String(string).length) + string; + +const archive = {}; +const loading = {}; + +const years = [ 2019 ]; +const months = [...Array(12).keys()].map(n => n+1); + +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)); + } + + 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 this.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(); + }; + } + + async load(file) { + console.log("loading " + file); + if (!archive[file] && !loading[file]) { + loading[file] = true; + return fetch(`archive/${file}.json`) + .then(resp => resp.json()) + .then(data => { + archive[file] = data; + loading[file] = undefined; + return data; + }).catch(e => console.warn(e)); + } else { + return archive[file]; + } + } + + 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> + ${years.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> + ${months.map(m => html`<mwc-list-item value="${pad(m, 2)}">${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).map((day) => html` + <div class="table-column">${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).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; + } + @media (min-width: 600px) { + #connection-status { + margin-top: 20px; + } + } + + .hidden { + display: none; + } + #selection { + display: flex; + flex-wrap: wrap; + flex-direction: row; + width: 450px; + max-width: 100%; + margin-left: auto; + margin-right: auto; + margin-top: 40px; + margin-bottom: -20px; + /*justify-content: space-between;*/ + } + mwc-select { + width: 100px; + margin-right: 20px; + } + `; + } +} + +customElements.define("smarthome-power-meter-history", PowerMeterHistory);