File

src/app/components/body/battery-test/show-test-result/show-test-result.component.ts

Index

Properties

Properties

chartData
chartData: | any
Type : | any
Optional
ChartOptions
ChartOptions: | any
Type : | any
Optional
ChartType
ChartType: ChartType
Type : ChartType
name
name: string
Type : string
Optional
import { ComponentStoreService } from './../../../../services/component-store.service';
import {
  _TestResultDeep,
  QuickResponseMeasurement,
  MeasuredParameters,
  SensorObj,
} from './../../../../models/TestResult';
import { TestChamberService } from 'src/app/services/test-chamber.service';
import { of, Subscription, switchMap } from 'rxjs';
import { ActivatedRoute, Router } from '@angular/router';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { saveAs } from 'file-saver';

import { ChartConfiguration, ChartType } from 'chart.js';
import {
  Component,
  OnInit,
  OnDestroy,
  QueryList,
  ViewChildren,
  ViewChild,
} from '@angular/core';
import { BaseChartDirective } from 'ng2-charts';
import { Location } from '@angular/common';

interface Charts {
  name?: string;
  chartData?: ChartConfiguration['data'] | any;
  ChartOptions?: ChartConfiguration['options'] | any;
  ChartType: ChartType;
}

@Component({
  selector: 'app-show-test-result',
  templateUrl: './show-test-result.component.html',
  styleUrls: ['./show-test-result.component.css'],
})
export class ShowTestResultComponent implements OnInit, OnDestroy {
  subs: Subscription[] = [];
  testInfo?: _TestResultDeep;
  showChart: boolean = false;
  allCharts: Charts[] = [];
  quickResponses: QuickResponseMeasurement[] = [];
  chartSub?: Subscription;
  testId?: string | null;
  chamberId?: string | null;
  measurementUpdateIntervalId: any;
  testInfoIntervalId: any;
  testInfoSub?: Subscription;
  modalTitle?: string;
  modalBody?: string;
  isConnected: boolean = false;
  isConnectedIntervalId: any;
  connSub?: Subscription;
  maxNoOfDataPoints: number = 1000;
  targetSampleSize: number = 700;
  updatedUptoIndex = 0;

  @ViewChildren(BaseChartDirective) charts?: QueryList<BaseChartDirective>;
  @ViewChild('myModal') modal: any;

  constructor(
    private route: ActivatedRoute,
    private _testChamberService: TestChamberService,
    private _componentStoreService: ComponentStoreService,
    private modalService: NgbModal,
    private location: Location,
    private router: Router
  ) {}

  toggleShowChart() {
    this.showChart = !this.showChart;
    clearInterval(this.measurementUpdateIntervalId);
    this.chartSub?.unsubscribe();
  }

  onClickChild(event: MouseEvent) {
    event.stopPropagation();
  }

  onClickParent(event: MouseEvent) {
    this.toggleShowChart();
  }

  showChartView(channelNo: number) {
    this.allCharts = [];
    this.toggleShowChart();
    const channelQuickResponse = this.quickResponses.find(
      (res) => res.channelNo === channelNo
    );
    if (channelQuickResponse) {
      this.createChart(channelQuickResponse);
      this.keepUpdatingChart(channelQuickResponse);
    } else {
      const sub = this._testChamberService
        .getQuickResponse(
          this.chamberId as any,
          this.testId as any,
          channelNo as any
        )
        .subscribe((data: QuickResponseMeasurement) => {
          this.createChart(data);
          this.quickResponses.push(data);
          if (data.statusCh === 'Running') {
            //if channel is running then only keep updating the channel
            this.keepUpdatingChart(data);
          }
          sub.unsubscribe();
        });
    }
  }

  createChart(channelQuickResponse: QuickResponseMeasurement) {
    let blankData: MeasuredParameters = {};
    blankData.time = [];
    if (
      channelQuickResponse.measuredParameters.current &&
      channelQuickResponse.measuredParameters.current.length > 0
    ) {
      blankData.current = [];
      let chart: Charts = {
        name: 'Current',
        chartData: {
          datasets: [
            {
              data: blankData.current,
              label: 'Current',
            },
          ],
          labels: blankData.time,
        },
        ChartOptions: {
          scales: {
            xAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Time(S)',
                },
              },
            ],
            yAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Cell Current (A)',
                },
              },
            ],
          },
        },
        ChartType: 'line',
      };
      this.allCharts.push(chart);
    }
    if (
      channelQuickResponse.measuredParameters.voltage &&
      channelQuickResponse.measuredParameters.voltage.length > 0
    ) {
      blankData.voltage = [];
      let chart: Charts = {
        name: 'Voltage',
        chartData: {
          datasets: [
            {
              data: blankData.voltage,
              label: 'Voltage',
            },
          ],
          labels: blankData.time,
        },
        ChartOptions: {
          scales: {
            xAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Time(S)',
                },
              },
            ],
            yAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Cell Voltage(V)',
                },
              },
            ],
          },
        },
        ChartType: 'line',
      };
      this.allCharts.push(chart);
    }
    if (
      channelQuickResponse.measuredParameters.chamberTemp &&
      channelQuickResponse.measuredParameters.chamberTemp.length > 0
    ) {
      blankData.chamberTemp = [];
      let chart: Charts = {
        name: 'Chamber Temperature',
        chartData: {
          datasets: [
            {
              data: blankData.chamberTemp,
              label: 'Chamber Temperature',
            },
          ],
          labels: blankData.time,
        },
        ChartOptions: {
          scales: {
            xAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Time(S)',
                },
              },
            ],
            yAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Chamber Temperature (°C)',
                },
              },
            ],
          },
        },
        ChartType: 'line',
      };
      this.allCharts.push(chart);
    }
    if (
      channelQuickResponse.measuredParameters.chamberHum &&
      channelQuickResponse.measuredParameters.chamberHum.length > 0
    ) {
      blankData.chamberHum = [];
      let chart: Charts = {
        name: 'Chamber Humidity',
        chartData: {
          datasets: [
            {
              data: blankData.chamberHum,
              label: 'Chamber Humidity',
            },
          ],
          labels: blankData.time,
        },
        ChartOptions: {
          scales: {
            xAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Time(S)',
                },
              },
            ],
            yAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Chamber Humidity(%)',
                },
              },
            ],
          },
        },
        ChartType: 'line',
      };
      this.allCharts.push(chart);
    }

    if (
      channelQuickResponse.measuredParameters.cellTemp &&
      channelQuickResponse.measuredParameters.cellTemp.length > 0
    ) {
      blankData.cellTemp = [];
      let chart: Charts = {
        name: 'Cell Temperature',
        chartData: {
          datasets: [],
          labels: blankData.time,
        },
        ChartOptions: {
          scales: {
            xAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Time(S)',
                },
              },
            ],
            yAxes: [
              {
                scaleLabel: {
                  display: true,
                  labelString: 'Cell Temperatures(°C)',
                },
              },
            ],
          },
        },
        ChartType: 'line',
      };
      channelQuickResponse.measuredParameters.cellTemp.forEach(
        (tempObj: SensorObj) => {
          let d: SensorObj = { sensorId: tempObj.sensorId, values: [] };
          blankData.cellTemp?.push(d);
          chart.chartData.datasets.push({
            data: d.values,
            label: 'Sensor' + tempObj.sensorId,
          });
        }
      );
      this.allCharts.push(chart);
    }
    this.appendNewData(blankData, channelQuickResponse.measuredParameters);
  }

  keepUpdatingChart(channelQuickResponse: QuickResponseMeasurement) {
    clearInterval(this.measurementUpdateIntervalId);
    this.measurementUpdateIntervalId = setInterval(() => {
      this.chartSub = this._testChamberService
        .getQuickResponse(
          this.chamberId as any,
          this.testId as any,
          channelQuickResponse.channelNo as any,
          this.updatedUptoIndex - 1
        )
        .subscribe((data: any) => {
          this.appendNewData(
            channelQuickResponse.measuredParameters,
            data.measuredParameters as MeasuredParameters
          );
          this.charts?.forEach((chart) => chart.update());
          this.chartSub?.unsubscribe();
          if (data.status === 'Completed' || data.status === 'Stopped') {
            clearInterval(this.measurementUpdateIntervalId);
          }
        });
    }, 2000);
  }

  appendNewData(
    prevMeasurements: MeasuredParameters,
    newMeasurements: MeasuredParameters
  ) {
    if (newMeasurements.current && newMeasurements.current?.length > 0) {
      prevMeasurements.current?.push(...newMeasurements.current);
    }
    if (newMeasurements.voltage && newMeasurements.voltage?.length > 0) {
      prevMeasurements.voltage?.push(...newMeasurements.voltage);
    }
    if (newMeasurements.chamberHum && newMeasurements.chamberHum?.length > 0) {
      prevMeasurements.chamberHum?.push(...newMeasurements.chamberHum);
    }
    if (
      newMeasurements.chamberTemp &&
      newMeasurements.chamberTemp?.length > 0
    ) {
      prevMeasurements.chamberTemp?.push(...newMeasurements.chamberTemp);
    }
    if (newMeasurements.time && newMeasurements.time?.length > 0) {
      prevMeasurements.time?.push(...newMeasurements.time);
    }
    newMeasurements.cellTemp?.forEach((tempObjNew, i) => {
      const tempObjOld = prevMeasurements.cellTemp?.find(
        (tempObj) => tempObj.sensorId === tempObjNew.sensorId
      );
      if (tempObjOld) {
        tempObjOld.values.push(...tempObjNew.values);
      } else {
        prevMeasurements.cellTemp?.push(tempObjNew);
      }
    });
    this.updatedUptoIndex += newMeasurements.time
      ? newMeasurements.time.length
      : 0;

    if (
      prevMeasurements.time &&
      prevMeasurements.time.length > this.maxNoOfDataPoints
    ) {
      // Use sampling technique
      const samplingRate = prevMeasurements.time.length / this.targetSampleSize;

      this.sampleData(prevMeasurements.time, samplingRate);
      this.sampleData(prevMeasurements.current, samplingRate);
      this.sampleData(prevMeasurements.voltage, samplingRate);
      this.sampleData(prevMeasurements.chamberHum, samplingRate);
      this.sampleData(prevMeasurements.chamberTemp, samplingRate);

      prevMeasurements.cellTemp?.forEach((tempObj) => {
        this.sampleData(tempObj.values, samplingRate);
      });
    }
  }

  sampleData(data: number[] | undefined, samplingRate: number): void {
    if (!data || samplingRate <= 1) {
      return;
    }

    let writeIndex = 0;
    for (
      let readIndex = 0;
      readIndex < data.length;
      readIndex += samplingRate
    ) {
      data[writeIndex++] = data[Math.floor(readIndex)];
    }

    data.length = writeIndex;
  }

  ngOnInit(): void {
    //console.log(this.router.url);
    if (window.location.hostname != 'localhost') {
      this.location.replaceState('./'); //on prod
    }
    const os$ = this.route.paramMap.pipe(
      switchMap((params) => {
        this.testId = params.get('testId');
        this.chamberId = params.get('chamberId');
        return this._testChamberService.getTestData(
          this.chamberId as any,
          this.testId as any
        );
      })
    );
    this.testInfoSub = os$.subscribe((testInfo: _TestResultDeep) => {
      this.testInfo = testInfo;
      this.testInfoSub?.unsubscribe();
    });

    this.testInfoIntervalId = setInterval(() => {
      if (this.testId && this.chamberId) {
        this.testInfoSub?.unsubscribe();
        this.testInfoSub = this._testChamberService
          .getTestData(this.chamberId as any, this.testId as any)
          .subscribe((testInfo) => {
            this.testInfo = testInfo;
            this.testInfoSub?.unsubscribe();
            if (
              this.testInfo?.status === 'Completed' ||
              this.testInfo?.status === 'Stopped'
            ) {
              clearInterval(this.testInfoIntervalId);
            }
          });
      }
    }, 10000);

    this.updateConnection();

    this.isConnectedIntervalId = setInterval(
      () => this.updateConnection(),
      10000
    );
  }

  deleteTest() {
    this.modalTitle = 'Alert';
    this.modalBody =
      'Are you sure you want to delete all the information related to this experiment? Once you do it, you can never retrieve it.';
    this.modalService.open(this.modal, { centered: true }).result.then(
      (result) => {
        //console.log('accepted');
        this._testChamberService
          .deleteTest(this.chamberId as any, this.testId as any)
          .subscribe((res) => {
            let url = '';
            let path = this.router.url;
            if (path.indexOf('view-all') > 0) {
              url = '../../../../';
            } else {
              url = '../../../';
            }
            this.router.navigate([url], {
              relativeTo: this.route,
              skipLocationChange: true,
            });
          });
      },
      (reason) => {
        //console.log('closed');
      }
    );
  }

  updateConnection() {
    if (this.chamberId) {
      this.connSub?.unsubscribe();
      this.connSub = this._testChamberService
        .getConnectionStatus(this.chamberId as any)
        .subscribe({
          next: (pay: any) => {
            this.isConnected = pay.isConnected;
            this.connSub?.unsubscribe();
          },
          error: (err) => {
            this.isConnected = false;
          },
        });
    }
  }

  edit() {}
  play() {
    this.changeStatus('Running');
  }
  pause() {
    this.changeStatus('Paused');
  }
  stop() {
    this.modalTitle = 'Alert';
    this.modalBody =
      'Are you sure you want to stop the experiment? Once you stop it, you can never start it again.';
    this.modalService.open(this.modal, { centered: true }).result.then(
      (result) => {
        //console.log('accepted');
        this.changeStatus('Stopped');
      },
      (reason) => {
        //console.log('closed');
      }
    );
  }
  changeStatus(status: string | null) {
    const sub = this._testChamberService
      .forceStatus(this.chamberId as any, this.testId as any, status)
      .subscribe((res: any) => {
        if (res.acknowledged) {
          this._componentStoreService.sendToastMsg({
            msg: 'Status has been sent to the cloud. Wait for the Test Chamber to reflect the status',
            timeOut: 10000,
            color: 'black',
          });
        }
      });
    this.subs.push(sub);
  }

  download(channelNo: number) {
    this._testChamberService
      .downloadTestResult(this.chamberId as any, this.testId as any, channelNo)
      .subscribe((response) => {
        const blob = new Blob([response.body], {
          type: 'text/csv;charset=utf-8;',
        });
        const url = URL.createObjectURL(blob);
        const contentDispositionHeader = response.headers.get(
          'content-disposition'
        );
        const filename = contentDispositionHeader
          ? contentDispositionHeader.split('filename=')[1].replace(/"/g, '')
          : 'testResult.csv';
        saveAs(url, filename);
      });
  }
  ngOnDestroy(): void {
    this.subs.forEach((sub) => sub.unsubscribe());
    this.testInfoSub?.unsubscribe();
    this.chartSub?.unsubscribe();
    clearInterval(this.measurementUpdateIntervalId);
    clearInterval(this.testInfoIntervalId);
    this.connSub?.unsubscribe();
    clearInterval(this.isConnectedIntervalId);
  }
}

results matching ""

    No results matching ""