Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Component, effect, inject, input, OnInit } from '@angular/core';
import { Segment } from 'src/utils/bms.utils';
import { HeatMapService, HeatMapView } from 'src/services/heat-map.service';
import { AlphaCells, BetaCells, CellReading, CellService } from 'src/services/cell.service';
import { CellReading, CellService } from 'src/services/cell.service';
import { DropdownOption, SelectorConfig } from 'src/components/select-dropdown/select-dropdown.component';
import { DialogService } from 'primeng/dynamicdialog';
import { CellViewComponent } from '../cell-view/cell-view.component';
Expand All @@ -25,8 +25,8 @@ export class CellByCellHeatMapComponent implements OnInit {
private heatMapService = inject(HeatMapService);
private dialogService = inject(DialogService);
currentSegment = input.required<Segment>();
alphaCells!: Readonly<AlphaCells>;
betaCells!: Readonly<BetaCells>;
alphaCells!: Readonly<CellReading[]>;
betaCells!: Readonly<CellReading[]>;
view = HeatMapView.Voltage;
selectedCell: CellReading | undefined = undefined;
cellViewSelectOptions: DropdownOption[] = [
Expand Down
83 changes: 28 additions & 55 deletions angular-client/src/services/cell.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Injectable } from '@angular/core';
import { BMS_CONFIG } from 'src/utils/bms.config';
import { Chip, numToSegmentType, Segment } from 'src/utils/bms.utils';
import Storage from './storage.service';
import {
Expand All @@ -22,14 +23,11 @@ export type CellReading = {
cellNumbers: [number, number] | undefined;
};

/* 7 alpha cell reading (for 14 cells) (if we only record data for every other CellReading, or anything like that, adjacents will contain the same data for field) */
export type AlphaCells = [CellReading, CellReading, CellReading, CellReading, CellReading, CellReading, CellReading];
export type PerSegmentAlphaCells = [AlphaCells, AlphaCells, AlphaCells, AlphaCells, AlphaCells];
const createSegmentAlphaCells = (segment: number): AlphaCells => {
const createSegmentCells = (segment: number, chip: Chip, count: number): CellReading[] => {
return Array.from(
{ length: 7 },
{ length: count },
(): CellReading => ({
chip: Chip.Alpha,
chip,
segment,
temp: undefined,
volt1: undefined,
Expand All @@ -38,55 +36,23 @@ const createSegmentAlphaCells = (segment: number): AlphaCells => {
balancing2: undefined,
cellNumbers: undefined
})
) as AlphaCells; // Type assertion here is safe due to length enforcement
);
};
const startingPerSegmentAlphaCells: PerSegmentAlphaCells = [
createSegmentAlphaCells(0),
createSegmentAlphaCells(1),
createSegmentAlphaCells(2),
createSegmentAlphaCells(3),
createSegmentAlphaCells(4)
];

/* 11 beta cells (if we only record data for every other CellReading, or anything like that, adjacents will contain the same data for field) */
// Explicit tuple types
export type BetaCells = [CellReading, CellReading, CellReading, CellReading, CellReading, CellReading];

export type PerSegmentBetaCells = [BetaCells, BetaCells, BetaCells, BetaCells, BetaCells];

// Utility function to create a BetaCells array for a specific segment
const createSegmentBetaCells = (segment: number): BetaCells => {
return Array.from(
{ length: 6 },
(): CellReading => ({
chip: Chip.Beta,
segment,
temp: undefined,
volt1: undefined,
volt2: undefined,
balancing1: undefined,
balancing2: undefined,
cellNumbers: undefined
})
) as BetaCells;

const createPerSegmentCells = (chip: Chip, cellsPerSegment: number): CellReading[][] => {
return Array.from({ length: BMS_CONFIG.NUM_SEGMENTS }, (_, seg) => createSegmentCells(seg, chip, cellsPerSegment));
};

// Create the main structure
const startingPerSegmentBetaCells: PerSegmentBetaCells = [
createSegmentBetaCells(0),
createSegmentBetaCells(1),
createSegmentBetaCells(2),
createSegmentBetaCells(3),
createSegmentBetaCells(4)
];
const startingPerSegmentAlphaCells: CellReading[][] = createPerSegmentCells(Chip.Alpha, BMS_CONFIG.ALPHA_THERM_COUNT);
const startingPerSegmentBetaCells: CellReading[][] = createPerSegmentCells(Chip.Beta, BMS_CONFIG.BETA_THERM_COUNT);

@Injectable({
providedIn: 'root'
})
export class CellService {
private storageService: Storage;
private perSegmentAlphaCells: PerSegmentAlphaCells;
private perSegmentBetaCells: PerSegmentBetaCells;
private perSegmentAlphaCells: CellReading[][];
private perSegmentBetaCells: CellReading[][];

constructor(storageService: Storage) {
this.storageService = storageService;
Expand Down Expand Up @@ -148,7 +114,10 @@ export class CellService {
const constIndex = index;
this.storageService.get(topics.betaTemp(segmentNumber, therm)).subscribe((data) => {
const tempBtwnTwoCells = parseFloat(data.values[0]);
segmentBetaCells[constIndex].cellNumbers = [constIndex * 2, Math.min(constIndex * 2 + 1, 10)];
segmentBetaCells[constIndex].cellNumbers = [
constIndex * 2,
Math.min(constIndex * 2 + 1, BMS_CONFIG.BETA_VOLT_COUNT - 1)
];

segmentBetaCells[constIndex].temp = tempBtwnTwoCells;
});
Expand All @@ -159,7 +128,10 @@ export class CellService {
const cellIndex = Math.floor(constIndex / 2);
this.storageService.get(topics.betaVolt(segmentNumber, volt)).subscribe((data) => {
const voltage = parseFloat(data.values[0]);
segmentBetaCells[cellIndex].cellNumbers = [cellIndex * 2, Math.min(cellIndex * 2 + 1, 10)];
segmentBetaCells[cellIndex].cellNumbers = [
cellIndex * 2,
Math.min(cellIndex * 2 + 1, BMS_CONFIG.BETA_VOLT_COUNT - 1)
];
if (constIndex % 2 === 0) {
segmentBetaCells[cellIndex].volt1 = voltage;
} else {
Expand All @@ -173,7 +145,10 @@ export class CellService {
const cellIndex = Math.floor(constIndex / 2);
this.storageService.get(topics.betaBurning(segmentNumber, burn)).subscribe((data) => {
const balancing = parseInt(data.values[0]) === 1;
segmentBetaCells[cellIndex].cellNumbers = [cellIndex * 2, Math.min(cellIndex * 2 + 1, 10)];
segmentBetaCells[cellIndex].cellNumbers = [
cellIndex * 2,
Math.min(cellIndex * 2 + 1, BMS_CONFIG.BETA_VOLT_COUNT - 1)
];
if (constIndex % 2 === 0) {
segmentBetaCells[cellIndex].balancing1 = balancing;
} else {
Expand All @@ -184,21 +159,19 @@ export class CellService {
});
};

getAllAlphaCells = (): Readonly<PerSegmentAlphaCells> => {
getAllAlphaCells = (): Readonly<CellReading[][]> => {
return this.perSegmentAlphaCells;
};

// 0 2 4 6 8 10 12
getAlphaCellsBySegment = (segment: number): Readonly<AlphaCells> => {
getAlphaCellsBySegment = (segment: number): Readonly<CellReading[]> => {
return this.perSegmentAlphaCells[segment];
};

getAllBetaCells = (): Readonly<PerSegmentBetaCells> => {
getAllBetaCells = (): Readonly<CellReading[][]> => {
return this.perSegmentBetaCells;
};

// 0 2 4 6 8 10
getBetaCellsBySegment = (segment: number): Readonly<BetaCells> => {
getBetaCellsBySegment = (segment: number): Readonly<CellReading[]> => {
return this.perSegmentBetaCells[segment];
};
}
16 changes: 16 additions & 0 deletions angular-client/src/utils/bms.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* Central BMS configuration — change counts here to match the current accumulator.
* All segment/cell arrays and topic subscriptions derive from these values.
*
* This file is intentionally free of imports to avoid circular dependency issues
* between bms.utils.ts and topic.utils.ts.
*/
export const BMS_CONFIG = {
NUM_SEGMENTS: 5,
ALPHA_VOLT_COUNT: 14,
BETA_VOLT_COUNT: 11,
ALPHA_THERM_COUNT: 7,
BETA_THERM_COUNT: 6,
ALPHA_BURN_COUNT: 14,
BETA_BURN_COUNT: 11
} as const;
75 changes: 22 additions & 53 deletions angular-client/src/utils/bms.utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { topics } from './topic.utils';
export { BMS_CONFIG } from './bms.config';
import { BMS_CONFIG } from './bms.config';

export enum Chip {
Alpha = 0,
Expand All @@ -14,18 +16,15 @@ export const chipToString = (chip: Chip, singleLetter = false): string => {
throw new Error('Invalid chip type ' + chip);
}
};
export enum Segment {
Segment0 = 0,
Segment1 = 1,
Segment2 = 2,
Segment3 = 3,
Segment4 = 4
}
export const allSegments = [Segment.Segment0, Segment.Segment1, Segment.Segment2, Segment.Segment3, Segment.Segment4];

/** Segment is a plain numeric index (0-based). */
export type Segment = number;

export const allSegments: Segment[] = Array.from({ length: BMS_CONFIG.NUM_SEGMENTS }, (_, i) => i);

export const numToSegmentType = (segment: number): Segment => {
const segmentType: Segment | undefined = segment as Segment;
if (segmentType !== undefined) {
return segmentType;
if (segment >= 0 && segment < BMS_CONFIG.NUM_SEGMENTS) {
return segment;
}
throw new Error('Invalid segment number ' + segment);
};
Expand All @@ -37,48 +36,18 @@ export type SegmentInfo = {
voltageKey: string;
};

export const segment0: SegmentInfo = {
segmentTempKey: topics.segmentTemp(Segment.Segment0),
alphaChipTempKey: topics.dieTemp(Segment.Segment0, Chip.Alpha),
betaChipTempKey: topics.dieTemp(Segment.Segment0, Chip.Beta),
voltageKey: topics.segmentVoltage(Segment.Segment0)
};

export const segment1: SegmentInfo = {
segmentTempKey: topics.segmentTemp(Segment.Segment1),
alphaChipTempKey: topics.dieTemp(Segment.Segment1, Chip.Alpha),
betaChipTempKey: topics.dieTemp(Segment.Segment1, Chip.Beta),
voltageKey: topics.segmentVoltage(Segment.Segment1)
};

export const segment2: SegmentInfo = {
segmentTempKey: topics.segmentTemp(Segment.Segment2),
alphaChipTempKey: topics.dieTemp(Segment.Segment2, Chip.Alpha),
betaChipTempKey: topics.dieTemp(Segment.Segment2, Chip.Beta),
voltageKey: topics.segmentVoltage(Segment.Segment2)
};

export const segment3: SegmentInfo = {
segmentTempKey: topics.segmentTemp(Segment.Segment3),
alphaChipTempKey: topics.dieTemp(Segment.Segment3, Chip.Alpha),
betaChipTempKey: topics.dieTemp(Segment.Segment3, Chip.Beta),
voltageKey: topics.segmentVoltage(Segment.Segment3)
};

export const segment4: SegmentInfo = {
segmentTempKey: topics.segmentTemp(Segment.Segment4),
alphaChipTempKey: topics.dieTemp(Segment.Segment4, Chip.Alpha),
betaChipTempKey: topics.dieTemp(Segment.Segment4, Chip.Beta),
voltageKey: topics.segmentVoltage(Segment.Segment4)
};

export const segmentInfoMap = {
[Segment.Segment0]: segment0,
[Segment.Segment1]: segment1,
[Segment.Segment2]: segment2,
[Segment.Segment3]: segment3,
[Segment.Segment4]: segment4
};
/** Dynamically generated map of segment index → SegmentInfo topic keys. */
export const segmentInfoMap: Record<Segment, SegmentInfo> = Object.fromEntries(
allSegments.map((seg) => [
seg,
{
segmentTempKey: topics.segmentTemp(seg),
alphaChipTempKey: topics.dieTemp(seg, Chip.Alpha),
betaChipTempKey: topics.dieTemp(seg, Chip.Beta),
voltageKey: topics.segmentVoltage(seg)
}
])
);

export const getConnectionDotStatusColor = (voltage: number): string => {
if (voltage <= 375) {
Expand Down
Loading