@@ -18,7 +18,12 @@ import {
1818} from "./../asset" ;
1919import { InternalCollection , DeviceManagerConfiguration } from "../../core" ;
2020import { Metadata , lock , ask , onAsk } from "../shared" ;
21- import { AskModelDeviceGet } from "../model" ;
21+ import {
22+ AskModelAssetGet ,
23+ AskModelDeviceGet ,
24+ AssetModelContent ,
25+ DeviceModelContent ,
26+ } from "../model" ;
2227import { MeasureContent } from "../measure" ;
2328
2429import { DeviceContent } from "./types/DeviceContent" ;
@@ -417,13 +422,17 @@ export class DeviceService {
417422 deviceId : string ,
418423 assetId : string ,
419424 measureNames : ApiDeviceLinkAssetRequest [ "body" ] [ "measureNames" ] ,
420- { refresh } : { refresh ?: any } = { }
425+ {
426+ refresh,
427+ implicitMeasuresLinking,
428+ } : { refresh ?: any ; implicitMeasuresLinking ?: boolean } = { }
421429 ) : Promise < {
422430 asset : KDocument < AssetContent > ;
423431 device : KDocument < DeviceContent > ;
424432 } > {
425433 return lock ( `device:linkAsset:${ deviceId } ` , async ( ) => {
426434 const device = await this . get ( this . config . adminIndex , deviceId ) ;
435+ const engine = await this . getEngine ( engineId ) ;
427436
428437 this . checkAttachedToEngine ( device ) ;
429438
@@ -445,7 +454,26 @@ export class DeviceService {
445454 assetId
446455 ) ;
447456
448- this . checkAssetMeasureNamesAvailability ( asset , measureNames ) ;
457+ const [ assetModel , deviceModel ] = await Promise . all ( [
458+ ask < AskModelAssetGet > ( "ask:device-manager:model:asset:get" , {
459+ engineGroup : engine . group ,
460+ model : asset . _source . model ,
461+ } ) ,
462+ ask < AskModelDeviceGet > ( "ask:device-manager:model:device:get" , {
463+ model : device . _source . model ,
464+ } ) ,
465+ ] ) ;
466+
467+ this . checkAlreadyProvidedMeasures ( asset , measureNames ) ;
468+
469+ if ( implicitMeasuresLinking ) {
470+ this . generateMissingAssetMeasureNames (
471+ asset ,
472+ assetModel ,
473+ deviceModel ,
474+ measureNames
475+ ) ;
476+ }
449477
450478 device . _source . assetId = assetId ;
451479 asset . _source . linkedDevices . push ( {
@@ -514,22 +542,68 @@ export class DeviceService {
514542 * Checks if the asset does not already have a linked device using one of the
515543 * requested measure names.
516544 */
517- private checkAssetMeasureNamesAvailability (
545+ private checkAlreadyProvidedMeasures (
518546 asset : KDocument < AssetContent > ,
519- measureNames : ApiDeviceLinkAssetRequest [ "body" ] [ "measureNames" ]
547+ requestedMeasureNames : ApiDeviceLinkAssetRequest [ "body" ] [ "measureNames" ]
520548 ) {
521- const requestedMeasuresNames = measureNames . map ( ( m ) => m . asset ) ;
549+ const measureAlreadyProvided = ( assetMeasureName : string ) : boolean => {
550+ return asset . _source . linkedDevices . some ( ( link ) =>
551+ link . measureNames . some ( ( names ) => names . asset === assetMeasureName )
552+ ) ;
553+ } ;
522554
523- for ( const link of asset . _source . linkedDevices ) {
524- const existingMeasureNames = link . measureNames . map ( ( m ) => m . asset ) ;
555+ for ( const name of requestedMeasureNames ) {
556+ if ( measureAlreadyProvided ( name . asset ) ) {
557+ throw new BadRequestError (
558+ `Measure name "${ name . asset } " is already used by another device on this asset.`
559+ ) ;
560+ }
561+ }
562+ }
525563
526- for ( const requestedMeasuresName of requestedMeasuresNames ) {
527- if ( existingMeasureNames . includes ( requestedMeasuresName ) ) {
528- throw new BadRequestError (
529- `Measure name "${ requestedMeasuresName } " is already used by another device on this asset.`
530- ) ;
531- }
564+ /**
565+ * Goes through the device available measures and add them into the link if:
566+ * - they are not already provided by another device
567+ * - they are not already present in the link request
568+ * - they are declared in the asset model
569+ */
570+ private generateMissingAssetMeasureNames (
571+ asset : KDocument < AssetContent > ,
572+ assetModel : AssetModelContent ,
573+ deviceModel : DeviceModelContent ,
574+ requestedMeasureNames : ApiDeviceLinkAssetRequest [ "body" ] [ "measureNames" ]
575+ ) {
576+ const measureAlreadyProvided = ( deviceMeasureName : string ) : boolean => {
577+ return asset . _source . linkedDevices . some ( ( link ) =>
578+ link . measureNames . some ( ( names ) => names . device === deviceMeasureName )
579+ ) ;
580+ } ;
581+
582+ const measureAlreadyRequested = ( deviceMeasureName : string ) : boolean => {
583+ return requestedMeasureNames . some (
584+ ( names ) => names . device === deviceMeasureName
585+ ) ;
586+ } ;
587+
588+ const measureUndeclared = ( deviceMeasureName : string ) : boolean => {
589+ return ! assetModel . asset . measures . some (
590+ ( measure ) => measure . name === deviceMeasureName
591+ ) ;
592+ } ;
593+
594+ for ( const deviceMeasure of deviceModel . device . measures ) {
595+ if (
596+ measureAlreadyRequested ( deviceMeasure . name ) ||
597+ measureAlreadyProvided ( deviceMeasure . name ) ||
598+ measureUndeclared ( deviceMeasure . name )
599+ ) {
600+ continue ;
532601 }
602+
603+ requestedMeasureNames . push ( {
604+ asset : deviceMeasure . name ,
605+ device : deviceMeasure . name ,
606+ } ) ;
533607 }
534608 }
535609
@@ -703,4 +777,14 @@ export class DeviceService {
703777 ) ;
704778 }
705779 }
780+
781+ private async getEngine ( engineId : string ) : Promise < JSONObject > {
782+ const engine = await this . sdk . document . get (
783+ this . config . adminIndex ,
784+ InternalCollection . CONFIG ,
785+ `engine-device-manager--${ engineId } `
786+ ) ;
787+
788+ return engine . _source . engine ;
789+ }
706790}
0 commit comments