Updated site to use new BMS data

This commit is contained in:
Zakary Timson 2019-12-27 01:13:31 -05:00
parent 0f07821317
commit 5c4bb8b515
4 changed files with 85 additions and 55 deletions

View File

@ -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>
</div> <h6 class="mb-0">Uptime: {{batteryService.uptime}}</h6>
<div class="d-flex flex-column align-content-center mb-3">
<div>
<h5><mat-icon *ngIf="locked" class="mr-1">lock</mat-icon>Cooling Fans</h5>
</div> </div>
<div> <div>
<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="24" [checked]="true">24 Hours</mat-button-toggle>
<mat-button-toggle value="null">Auto</mat-button-toggle> <mat-button-toggle value="12">12 Hours</mat-button-toggle>
<mat-button-toggle value="true">On</mat-button-toggle> <mat-button-toggle value="6">6 Hours</mat-button-toggle>
<mat-button-toggle value="false">Off</mat-button-toggle>
</mat-button-toggle-group> </mat-button-toggle-group>
</div> </div>
</div> </div>
</div> <mat-card class="mt-2" *ngFor="let battery of batteries; let i = index">
<mat-card class="mt-2" *ngFor="let battery of batteryService.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"

View File

@ -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() { }

View File

@ -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}});
}
} }

View 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;
}