From fe9b6e2e4294e21646e008725c02726d5308af1b Mon Sep 17 00:00:00 2001 From: mpetrov Date: Wed, 25 Sep 2024 17:22:53 +0300 Subject: [PATCH] Gateway Fixes --- ...gateway-connector-basic-config.abstract.ts | 9 +- ...ay-connector-version-processor.abstract.ts | 22 ++++- .../opc-version-processor.abstract.ts | 2 +- ...gateway-basic-configuration.component.html | 2 +- .../gateway-configuration.component.ts | 2 +- .../models/gateway-configuration.models.ts | 2 +- .../mapping-data-keys-panel.component.html | 11 ++- .../modbus-master-table.component.html | 20 ++-- .../modbus-slave-dialog.abstract.ts | 1 - .../modbus-slave-dialog.component.html | 17 ---- .../gateway/gateway-connectors.component.html | 23 ++++- .../gateway/gateway-connectors.component.ts | 93 +++++++++++++++---- .../lib/gateway/gateway-widget.models.ts | 2 +- .../gateway/utils/opc-version-mapping.util.ts | 2 +- .../assets/locale/locale.constant-en_US.json | 3 +- .../connector-default-configs/modbus.json | 7 +- 16 files changed, 152 insertions(+), 66 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract.ts index d12e647254..4c90eeb01c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/gateway-connector-basic-config.abstract.ts @@ -14,16 +14,17 @@ /// limitations under the License. /// -import { Directive, inject, Input, OnDestroy, TemplateRef } from '@angular/core'; +import { AfterViewInit, Directive, EventEmitter, inject, Input, OnDestroy, Output, TemplateRef } from '@angular/core'; import { ControlValueAccessor, FormBuilder, FormGroup, ValidationErrors, Validator } from '@angular/forms'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @Directive() export abstract class GatewayConnectorBasicConfigDirective - implements ControlValueAccessor, Validator, OnDestroy { + implements AfterViewInit, ControlValueAccessor, Validator, OnDestroy { @Input() generalTabContent: TemplateRef; + @Output() initialized = new EventEmitter(); basicFormGroup: FormGroup; @@ -45,6 +46,10 @@ export abstract class GatewayConnectorBasicConfigDirective { protected constructor(protected gatewayVersionIn: string | number, protected connector: GatewayConnector) { this.gatewayVersion = this.parseVersion(this.gatewayVersionIn); - this.configVersion = this.parseVersion(connector.configVersion); + this.configVersion = this.parseVersion(this.connector.configVersion); } getProcessedByVersion(): GatewayConnector { - if (this.isVersionUpdateNeeded()) { - return this.isVersionUpgradeNeeded() - ? this.getUpgradedVersion() - : this.getDowngradedVersion(); + if (!this.isVersionUpdateNeeded()) { + return this.connector; + } + + return this.processVersionUpdate(); + } + + private processVersionUpdate(): GatewayConnector { + if (this.isVersionUpgradeNeeded()) { + return this.getUpgradedVersion(); + } else if (this.isVersionDowngradeNeeded()) { + return this.getDowngradedVersion(); } return this.connector; @@ -48,6 +56,10 @@ export abstract class GatewayConnectorVersionProcessor { return this.gatewayVersionIn === GatewayVersion.Current && (!this.configVersion || this.configVersion < this.gatewayVersion); } + private isVersionDowngradeNeeded(): boolean { + return this.configVersion && this.connector.configVersion === GatewayVersion.Current && (this.configVersion > this.gatewayVersion); + } + private parseVersion(version: string | number): number { if (isNumber(version)) { return version as number; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts index e89c48fc28..541e26001f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/abstract/opc-version-processor.abstract.ts @@ -38,7 +38,7 @@ export class OpcVersionProcessor extends GatewayConnectorVersionProcessor; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/basic/gateway-basic-configuration.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/basic/gateway-basic-configuration.component.html index 5f33f6e00c..af8dc3119c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/basic/gateway-basic-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/basic/gateway-basic-configuration.component.html @@ -693,7 +693,7 @@ gateway.inactivity-check-period-seconds - + {{ 'gateway.inactivity-check-period-seconds-required' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/gateway-configuration.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/gateway-configuration.component.ts index c1fa370b95..670fd57bd4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/gateway-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/gateway-configuration.component.ts @@ -242,7 +242,7 @@ export class GatewayConfigurationComponent implements AfterViewInit, OnDestroy { consoleHandler: { class: 'logging.StreamHandler', formatter: 'LogFormatter', - level: 'DEBUG', + level: 0, stream: 'ext://sys.stdout' }, databaseHandler: { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/models/gateway-configuration.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/models/gateway-configuration.models.ts index 62d8dcc618..4115c6c024 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/models/gateway-configuration.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/configuration/models/gateway-configuration.models.ts @@ -128,7 +128,7 @@ interface LogFormatterConfig { interface StreamHandlerConfig { class: string; formatter: string; - level: string; + level: string | number; stream: string; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-data-keys-panel/mapping-data-keys-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-data-keys-panel/mapping-data-keys-panel.component.html index 31bed344b7..736d9c83c6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-data-keys-panel/mapping-data-keys-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/mapping-data-keys-panel/mapping-data-keys-panel.component.html @@ -26,10 +26,13 @@ -
- {{ keyControl.get('key').value }}{{ '-' }} -
-
{{ valueTitle(keyControl) }}
+ +
+ {{ keyControl.get('key').value }} +
+ {{ '-' }} +
+
{{ valueTitle(keyControl) }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-master-table/modbus-master-table.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-master-table/modbus-master-table.component.html index 8f8aeaeef7..eb3fb8e3f5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-master-table/modbus-master-table.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-master-table/modbus-master-table.component.html @@ -62,17 +62,25 @@
- + - {{ 'gateway.name' | translate }} + {{ 'gateway.info' | translate }} - {{ slave['name'] }} +
{{ slave['host'] ?? slave['port'] }}
+
+
+ + + {{ 'gateway.unit-id' | translate }} + + +
{{ slave['unitId'] }}
- {{ 'gateway.client-communication-type' | translate }} +
{{ 'gateway.client-communication-type' | translate }}
{{ ModbusProtocolLabelsMap.get(slave['type']) }} @@ -113,8 +121,8 @@
- - + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-slave-dialog/modbus-slave-dialog.abstract.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-slave-dialog/modbus-slave-dialog.abstract.ts index 6d434591d0..ff2b642621 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-slave-dialog/modbus-slave-dialog.abstract.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-slave-dialog/modbus-slave-dialog.abstract.ts @@ -113,7 +113,6 @@ export abstract class ModbusSlaveDialogAbstract extends Dialo private initializeSlaveFormGroup(): void { this.slaveConfigFormGroup = this.fb.group({ - name: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], type: [ModbusProtocolType.TCP], host: ['', [Validators.required, Validators.pattern(noLeadTrailSpacesRegex)]], port: [null, [Validators.required, Validators.min(PortLimits.MIN), Validators.max(PortLimits.MAX)]], diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-slave-dialog/modbus-slave-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-slave-dialog/modbus-slave-dialog.component.html index d869785589..bb7e90f280 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-slave-dialog/modbus-slave-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/connectors-configuration/modbus/modbus-slave-dialog/modbus-slave-dialog.component.html @@ -27,23 +27,6 @@
-
-
gateway.name
-
- - - - warning - - -
-
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html index 124b698612..cec81ab637 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html @@ -181,9 +181,14 @@ *ngIf="connectorForm.get('configVersion').value === GatewayVersion.Current else legacy" formControlName="basicConfig" [generalTabContent]="generalTabContent" + (initialized)="basicConfigInitSubject.next()" /> - + @@ -191,9 +196,14 @@ *ngIf="connectorForm.get('configVersion').value === GatewayVersion.Current else legacy" formControlName="basicConfig" [generalTabContent]="generalTabContent" + (initialized)="basicConfigInitSubject.next()" /> - + @@ -201,9 +211,14 @@ *ngIf="connectorForm.get('configVersion').value === GatewayVersion.Current else legacy" formControlName="basicConfig" [generalTabContent]="generalTabContent" + (initialized)="basicConfigInitSubject.next()" /> - + @@ -229,7 +244,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts index 2fc806a708..59911f62a9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts @@ -31,7 +31,7 @@ import { EntityId } from '@shared/models/id/entity-id'; import { AttributeService } from '@core/http/attribute.service'; import { TranslateService } from '@ngx-translate/core'; import { forkJoin, Observable, of, Subject, Subscription } from 'rxjs'; -import { AttributeScope } from '@shared/models/telemetry/telemetry.models'; +import { AttributeData, AttributeScope } from '@shared/models/telemetry/telemetry.models'; import { PageComponent } from '@shared/components/page.component'; import { PageLink } from '@shared/models/page/page-link'; import { AttributeDatasource } from '@home/models/datasource/attribute-datasource'; @@ -110,8 +110,10 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie activeConnectors: Array; mode: ConfigurationModes = this.ConnectorConfigurationModes.BASIC; initialConnector: GatewayConnector; + basicConfigInitSubject = new Subject(); private gatewayVersion: string; + private isGatewayActive: boolean; private inactiveConnectors: Array; private attributeDataSource: AttributeDatasource; private inactiveConnectorsDataSource: AttributeDatasource; @@ -124,7 +126,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie private subscriptionOptions: WidgetSubscriptionOptions = { callbacks: { onDataUpdated: () => this.ctx.ngZone.run(() => { - this.onDataUpdated(); + this.onErrorsUpdated(); }), onDataUpdateError: (_, e) => this.ctx.ngZone.run(() => { this.onDataUpdateError(e); @@ -155,8 +157,10 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie ngAfterViewInit(): void { this.dataSource.sort = this.sort; this.dataSource.sortingDataAccessor = this.getSortingDataAccessor(); + this.ctx.$scope.gatewayConnectors = this; this.loadConnectors(); + this.loadGatewayState(); this.observeModeChange(); } @@ -166,9 +170,9 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie super.ngOnDestroy(); } - saveConnector(): void { + saveConnector(isNew = true): void { const value = this.getConnectorData(); - const scope = (!this.initialConnector || this.activeConnectors.includes(this.initialConnector.name)) + const scope = (isNew || this.activeConnectors.includes(this.initialConnector.name)) ? AttributeScope.SHARED_SCOPE : AttributeScope.SERVER_SCOPE; @@ -275,7 +279,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie isConnectorSynced(attribute: GatewayAttributeData): boolean { const connectorData = attribute.value; - if (!connectorData.ts || attribute.skipSync) { + if (!connectorData.ts || attribute.skipSync || !this.isGatewayActive) { return false; } const clientIndex = this.activeData.findIndex(data => { @@ -479,7 +483,6 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie filter(Boolean), ) .subscribe(value => { - this.initialConnector = null; if (this.connectorForm.disabled) { this.connectorForm.enable(); } @@ -487,9 +490,16 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie value.configurationJson = {} as ConnectorBaseConfig; } value.basicConfig = value.configurationJson; - this.updateConnector(value); + this.initialConnector = value; + this.connectorForm.patchValue(value, {emitEvent: false}); this.generate('basicConfig.broker.clientId'); - setTimeout(() => this.saveConnector()); + if (this.connectorForm.get('type').value === value.type || !this.allowBasicConfig.has(value.type)) { + this.saveConnector(); + } else { + this.basicConfigInitSubject.pipe(take(1)).subscribe(() => { + this.saveConnector(); + }); + } }); } @@ -590,6 +600,19 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie }); } + private loadGatewayState(): void { + this.attributeService.getEntityAttributes(this.device, AttributeScope.SERVER_SCOPE) + .pipe(takeUntil(this.destroy$)) + .subscribe((attributes: AttributeData[]) => { + + const active = attributes.find(data => data.key === 'active').value; + const lastDisconnectedTime = attributes.find(data => data.key === 'lastDisconnectTime').value; + const lastConnectedTime = attributes.find(data => data.key === 'lastConnectTime').value; + + this.isGatewayActive = this.getGatewayStatus(active, lastConnectedTime, lastDisconnectedTime); + }); + } + private parseConnectors(attribute: GatewayAttributeData[]): string[] { const connectors = attribute?.[0]?.value || []; return isString(connectors) ? JSON.parse(connectors) : connectors; @@ -598,7 +621,14 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie private observeModeChange(): void { this.connectorForm.get('mode').valueChanges .pipe(takeUntil(this.destroy$)) - .subscribe(() => this.connectorForm.get('mode').markAsPristine()); + .subscribe((mode) => { + this.connectorForm.get('mode').markAsPristine(); + if (mode === ConfigurationModes.BASIC) { + this.basicConfigInitSubject.pipe(take(1)).subscribe(() => { + this.patchBasicConfigConnector({...this.initialConnector, mode: ConfigurationModes.BASIC}); + }); + } + }); } private observeAttributeChange(): void { @@ -664,10 +694,29 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie console.error(errorText); } + private onErrorsUpdated(): void { + this.cd.detectChanges(); + } + private onDataUpdated(): void { + const dataSources = this.ctx.defaultSubscription.data; + + const active = dataSources.find(data => data.dataKey.name === 'active').data[0][1]; + const lastDisconnectedTime = dataSources.find(data => data.dataKey.name === 'lastDisconnectTime').data[0][1]; + const lastConnectedTime = dataSources.find(data => data.dataKey.name === 'lastConnectTime').data[0][1]; + + this.isGatewayActive = this.getGatewayStatus(active, lastConnectedTime, lastDisconnectedTime); + this.cd.detectChanges(); } + private getGatewayStatus(active: boolean, lastConnectedTime: number, lastDisconnectedTime: number): boolean { + if (!active) { + return false; + } + return lastConnectedTime > lastDisconnectedTime; + } + private generateSubscription(): void { if (this.subscription) { this.subscription.unsubscribe(); @@ -760,13 +809,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie case ConnectorType.MQTT: case ConnectorType.OPCUA: case ConnectorType.MODBUS: - this.connectorForm.get('mode').setValue(connector.mode || ConfigurationModes.BASIC, {emitEvent: false}); - this.connectorForm.get('configVersion').setValue(connector.configVersion, {emitEvent: false}); - setTimeout(() => { - this.connectorForm.patchValue(connector, {emitEvent: false}); - this.connectorForm.markAsPristine(); - this.createBasicConfigWatcher(); - }); + this.updateBasicConfigConnector(connector); break; default: this.connectorForm.patchValue({...connector, mode: null}); @@ -775,6 +818,24 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie this.createJsonConfigWatcher(); } + private updateBasicConfigConnector(connector: GatewayConnector): void { + this.connectorForm.get('mode').setValue(connector.mode || ConfigurationModes.BASIC, {emitEvent: false}); + this.connectorForm.get('configVersion').setValue(connector.configVersion, {emitEvent: false}); + if (!connector.mode || connector.mode === ConfigurationModes.BASIC) { + this.basicConfigInitSubject.asObservable().pipe(take(1)).subscribe(() => { + this.patchBasicConfigConnector(connector); + }); + } else { + this.patchBasicConfigConnector(connector); + } + } + + private patchBasicConfigConnector(connector: GatewayConnector): void { + this.connectorForm.patchValue(connector, {emitEvent: false}); + this.connectorForm.markAsPristine(); + this.createBasicConfigWatcher(); + } + private toggleReportStrategy(type: ConnectorType): void { const reportStrategyControl = this.connectorForm.get('reportStrategy'); if (type === ConnectorType.MODBUS) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts index bf3bf01d21..c3031331b4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts @@ -680,7 +680,7 @@ export const HelpLinkByMappingTypeMap = new Map( [ [MappingType.DATA, helpBaseUrl + '/docs/iot-gateway/config/mqtt/#section-mapping'], [MappingType.OPCUA, helpBaseUrl + '/docs/iot-gateway/config/opc-ua/#section-mapping'], - [MappingType.REQUESTS, helpBaseUrl + '/docs/iot-gateway/config/mqtt/#section-mapping'] + [MappingType.REQUESTS, helpBaseUrl + '/docs/iot-gateway/config/mqtt/#requests-mapping'] ] ); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/opc-version-mapping.util.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/opc-version-mapping.util.ts index 91246b0220..9837f2f15d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/opc-version-mapping.util.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/utils/opc-version-mapping.util.ts @@ -45,7 +45,7 @@ export class OpcVersionMappingUtil { static mapServerToDowngradedVersion(config: OPCBasicConfig_v3_5_2): LegacyServerConfig { const { mapping, server } = config; - const { enableSubscriptions, ...restServer } = server; + const { enableSubscriptions, ...restServer } = server ?? {} as ServerConfig; return { ...restServer, mapping: mapping ? this.mapMappingToDowngradedVersion(mapping) : [], diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 95314ded5c..b66457cc3d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3036,6 +3036,7 @@ "grpc-max-pings-without-data-required": "Max pings without data is required", "grpc-max-pings-without-data-min": "Max pings without data can not be less then 1", "grpc-max-pings-without-data-pattern": "Max pings without data is not valid", + "info": "Info", "identity": "Identity", "inactivity-check-period-seconds": "Inactivity check period (in sec)", "inactivity-check-period-seconds-required": "Inactivity check period is required", @@ -3311,7 +3312,7 @@ "check-connectors-configuration-min": "Check connectors configuration can not be less then 1", "check-connectors-configuration-pattern": "Check connectors configuration is not valid", "add": "Add command", - "timeout": "Timeout", + "timeout": "Timeout (in sec)", "timeout-ms": "Timeout (in ms)", "timeout-required": "Timeout is required", "timeout-min": "Timeout can not be less then 1", diff --git a/ui-ngx/src/assets/metadata/connector-default-configs/modbus.json b/ui-ngx/src/assets/metadata/connector-default-configs/modbus.json index fbace65d78..019d2062f8 100644 --- a/ui-ngx/src/assets/metadata/connector-default-configs/modbus.json +++ b/ui-ngx/src/assets/metadata/connector-default-configs/modbus.json @@ -3,7 +3,6 @@ "master": { "slaves": [ { - "name": "Slave 1", "host": "127.0.0.1", "port": 5021, "type": "tcp", @@ -231,10 +230,10 @@ "attributes": [ { "address": 5, - "type": "string", - "tag": "sm", + "type": "8int", + "tag": "coil", "objectsCount": 1, - "value": "12" + "value": 0 } ], "timeseries": [],