Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Dataset description and Signal K Tab #339

Merged
merged 1 commit into from
Mar 22, 2024
Merged
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
14 changes: 10 additions & 4 deletions src/app/core/services/signalk.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { cloneDeep } from 'lodash-es';
import { Injectable } from '@angular/core';
import { Observable , BehaviorSubject, Subscription, ReplaySubject } from 'rxjs';
import { IPathData, IPathValueData, IPathMetaData, IDefaultSource, IMeta } from "../interfaces/app-interfaces";
import { IPathData, IPathValueData, IPathMetaData, IMeta } from "../interfaces/app-interfaces";
import { IZone, IZoneState } from '../interfaces/app-settings.interfaces';
import { AppSettingsService } from './app-settings.service';
import { SignalKDeltaService } from './signalk-delta.service';
Expand Down Expand Up @@ -45,6 +45,11 @@ interface pathRegistration {
subject: BehaviorSubject<pathRegistrationValue>;
}

export interface IDeltaUpdate {
value: number;
timestamp: number;
}

@Injectable({
providedIn: 'root'
})
Expand All @@ -63,7 +68,7 @@ export class SignalKService {

// Performance stats
private _deltaUpdatesCounter: number = null;
private _deltaUpdatesSubject: ReplaySubject<number> = new ReplaySubject(60);
private _deltaUpdatesSubject: ReplaySubject<IDeltaUpdate> = new ReplaySubject(60);

defaultUnits: IUnitDefaults;
defaultUnitsSub: Subscription;
Expand All @@ -80,7 +85,8 @@ export class SignalKService {
// Emit Delta message update counter every second
setInterval(() => {
if (this._deltaUpdatesCounter !== null) {
this._deltaUpdatesSubject.next(this._deltaUpdatesCounter);
let update: IDeltaUpdate = {timestamp: Date.now(), value: this._deltaUpdatesCounter}
this._deltaUpdatesSubject.next(update);
this._deltaUpdatesCounter = 0;
};
}, 1000);
Expand Down Expand Up @@ -123,7 +129,7 @@ export class SignalKService {
* @return {*} {Observable<number>} Count of delta messages received in the last second.
* @memberof SignalKService
*/
public getSignalkDeltaUpdateStatistics(): Observable<number> {
public getSignalkDeltaUpdateStatistics(): Observable<IDeltaUpdate> {
return this._deltaUpdatesSubject.asObservable();
}

Expand Down
4 changes: 3 additions & 1 deletion src/app/settings/datasets/datasets.component.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<div class="mat-typography">
<form name="existingDataSet" #existingDataSet="ngForm">
<h1>Datasets Configuration</h1>
<p class="mat-card-subtitle">Create historical datasets to record data values over time and display them on charts with the Data Chart widget.</p>
<p class="mat-card-subtitle">Datasets are background processes that record path values over time. Combine with the Data Chart widget they offer
data visualization graphs. Care should be applied to manage Datasets and evaluate system resources usage.
</p>
<mat-form-field class="filter">
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event)" placeholder="Ex: navigation" value="" #input>
Expand Down
4 changes: 2 additions & 2 deletions src/app/settings/datasets/datasets.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export class SettingsDatasetsModalComponent implements OnInit {

ngOnInit() {
if (this.dataset) {
this.titleDialog = "Edit dataset";
this.titleDialog = "Edit Dataset";
this.formDataset = this.dataset;

let pathObject = this.SignalKService.getPathObject(this.formDataset.path);
Expand All @@ -175,7 +175,7 @@ export class SettingsDatasetsModalComponent implements OnInit {
}

} else {
this.titleDialog = "Add dataset";
this.titleDialog = "Add Dataset";
this.formDataset = this.newDataset;
}

Expand Down
70 changes: 47 additions & 23 deletions src/app/settings/datasets/datasets.modal.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,30 +55,54 @@ <h2 mat-dialog-title> {{titleDialog}} </h2>
</div>
</mat-step>
<mat-step>
<ng-template matStepLabel>Time Scale</ng-template>
<ng-template matStepLabel>Sampling</ng-template>
<div class="tab-content">
<mat-form-field class="full-width" style="margin-bottom: 10px;">
<mat-label>Time Scale</mat-label>
<mat-select
placeholder="Select dataset time scale"
[(ngModel)]="formDataset.timeScaleFormat"
name="timeScaleFormat"
required>
<mat-option value="hour">Hours</mat-option>
<mat-option value="minute">Minutes</mat-option>
<mat-option value="second">Seconds</mat-option>
</mat-select>
</mat-form-field>

<mat-form-field style="margin-bottom: 10px;">
<mat-label>Duration</mat-label>
<input matInput type="number"
min="1" max="60" step="1"
placeholder="Enter or select number..."
name="period"
[(ngModel)]="formDataset.period"
required>
</mat-form-field>
<span class="mat-subtitle-1">Time Scales</span>
<div class="flex-container" style="margin-top: 10px;">
<div class="flex-field-50">
<mat-form-field class="full-width">
<mat-label>Scale</mat-label>
<mat-select
placeholder="Select dataset time scale"
[(ngModel)]="formDataset.timeScaleFormat"
name="timeScaleFormat"
required>
<mat-option value="hour">Hours</mat-option>
<mat-option value="minute">Minutes</mat-option>
<mat-option value="second">Seconds</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="flex-field-50">
<mat-form-field class="full-width">
<mat-label>Duration</mat-label>
<input matInput type="number"
min="1" max="60" step="1"
placeholder="Enter or select number..."
name="period"
[(ngModel)]="formDataset.period"
required>
</mat-form-field>
</div>
</div>
<p class="mat-caption">Time scales define the data sampling rate and overall Dataset level
of precision. Chose a Time Scale that is targeted to you intended usage.
Shorter Time Scales have higher system resources
costs, for both the data capture and widget rendering process.
</p>
<ul class="mat-caption">
<li>Hours: per minute sampling rate. Intended for long sampling periods when slow
refresh rate is acceptable and system resource usage should be minimized. Grafana is
the perfect alternative to this Time Scale.
</li>
<li>Minutes: per second sampling rate. Meant for trends observations such wind
speed, depth, solar power, voltage, etc., when up to the second realtime updates are
not required.
</li>
<li>Secondes: 200ms sampling rate. Intended for use cases where user may act upon realtime
information such as when racing.
</li>
</ul>
</div>
<mat-divider></mat-divider>
<div class="buttons">
Expand Down
42 changes: 23 additions & 19 deletions src/app/settings/signalk/signalk.component.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ViewChild, ElementRef, Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription, pipe, timestamp } from 'rxjs';
import { Subscription } from 'rxjs';
import { AppSettingsService } from '../../core/services/app-settings.service';
import { IConnectionConfig } from "../../core/interfaces/app-settings.interfaces";
import { SignalKConnectionService, IEndpointStatus } from '../../core/services/signalk-connection.service';
import { SignalKService } from '../../core/services/signalk.service';
import { IDeltaUpdate, SignalKService } from '../../core/services/signalk.service';
import { SignalKDeltaService, IStreamStatus } from '../../core/services/signalk-delta.service';
import { AuthenticationService, IAuthorizationToken } from '../../core/services/authentication.service';
import { SignalkRequestsService } from '../../core/services/signalk-requests.service';
Expand Down Expand Up @@ -49,7 +49,7 @@ import ChartStreaming from '@robloche/chartjs-plugin-streaming';

export class SettingsSignalkComponent implements OnInit, OnDestroy {

@ViewChild('lineGraph', {static: true, read: ElementRef}) lineGraph: ElementRef;
@ViewChild('lineGraph', {static: true}) lineGraph: ElementRef<HTMLCanvasElement>;

connectionConfig: IConnectionConfig;

Expand All @@ -65,12 +65,12 @@ export class SettingsSignalkComponent implements OnInit, OnDestroy {
skStreamStatusSub: Subscription;


updatesSecondSub: Subscription;
signalkDeltaUpdatesStatsSubscription: Subscription;

lastSecondsUpdate: number; //number of updates from server in last second
updatesSeconds: number[] = [];

chart = null;
_chart: Chart = null;
textColor; // store the color of text for the graph...

// dynamics theme support
Expand All @@ -86,7 +86,7 @@ export class SettingsSignalkComponent implements OnInit, OnDestroy {
private deltaService: SignalKDeltaService,
public auth: AuthenticationService)
{
Chart.register(ChartStreaming);
// Chart.register(ChartStreaming);
}

ngOnInit() {
Expand Down Expand Up @@ -125,12 +125,16 @@ export class SettingsSignalkComponent implements OnInit, OnDestroy {
});

this.textColor = window.getComputedStyle(this.lineGraph.nativeElement).color;
this._chart?.destroy();
this.startChart();

//get WebSocket Stream performance update
this.updatesSecondSub = this.signalKService.getSignalkDeltaUpdateStatistics().pipe(timestamp()).subscribe((update: {value: number, timestamp: number}) => {
this.chart.data.datasets[0].data.push({x: update.timestamp, y: update.value});
this.chart?.update("quiet");
// Get WebSocket Delta update per seconds stats
this.signalkDeltaUpdatesStatsSubscription = this.signalKService.getSignalkDeltaUpdateStatistics().subscribe((update: IDeltaUpdate) => {
this._chart.data.datasets[0].data.push({x: update.timestamp, y: update.value});
if (this._chart.data.datasets[0].data.length > 60) {
this._chart.data.datasets[0].data.shift();
}
this._chart?.update("none");
});
}

Expand Down Expand Up @@ -217,7 +221,7 @@ export class SettingsSignalkComponent implements OnInit, OnDestroy {
}

private startChart() {
this.chart = new Chart(this.lineGraph.nativeElement.getContext('2d'),{
this._chart = new Chart(this.lineGraph.nativeElement.getContext('2d'),{
type: 'line',
data: {
datasets: [
Expand All @@ -234,7 +238,7 @@ export class SettingsSignalkComponent implements OnInit, OnDestroy {
parsing: false,
scales: {
x: {
type: "realtime",
type: "time",
time: {
unit: "minute",
minUnit: "second",
Expand Down Expand Up @@ -279,11 +283,11 @@ export class SettingsSignalkComponent implements OnInit, OnDestroy {
color: this.textColor,
}
},
streaming: {
duration: 60000,
delay: 1000,
frameRate: 15,
}
// streaming: {
// duration: 60000,
// delay: 1000,
// frameRate: 15,
// }
}
}
});
Expand All @@ -306,7 +310,7 @@ export class SettingsSignalkComponent implements OnInit, OnDestroy {
this.skStreamStatusSub.unsubscribe();
this.authTokenSub.unsubscribe();
this.isLoggedInSub.unsubscribe();
this.updatesSecondSub.unsubscribe();
this.chart?.destroy();
this.signalkDeltaUpdatesStatsSubscription.unsubscribe();
this._chart?.destroy();
}
}