diff --git a/ui/src/app/edge/history/history.component.ts b/ui/src/app/edge/history/history.component.ts index 217511811b2..5a3cbc24158 100644 --- a/ui/src/app/edge/history/history.component.ts +++ b/ui/src/app/edge/history/history.component.ts @@ -16,7 +16,6 @@ export class HistoryComponent implements OnInit { // is a Timedata service available, i.e. can historic data be queried. public isTimedataAvailable: boolean = true; - protected errorResponse: JsonrpcResponseError | null = null; // sets the height for a chart. This is recalculated on every window resize. diff --git a/ui/src/app/edge/history/historydataservice.ts b/ui/src/app/edge/history/historydataservice.ts index 6b1fddd3052..fc42fd2a7a7 100644 --- a/ui/src/app/edge/history/historydataservice.ts +++ b/ui/src/app/edge/history/historydataservice.ts @@ -46,4 +46,8 @@ export class HistoryDataService extends DataService { }, 100); } } + + public override unsubscribeFromChannels(channels: ChannelAddress[]) { + return; + } } \ No newline at end of file diff --git a/ui/src/app/edge/live/livedataservice.ts b/ui/src/app/edge/live/livedataservice.ts index df2b7d79ffe..24ab07ffa03 100644 --- a/ui/src/app/edge/live/livedataservice.ts +++ b/ui/src/app/edge/live/livedataservice.ts @@ -1,15 +1,15 @@ -import { Inject, Injectable, OnDestroy } from "@angular/core"; +import { Directive, Inject, OnDestroy } from "@angular/core"; import { takeUntil } from "rxjs/operators"; import { v4 as uuidv4 } from 'uuid'; import { DataService } from "../../shared/genericComponents/shared/dataservice"; -import { SubscribeEdgesRequest } from "../../shared/jsonrpc/request/subscribeEdgesRequest"; import { ChannelAddress, Edge, Service, Websocket } from "../../shared/shared"; -@Injectable() +@Directive() export class LiveDataService extends DataService implements OnDestroy { private subscribeId: string | null = null; + private subscribedChannelAddresses: ChannelAddress[] = []; constructor( @Inject(Websocket) protected websocket: Websocket, @@ -19,6 +19,11 @@ export class LiveDataService extends DataService implements OnDestroy { } public getValues(channelAddresses: ChannelAddress[], edge: Edge, componentId: string) { + + for (let channelAddress of channelAddresses) { + this.subscribedChannelAddresses.push(channelAddress); + } + this.subscribeId = uuidv4(); this.edge = edge; if (channelAddresses.length != 0) { @@ -38,8 +43,12 @@ export class LiveDataService extends DataService implements OnDestroy { } ngOnDestroy() { - this.websocket.sendRequest(new SubscribeEdgesRequest({ edges: [] })); + this.edge.unsubscribeFromChannels(this.websocket, this.subscribedChannelAddresses); this.stopOnDestroy.next(); this.stopOnDestroy.complete(); } + + public unsubscribeFromChannels(channels: ChannelAddress[]) { + this.edge.unsubscribeFromChannels(this.websocket, channels); + } } diff --git a/ui/src/app/shared/edge/edge.ts b/ui/src/app/shared/edge/edge.ts index 808ed9f396f..417f99f7e64 100644 --- a/ui/src/app/shared/edge/edge.ts +++ b/ui/src/app/shared/edge/edge.ts @@ -1,5 +1,6 @@ import { compareVersions } from 'compare-versions'; import { BehaviorSubject, Subject } from 'rxjs'; + import { JsonrpcRequest, JsonrpcResponseSuccess } from '../jsonrpc/base'; import { CurrentDataNotification } from '../jsonrpc/notification/currentDataNotification'; import { EdgeConfigNotification } from '../jsonrpc/notification/edgeConfigNotification'; @@ -12,6 +13,7 @@ import { SubscribeChannelsRequest } from '../jsonrpc/request/subscribeChannelsRe import { SubscribeSystemLogRequest } from '../jsonrpc/request/subscribeSystemLogRequest'; import { UpdateComponentConfigRequest } from '../jsonrpc/request/updateComponentConfigRequest'; import { GetEdgeConfigResponse } from '../jsonrpc/response/getEdgeConfigResponse'; +import { ArrayUtils } from '../service/arrayutils'; import { Websocket } from '../service/websocket'; import { ChannelAddress } from '../type/channeladdress'; import { Role } from '../type/role'; @@ -120,12 +122,38 @@ export class Edge { * * @param websocket the Websocket * @param id the unique ID for this subscription + * @deprecated Use `unsubscribeFromChannels` instead. + * + * @todo should be removed */ public unsubscribeChannels(websocket: Websocket, id: string): void { delete this.subscribedChannels[id]; this.sendSubscribeChannels(websocket); } + /** + * Unsubscribes from passed channels + * + * @param websocket the Websocket + * @param channels the channels + * + * @todo should be renamed to `unsubscribeChannels` after unsubscribeChannels is removed + */ + public unsubscribeFromChannels(websocket: Websocket, channels: ChannelAddress[]) { + this.subscribedChannels = Object.entries(this.subscribedChannels).reduce((arr, [id, subscribedChannels]) => { + + if (ArrayUtils.equalsCheck(channels.map(channel => channel.toString()), subscribedChannels.map(channel => channel.toString()))) { + return arr; + } + + arr[id] = subscribedChannels; + + return arr; + }, {}); + + this.sendSubscribeChannels(websocket); + } + /** * Subscribe to System-Log * diff --git a/ui/src/app/shared/genericComponents/flat/abstract-flat-widget-line.ts b/ui/src/app/shared/genericComponents/flat/abstract-flat-widget-line.ts index ce91ee531c1..4dc2c3284a1 100644 --- a/ui/src/app/shared/genericComponents/flat/abstract-flat-widget-line.ts +++ b/ui/src/app/shared/genericComponents/flat/abstract-flat-widget-line.ts @@ -27,9 +27,12 @@ export abstract class AbstractFlatWidgetLine implements OnChanges, OnDestroy { /** Channel defines the channel, you need for this line */ @Input() set channelAddress(channelAddress: string) { + this._channelAddress = ChannelAddress.fromString(channelAddress); this.subscribe(ChannelAddress.fromString(channelAddress)); } + private _channelAddress: ChannelAddress | null = null; + /** * displayValue is the displayed @Input value in html */ @@ -71,8 +74,8 @@ export abstract class AbstractFlatWidgetLine implements OnChanges, OnDestroy { public ngOnDestroy() { // Unsubscribe from OpenEMS - if (this.edge != null) { - this.edge.unsubscribeChannels(this.websocket, this.selector); + if (this.edge != null && this._channelAddress) { + this.edge.unsubscribeFromChannels(this.websocket, [this._channelAddress]); } // Unsubscribe from CurrentData subject diff --git a/ui/src/app/shared/genericComponents/flat/abstract-flat-widget.ts b/ui/src/app/shared/genericComponents/flat/abstract-flat-widget.ts index 42d8a424190..395616680d6 100644 --- a/ui/src/app/shared/genericComponents/flat/abstract-flat-widget.ts +++ b/ui/src/app/shared/genericComponents/flat/abstract-flat-widget.ts @@ -55,7 +55,6 @@ export abstract class AbstractFlatWidget implements OnInit, OnDestroy { for (let channelId of channelIds) { channelAddresses.add(new ChannelAddress(this.componentId, channelId)); } - this.dataService.getValues(Array.from(channelAddresses), this.edge, this.componentId); this.dataService.currentValue.pipe(takeUntil(this.stopOnDestroy)).subscribe(value => { this.onCurrentData(value); @@ -65,8 +64,7 @@ export abstract class AbstractFlatWidget implements OnInit, OnDestroy { }; public ngOnDestroy() { - // Unsubscribe from OpenEMS - this.edge.unsubscribeChannels(this.websocket, this.selector); + this.dataService.unsubscribeFromChannels(this.getChannelAddresses()); // Unsubscribe from CurrentData subject this.stopOnDestroy.next(); @@ -78,8 +76,7 @@ export abstract class AbstractFlatWidget implements OnInit, OnDestroy { * * @param currentData new data for the subscribed Channel-Addresses */ - protected onCurrentData(currentData: CurrentData) { - } + protected onCurrentData(currentData: CurrentData) { } /** * Gets the ChannelAddresses that should be subscribed. diff --git a/ui/src/app/shared/genericComponents/shared/dataservice.ts b/ui/src/app/shared/genericComponents/shared/dataservice.ts index 238257dda8e..d3fd99a0998 100644 --- a/ui/src/app/shared/genericComponents/shared/dataservice.ts +++ b/ui/src/app/shared/genericComponents/shared/dataservice.ts @@ -19,5 +19,12 @@ export abstract class DataService { * @param edge the edge * @param componentId the componentId */ - public abstract getValues(channelAddress: ChannelAddress[], edge: Edge, componentId?: string) + public abstract getValues(channelAddress: ChannelAddress[], edge: Edge, componentId?: string); + + /** + * Unsubscribes from passed channels + * + * @param channels the channels + */ + public abstract unsubscribeFromChannels(channels: ChannelAddress[]); } \ No newline at end of file diff --git a/ui/src/app/shared/header/header.component.html b/ui/src/app/shared/header/header.component.html index 27b6f123930..875067f79e3 100644 --- a/ui/src/app/shared/header/header.component.html +++ b/ui/src/app/shared/header/header.component.html @@ -1,7 +1,7 @@ - + diff --git a/ui/src/app/shared/header/header.component.ts b/ui/src/app/shared/header/header.component.ts index b6768034857..db158750e07 100644 --- a/ui/src/app/shared/header/header.component.ts +++ b/ui/src/app/shared/header/header.component.ts @@ -150,11 +150,11 @@ export class HeaderComponent implements OnInit, OnDestroy, AfterViewChecked { public segmentChanged(event) { if (event.detail.value == "IndexLive") { - this.router.navigateByUrl("/device/" + this.service.currentEdge.value.id + "/live", { replaceUrl: true }); + this.router.navigate(["/device/" + this.service.currentEdge.value.id + "/live"], { replaceUrl: true }); this.cdRef.detectChanges(); } if (event.detail.value == "IndexHistory") { - this.router.navigate(['../history'], { relativeTo: this.route }); + this.router.navigate(["/device/" + this.service.currentEdge.value.id + "/history"], { replaceUrl: true }); this.cdRef.detectChanges(); } } diff --git a/ui/src/app/shared/jsonrpc/jsonrpcutils.ts b/ui/src/app/shared/jsonrpc/jsonrpcutils.ts index ec7788c1620..46d0c343f27 100644 --- a/ui/src/app/shared/jsonrpc/jsonrpcutils.ts +++ b/ui/src/app/shared/jsonrpc/jsonrpcutils.ts @@ -3,14 +3,14 @@ import { ChannelAddress } from "../type/channeladdress"; export class JsonRpcUtils { /** - * Converts an array of ChannelAddresses to a string array. + * Converts an array of ChannelAddresses to a string array with unique values. */ public static channelsToStringArray(channels: ChannelAddress[]): string[] { let result = []; for (let channel of channels) { result.push(channel.toString()); } - return result; + return Array.from(new Set(result)); } } \ No newline at end of file diff --git a/ui/src/app/shared/service/arrayutils.ts b/ui/src/app/shared/service/arrayutils.ts new file mode 100644 index 00000000000..da62578fbf9 --- /dev/null +++ b/ui/src/app/shared/service/arrayutils.ts @@ -0,0 +1,6 @@ +export namespace ArrayUtils { + export function equalsCheck(a: any[], b: any[]) { + return a.length === b.length && + a.every((v, i) => v === b[i]); + } +} \ No newline at end of file