Updated site to use new BMS data
This commit is contained in:
parent
0f07821317
commit
5c4bb8b515
@ -1,25 +1,20 @@
|
|||||||
<div class="fill-height p-3" style="background-color: #b52e3c !important;">
|
<div class="fill-height p-3" style="background-color: #b52e3c !important; overflow-y: scroll">
|
||||||
<div style="max-width: 1000px;">
|
<div style="max-width: 1000px;">
|
||||||
<div class="d-flex flex-column flex-md-row justify-content-between">
|
<div class="d-flex flex-column flex-md-row justify-content-between align-items-end mb-2">
|
||||||
<div class="mb-3">
|
<div>
|
||||||
<h1 class="mb-0">Powerwall: {{batteryService.charge | number : '1.1-1'}} V</h1>
|
<h1 class="mb-0">Powerwall: {{batteryService.charge | number : '1.1-1'}} V</h1>
|
||||||
<h6>Last Updated At: {{batteryService.lastUpdate | date: 'short'}}</h6>
|
<h6>Last Updated At: {{batteryService.lastUpdate | date: 'short'}}</h6>
|
||||||
|
<h6 class="mb-0">Uptime: {{batteryService.uptime}}</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex flex-column align-content-center mb-3">
|
<div>
|
||||||
<div>
|
<mat-button-toggle-group>
|
||||||
<h5><mat-icon *ngIf="locked" class="mr-1">lock</mat-icon>Cooling Fans</h5>
|
<mat-button-toggle value="24" [checked]="true">24 Hours</mat-button-toggle>
|
||||||
</div>
|
<mat-button-toggle value="12">12 Hours</mat-button-toggle>
|
||||||
<div>
|
<mat-button-toggle value="6">6 Hours</mat-button-toggle>
|
||||||
<mat-button-toggle-group class="mb-3" [ngModel]="batteryService.relayMode"
|
</mat-button-toggle-group>
|
||||||
(change)="batteryService.setRelayMode($event.value)" [disabled]="locked">
|
|
||||||
<mat-button-toggle value="null">Auto</mat-button-toggle>
|
|
||||||
<mat-button-toggle value="true">On</mat-button-toggle>
|
|
||||||
<mat-button-toggle value="false">Off</mat-button-toggle>
|
|
||||||
</mat-button-toggle-group>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<mat-card class="mt-2" *ngFor="let battery of batteryService.batteries; let i = index">
|
<mat-card class="mt-2" *ngFor="let battery of batteries; let i = index">
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<div class="d-flex flex-grow-1 align-items-center">
|
<div class="d-flex flex-grow-1 align-items-center">
|
||||||
<h5 class="mb-0">{{battery.name}}</h5>
|
<h5 class="mb-0">{{battery.name}}</h5>
|
||||||
@ -27,13 +22,13 @@
|
|||||||
<div class="d-flex flex-grow-1 align-items-center justify-content-center">
|
<div class="d-flex flex-grow-1 align-items-center justify-content-center">
|
||||||
<button mat-button (click)="selected = i"
|
<button mat-button (click)="selected = i"
|
||||||
[ngClass]="{'selected': selected == i, 'text-success': batteryService.charging, 'text-danger': !batteryService.charging}">
|
[ngClass]="{'selected': selected == i, 'text-success': batteryService.charging, 'text-danger': !batteryService.charging}">
|
||||||
{{battery.charge | number : '1.1-1'}} V
|
{{battery.voltage | number : '1.1-1'}} V
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex flex-grow-1 align-items-center justify-content-end text-muted">
|
<div class="d-flex flex-grow-1 align-items-center justify-content-end text-muted">
|
||||||
<button mat-button (click)="selected = batteryService.batteries.length + i"
|
<button mat-button (click)="selected = batteries.length + i"
|
||||||
[ngClass]="{'selected': selected == batteryService.batteries.length + i}">
|
[ngClass]="{'selected': selected == batteries.length + i}">
|
||||||
{{battery.temp | number : '1.1-1'}} °C
|
{{battery.temperature | number : '1.1-1'}} °C
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -50,7 +45,7 @@
|
|||||||
[roundDomains]="true"
|
[roundDomains]="true"
|
||||||
></ngx-charts-area-chart>
|
></ngx-charts-area-chart>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="selected == batteryService.batteries.length + i" class="w-100" style="height: 200px">
|
<div *ngIf="selected == batteries.length + i" class="w-100" style="height: 200px">
|
||||||
<ngx-charts-area-chart class="w-100 h-100"
|
<ngx-charts-area-chart class="w-100 h-100"
|
||||||
[results]="[{name: battery.name, series: battery.tempHistory}]"
|
[results]="[{name: battery.name, series: battery.tempHistory}]"
|
||||||
[scheme]="scheme"
|
[scheme]="scheme"
|
||||||
|
@ -8,8 +8,7 @@ import {AppComponent} from '../app.component';
|
|||||||
styles: [`.selected { background-color: rgba(0, 0, 0, 0.1); }`]
|
styles: [`.selected { background-color: rgba(0, 0, 0, 0.1); }`]
|
||||||
})
|
})
|
||||||
export class BatteryComponent implements OnInit {
|
export class BatteryComponent implements OnInit {
|
||||||
|
batteries = [];
|
||||||
locked = true;
|
|
||||||
scheme = {
|
scheme = {
|
||||||
name: 'cool',
|
name: 'cool',
|
||||||
selectable: true,
|
selectable: true,
|
||||||
@ -18,7 +17,20 @@ export class BatteryComponent implements OnInit {
|
|||||||
};
|
};
|
||||||
selected = 0;
|
selected = 0;
|
||||||
|
|
||||||
constructor(public app: AppComponent, public batteryService: BatteryService) { }
|
constructor(public app: AppComponent, public batteryService: BatteryService) {
|
||||||
|
this.batteryService.data.subscribe((data) => {
|
||||||
|
console.log(data);
|
||||||
|
this.batteries = Object.keys(this.batteryService.modules).map(key => {
|
||||||
|
return {
|
||||||
|
name: `Module ${key}`,
|
||||||
|
chargeHistory: this.batteryService.modules[key].map(row => ({name: new Date(row.timestamp), value: row.voltage})),
|
||||||
|
tempHistory: this.batteryService.modules[key].map(row => ({name: new Date(row.timestamp), value: row.temperature})),
|
||||||
|
temperature: this.batteryService.modules[key][this.batteryService.modules[key].length - 1].temperature,
|
||||||
|
voltage: this.batteryService.modules[key][this.batteryService.modules[key].length - 1].voltage
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() { }
|
ngOnInit() { }
|
||||||
|
|
||||||
|
@ -1,18 +1,26 @@
|
|||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {AngularFirestore} from '@angular/fire/firestore';
|
import {AngularFirestore} from '@angular/fire/firestore';
|
||||||
|
import {Battery} from './battery';
|
||||||
|
import {BehaviorSubject} from 'rxjs';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
})
|
})
|
||||||
export class BatteryService {
|
export class BatteryService {
|
||||||
batteries = [];
|
|
||||||
charge: number;
|
charge: number;
|
||||||
lastCharge: number[] = [];
|
data = new BehaviorSubject<Battery[]>([]);
|
||||||
lastUpdate = new Date().getTime();
|
lastUpdate = new Date().getTime();
|
||||||
relayMode: string = 'null';
|
modules = [];
|
||||||
temp: number = 0;
|
temp: number = 0;
|
||||||
|
uptime: string;
|
||||||
|
|
||||||
get charging() { return this.lastCharge.reduce((acc, v) => acc + v, 0) / this.lastCharge.length < this.charge; }
|
get charging() {
|
||||||
|
let value = this.data.value;
|
||||||
|
if(!value.length) return null;
|
||||||
|
let last = value[value.length - 1];
|
||||||
|
let secondLast = value[value.length - 2];
|
||||||
|
return last.soc > secondLast.soc;
|
||||||
|
}
|
||||||
|
|
||||||
get icon() {
|
get icon() {
|
||||||
if(new Date().getTime() - this.lastUpdate > 300000) return 'battery_alert';
|
if(new Date().getTime() - this.lastUpdate > 300000) return 'battery_alert';
|
||||||
@ -24,36 +32,21 @@ export class BatteryService {
|
|||||||
let afterDate = new Date();
|
let afterDate = new Date();
|
||||||
afterDate.setDate(afterDate.getDate() - 1);
|
afterDate.setDate(afterDate.getDate() - 1);
|
||||||
|
|
||||||
this.firestore.collection('Battery').doc('170614D').collection('data', ref => ref.where('timestamp', '>=', afterDate).orderBy('timestamp')).valueChanges().subscribe(data => {
|
this.firestore.collection('Battery').doc('170614D').collection<Battery>('data', ref => ref.where('timestamp', '>=', afterDate.getTime()).orderBy('timestamp')).valueChanges().subscribe(data => {
|
||||||
this.batteries = data.reduce((acc, row) => {
|
this.modules = data.reduce((acc: any, row) => {
|
||||||
row.payload.forEach((data, i) => {
|
Object.keys(row.modules).forEach(module => {
|
||||||
if(!acc[i]) acc[i] = [];
|
if(!acc[module]) acc[module] = [];
|
||||||
acc[i].push(Object.assign(data, {timestamp: row.timestamp.toDate()}));
|
acc[module].push(Object.assign(row.modules[module], {timestamp: row.timestamp}));
|
||||||
});
|
});
|
||||||
return acc;
|
return acc;
|
||||||
}, []).map((module, i) => {
|
}, {});
|
||||||
const last = module[module.length - 1];
|
|
||||||
return {
|
|
||||||
charge: last.charge,
|
|
||||||
chargeHistory: module.map(row => ({name: row.timestamp, value: row.charge})),
|
|
||||||
lastUpdate: last.timestamp,
|
|
||||||
name: `Module ${i + 1}`,
|
|
||||||
temp: last.temp,
|
|
||||||
tempHistory: module.map(row => ({name: row.timestamp, value: row.temp}))
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
this.lastCharge.push(this.charge);
|
let last = data[data.length - 1];
|
||||||
this.lastCharge.splice(0, this.lastCharge.length - 3);
|
this.lastUpdate = last.timestamp;
|
||||||
this.lastUpdate = this.batteries[0].lastUpdate;
|
this.charge = last.voltage;
|
||||||
this.charge = this.batteries.reduce((acc, module) => acc + module.charge, 0) / 2;
|
this.temp = last.temperature;
|
||||||
this.temp = this.batteries.reduce((acc, module) => acc + module.temp, 0) / this.batteries.length;
|
this.uptime = last.uptime;
|
||||||
|
this.data.next(data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setRelayMode(mode?: string) {
|
|
||||||
if(mode == 'null') this.firestore.collection('Battery').doc('170614D').update({config: {relayMode: null}});
|
|
||||||
else if(mode == 'true') this.firestore.collection('Battery').doc('170614D').update({config: {relayMode: true}});
|
|
||||||
else if(mode == 'false') this.firestore.collection('Battery').doc('170614D').update({config: {relayMode: false}});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
30
src/app/battery/battery.ts
Normal file
30
src/app/battery/battery.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
export interface Battery {
|
||||||
|
ampHours: number;
|
||||||
|
avgCellVoltage: number;
|
||||||
|
capacity: number;
|
||||||
|
current: number;
|
||||||
|
lifetimeCharge: number;
|
||||||
|
lifetimeDischarge: number;
|
||||||
|
maxCellVoltage: number;
|
||||||
|
maxDischargeCurrent: number;
|
||||||
|
maxVoltage: number;
|
||||||
|
minCellVoltage: number;
|
||||||
|
minVoltage: number;
|
||||||
|
modules: {[key: number]: {
|
||||||
|
cells: {[key: number]: number}
|
||||||
|
negativeTemperature: number;
|
||||||
|
positiveTemperature: number;
|
||||||
|
temperature: number;
|
||||||
|
voltage: number;
|
||||||
|
}},
|
||||||
|
negativeContactor: boolean,
|
||||||
|
positiveContactor: boolean,
|
||||||
|
power: number;
|
||||||
|
soc: number;
|
||||||
|
temperature: number;
|
||||||
|
timestamp: number;
|
||||||
|
uptime: string;
|
||||||
|
version: number;
|
||||||
|
voltage: number;
|
||||||
|
wattHours: number;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user