You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
119 lines
4.2 KiB
119 lines
4.2 KiB
import m from 'mithril'; |
|
import { Page } from 'components/page'; |
|
import { MonitorApi, Status } from 'monitor-api'; |
|
import { Pipe } from 'utilities/pipe'; |
|
|
|
import { Clock } from 'components/widgets/clock'; |
|
import { NumericValue } from 'components/widgets/numeric-value'; |
|
import { GaugeLinear } from 'components/widgets/gauge-linear'; |
|
import { GaugeCircular } from 'components/widgets/gauge-circular'; |
|
import { GaugeBattery } from 'components/widgets/gauge-battery'; |
|
|
|
require('./dashboard-page.css'); |
|
|
|
export class DashboardPage extends Page { |
|
status: Status = null; |
|
autoRefresh = true; |
|
|
|
private power = new Pipe(0.0); |
|
private battery = new Pipe(0.0); |
|
private speed = new Pipe(0.0); |
|
|
|
private lastRefreshTime = 0.0; |
|
private movementTime = 0.0; |
|
private distance = new Pipe(0.0); |
|
private averageSpeed = new Pipe(0.0); |
|
private energy = new Pipe(0.0); |
|
private averageConsumption = new Pipe(0.0); |
|
private ascendingElevation = new Pipe(0.0); |
|
private lastElevation = -100000; |
|
private altitude = new Pipe(0.0); |
|
private temperature = new Pipe(0.0); |
|
|
|
oninit() { |
|
this.status = MonitorApi.get().getStatus(); |
|
this.refresh(); |
|
} |
|
|
|
onbeforeremove(vnode: m.Vnode<{}, {}>) { |
|
this.autoRefresh = false; |
|
} |
|
|
|
async refresh() { |
|
let newStatus = await MonitorApi.get().fetchStatus(); |
|
if(this.status == null) |
|
m.redraw(); |
|
this.status = newStatus; |
|
|
|
let power = Math.max(0.0, this.status.batteryVoltage * this.status.motorCurrent); |
|
this.power.set(power); |
|
|
|
const minVoltage = 36.0; |
|
const maxVoltage = 42.0; |
|
let batteryRatio = Math.max(0.0, (this.status.batteryVoltage - minVoltage) / (maxVoltage - minVoltage)); |
|
this.battery.set(batteryRatio * batteryRatio * 100.0); // TODO: find a better formula to estimate remaining energy from battery voltage and power |
|
|
|
this.speed.set(this.status.speed * 3.6); // convert m/s to km/h |
|
|
|
let now = Date.now() / 1000; |
|
if(this.lastRefreshTime == 0.0) this.lastRefreshTime = now; |
|
let dt = now - this.lastRefreshTime; |
|
this.lastRefreshTime = now; |
|
|
|
if(this.status.speed > 0.0) |
|
this.movementTime += dt; |
|
this.distance.set(this.distance.get() + this.status.speed * dt / 1000); |
|
if(this.movementTime > 0.0) |
|
this.averageSpeed.set(this.distance.get() / (this.movementTime / 3600)); |
|
|
|
if(this.lastElevation == -100000) |
|
this.lastElevation = this.status.altitude; |
|
let elevationChange = this.status.altitude - this.lastElevation; |
|
this.lastElevation = this.status.altitude; |
|
if(elevationChange > 0.0) |
|
this.ascendingElevation.set(this.ascendingElevation.get() + elevationChange); |
|
this.altitude.set(this.status.altitude); |
|
|
|
this.temperature.set(this.status.temperature); |
|
|
|
this.energy.set(this.energy.get() + power * dt / 3600); |
|
if(this.distance.get() > 0.1) |
|
this.averageConsumption.set(this.energy.get() / this.distance.get()); |
|
|
|
if(this.autoRefresh) |
|
setTimeout(() => { if(this.autoRefresh) this.refresh(); }, 150); |
|
} |
|
|
|
view() { |
|
return this.status |
|
? <div class="dashboard-page"> |
|
<div class="widgets-row"> |
|
<Clock/> |
|
</div> |
|
|
|
<div class="widgets-row" style="height: 40%"> |
|
<GaugeLinear widgetWidth={0.2} value={this.power} minValue={0} maxValue={999.0} bottomWidth={0.4} unit="W" /> |
|
<GaugeCircular widgetWidth={0.6} value={this.speed} minValue={0} maxValue={50.0} decimals={1} unit="km/h" /> |
|
<GaugeBattery widgetWidth={0.2} value={this.battery} minValue={0} maxValue={100.0} unit="%" /> |
|
</div> |
|
|
|
<div class="widgets-row"> |
|
<NumericValue widgetWidth={0.5} value={this.distance} decimals={1} unit="km" /> |
|
</div> |
|
<div class="widgets-row"> |
|
<NumericValue widgetWidth={0.5} value={this.averageSpeed} decimals={1} unit="km/h" /> |
|
<NumericValue widgetWidth={0.5} value={this.ascendingElevation} decimals={1} unit="m" /> |
|
</div> |
|
<div class="widgets-row"> |
|
<NumericValue widgetWidth={0.5} value={this.averageConsumption} decimals={1} unit="Wh/km" /> |
|
<NumericValue widgetWidth={0.5} value={this.energy} decimals={1} unit="Wh" /> |
|
</div> |
|
|
|
<div class="widgets-row"> |
|
<NumericValue widgetWidth={0.5} value={this.temperature} decimals={1} unit="°C" /> |
|
<NumericValue widgetWidth={0.5} value={this.altitude} decimals={1} unit="m" /> |
|
</div> |
|
</div> |
|
: <p>Chargement...</p>; |
|
} |
|
}
|
|
|